packages feed

hevm 0.56.0 → 0.57.0

raw patch · 25 files changed

+1909/−1718 lines, 25 filesdep +monad-loopsdep ~directorydep ~filepathPVP ok

version bump matches the API change (PVP)

Dependencies added: monad-loops

Dependency ranges changed: directory, filepath

API changes (from Hackage documentation)

- EVM: runAll :: Maybe Int -> Int -> RunAll s -> EVM 'Symbolic s ()
- EVM: runBoth :: Maybe Int -> Int -> RunBoth s -> EVM 'Symbolic s ()
- EVM.Expr: numBranches :: Expr 'End -> Int
- EVM.Fetch: [mockBlock] :: RpcInfo -> Maybe (Map W256 Block)
- EVM.Fetch: [mockContract] :: RpcInfo -> Maybe (Map Addr RPCContract)
- EVM.Fetch: [mockSlot] :: RpcInfo -> Maybe (Map (Addr, W256) W256)
- EVM.Fetch: data RpcInfo
- EVM.Fetch: instance Data.Aeson.Types.FromJSON.FromJSON EVM.Fetch.MockData
- EVM.Fetch: instance Data.Aeson.Types.ToJSON.ToJSON EVM.Fetch.MockData
- EVM.Fetch: instance GHC.Base.Monoid EVM.Fetch.MockData
- EVM.Fetch: instance GHC.Base.Monoid EVM.Fetch.RpcInfo
- EVM.Fetch: instance GHC.Base.Semigroup EVM.Fetch.MockData
- EVM.Fetch: instance GHC.Base.Semigroup EVM.Fetch.RpcInfo
- EVM.Fetch: mkRpcInfo :: Maybe (BlockNumber, Text) -> MockData -> RpcInfo
- EVM.Fetch: readMockData :: FilePath -> IO (Either String MockData)
- EVM.Stepper: [ForkMany] :: forall s. RunAll s -> Action 'Symbolic s ()
- EVM.SymExec: checkAssertWithSession :: App m => SolverGroup -> Maybe Session -> [Word256] -> ByteString -> Maybe Sig -> [String] -> VeriOpts -> m (Expr 'End, [VerifyResult])
- EVM.SymExec: flattenExpr :: Expr 'End -> [Expr 'End]
- EVM.SymExec: rpcVeriOpts :: (BlockNumber, Text) -> VeriOpts
- EVM.SymExec: verifyContractWithSession :: App m => SolverGroup -> Maybe Session -> ByteString -> Maybe Sig -> [String] -> VeriOpts -> Maybe (Precondition RealWorld) -> Maybe (Postcondition RealWorld) -> m (Expr 'End, [VerifyResult])
- EVM.SymExec: verifyInputs :: App m => SolverGroup -> VeriOpts -> Fetcher 'Symbolic m RealWorld -> VM 'Symbolic RealWorld -> Maybe (Postcondition RealWorld) -> m (Expr 'End, [(SMTResult, Expr 'End)], [(PartialExec, Expr 'End)])
- EVM.SymExec: verifyResults :: VM 'Symbolic RealWorld -> Expr 'End -> [(SMTResult, Expr 'End)] -> (Expr 'End, [VerifyResult])
- EVM.Types: [ITE] :: Expr 'EWord -> Expr 'End -> Expr 'End -> Expr 'End
- EVM.Types: [RunAll] :: forall s. RunAll s -> Effect 'Symbolic s
- EVM.Types: [RunBoth] :: forall s. RunBoth s -> Effect 'Symbolic s
- EVM.Types: data RunAll s
- EVM.Types: data RunBoth s
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Map.Internal.Map EVM.Types.Addr Data.Text.Internal.Text, b GHC.Types.~ Data.Map.Internal.Map EVM.Types.Addr Data.Text.Internal.Text) => Optics.Label.LabelOptic "labels" k (EVM.Types.VM t s) (EVM.Types.VM t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Map.Internal.Map EVM.Types.CodeLocation (GHC.Types.Int, [EVM.Types.Expr 'EVM.Types.EWord]), b GHC.Types.~ Data.Map.Internal.Map EVM.Types.CodeLocation (GHC.Types.Int, [EVM.Types.Expr 'EVM.Types.EWord])) => Optics.Label.LabelOptic "iterations" k (EVM.Types.VM t s) (EVM.Types.VM t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Map.Internal.Map GHC.Base.String GHC.Base.String, b GHC.Types.~ Data.Map.Internal.Map GHC.Base.String GHC.Base.String) => Optics.Label.LabelOptic "osEnv" k (EVM.Types.VM t s) (EVM.Types.VM t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Sequence.Internal.Seq EVM.Types.ForkState, b GHC.Types.~ Data.Sequence.Internal.Seq EVM.Types.ForkState) => Optics.Label.LabelOptic "forks" k (EVM.Types.VM t s) (EVM.Types.VM t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Set.Internal.Set (Data.ByteString.Internal.Type.ByteString, EVM.Types.W256), b GHC.Types.~ Data.Set.Internal.Set (Data.ByteString.Internal.Type.ByteString, EVM.Types.W256)) => Optics.Label.LabelOptic "keccakPreImgs" k (EVM.Types.VM t s) (EVM.Types.VM t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Tree.Zipper.TreePos Data.Tree.Zipper.Empty EVM.Types.Trace, b GHC.Types.~ Data.Tree.Zipper.TreePos Data.Tree.Zipper.Empty EVM.Types.Trace) => Optics.Label.LabelOptic "traces" k (EVM.Types.VM t s) (EVM.Types.VM t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Block, b GHC.Types.~ EVM.Types.Block) => Optics.Label.LabelOptic "block" k (EVM.Types.VM t s) (EVM.Types.VM t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.ContractCode, b GHC.Types.~ EVM.Types.ContractCode) => Optics.Label.LabelOptic "code" k (EVM.Types.FrameState t s) (EVM.Types.FrameState t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Env, b GHC.Types.~ EVM.Types.Env) => Optics.Label.LabelOptic "env" k (EVM.Types.VM t s) (EVM.Types.VM t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Expr 'EVM.Types.Buf, b GHC.Types.~ EVM.Types.Expr 'EVM.Types.Buf) => Optics.Label.LabelOptic "calldata" k (EVM.Types.FrameState t s) (EVM.Types.FrameState t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Expr 'EVM.Types.Buf, b GHC.Types.~ EVM.Types.Expr 'EVM.Types.Buf) => Optics.Label.LabelOptic "returndata" k (EVM.Types.FrameState t s) (EVM.Types.FrameState t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Expr 'EVM.Types.EAddr, b GHC.Types.~ EVM.Types.Expr 'EVM.Types.EAddr) => Optics.Label.LabelOptic "caller" k (EVM.Types.FrameState t s) (EVM.Types.FrameState t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Expr 'EVM.Types.EAddr, b GHC.Types.~ EVM.Types.Expr 'EVM.Types.EAddr) => Optics.Label.LabelOptic "codeContract" k (EVM.Types.FrameState t s) (EVM.Types.FrameState t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Expr 'EVM.Types.EAddr, b GHC.Types.~ EVM.Types.Expr 'EVM.Types.EAddr) => Optics.Label.LabelOptic "contract" k (EVM.Types.FrameState t s) (EVM.Types.FrameState t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Expr 'EVM.Types.EWord, b GHC.Types.~ EVM.Types.Expr 'EVM.Types.EWord) => Optics.Label.LabelOptic "callvalue" k (EVM.Types.FrameState t s) (EVM.Types.FrameState t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.FrameContext, b GHC.Types.~ EVM.Types.FrameContext) => Optics.Label.LabelOptic "context" k (EVM.Types.Frame t s) (EVM.Types.Frame t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.FrameState t s, b GHC.Types.~ EVM.Types.FrameState t s) => Optics.Label.LabelOptic "state" k (EVM.Types.VM t s) (EVM.Types.VM t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.FrameState t1 s1, b GHC.Types.~ EVM.Types.FrameState t2 s2) => Optics.Label.LabelOptic "state" k (EVM.Types.Frame t1 s1) (EVM.Types.Frame t2 s2) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Gas t, b GHC.Types.~ EVM.Types.Gas t) => Optics.Label.LabelOptic "burned" k (EVM.Types.VM t s) (EVM.Types.VM t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Gas t1, b GHC.Types.~ EVM.Types.Gas t2) => Optics.Label.LabelOptic "gas" k (EVM.Types.FrameState t1 s) (EVM.Types.FrameState t2 s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Memory s1, b GHC.Types.~ EVM.Types.Memory s2) => Optics.Label.LabelOptic "memory" k (EVM.Types.FrameState t s1) (EVM.Types.FrameState t s2) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.PathsVisited, b GHC.Types.~ EVM.Types.PathsVisited) => Optics.Label.LabelOptic "pathsVisited" k (EVM.Types.VM t s) (EVM.Types.VM t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.RuntimeConfig, b GHC.Types.~ EVM.Types.RuntimeConfig) => Optics.Label.LabelOptic "config" k (EVM.Types.VM t s) (EVM.Types.VM t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.TxState, b GHC.Types.~ EVM.Types.TxState) => Optics.Label.LabelOptic "tx" k (EVM.Types.VM t s) (EVM.Types.VM t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ GHC.Maybe.Maybe (EVM.Types.Expr 'EVM.Types.EAddr), b GHC.Types.~ GHC.Maybe.Maybe (EVM.Types.Expr 'EVM.Types.EAddr)) => Optics.Label.LabelOptic "overrideCaller" k (EVM.Types.FrameState t s) (EVM.Types.FrameState t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ GHC.Maybe.Maybe (EVM.Types.VMResult t s), b GHC.Types.~ GHC.Maybe.Maybe (EVM.Types.VMResult t s)) => Optics.Label.LabelOptic "result" k (EVM.Types.VM t s) (EVM.Types.VM t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ GHC.Types.Bool, b GHC.Types.~ GHC.Types.Bool) => Optics.Label.LabelOptic "resetCaller" k (EVM.Types.FrameState t s) (EVM.Types.FrameState t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ GHC.Types.Bool, b GHC.Types.~ GHC.Types.Bool) => Optics.Label.LabelOptic "static" k (EVM.Types.FrameState t s) (EVM.Types.FrameState t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ GHC.Types.Int, b GHC.Types.~ GHC.Types.Int) => Optics.Label.LabelOptic "currentFork" k (EVM.Types.VM t s) (EVM.Types.VM t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ GHC.Types.Int, b GHC.Types.~ GHC.Types.Int) => Optics.Label.LabelOptic "exploreDepth" k (EVM.Types.VM t s) (EVM.Types.VM t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ GHC.Types.Int, b GHC.Types.~ GHC.Types.Int) => Optics.Label.LabelOptic "freshVar" k (EVM.Types.VM t s) (EVM.Types.VM t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ GHC.Types.Int, b GHC.Types.~ GHC.Types.Int) => Optics.Label.LabelOptic "pc" k (EVM.Types.FrameState t s) (EVM.Types.FrameState t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ GHC.Word.Word64, b GHC.Types.~ GHC.Word.Word64) => Optics.Label.LabelOptic "memorySize" k (EVM.Types.FrameState t s) (EVM.Types.FrameState t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ [EVM.Types.Expr 'EVM.Types.EWord], b GHC.Types.~ [EVM.Types.Expr 'EVM.Types.EWord]) => Optics.Label.LabelOptic "stack" k (EVM.Types.FrameState t s) (EVM.Types.FrameState t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ [EVM.Types.Expr 'EVM.Types.Log], b GHC.Types.~ [EVM.Types.Expr 'EVM.Types.Log]) => Optics.Label.LabelOptic "logs" k (EVM.Types.VM t s) (EVM.Types.VM t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ [EVM.Types.Frame t s], b GHC.Types.~ [EVM.Types.Frame t s]) => Optics.Label.LabelOptic "frames" k (EVM.Types.VM t s) (EVM.Types.VM t s) a b
- EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ [EVM.Types.Prop], b GHC.Types.~ [EVM.Types.Prop]) => Optics.Label.LabelOptic "constraints" k (EVM.Types.VM t s) (EVM.Types.VM t s) a b
- EVM.Types: instance GHC.Generics.Generic (EVM.Types.FrameState t s)
- EVM.Types: instance GHC.Generics.Generic (EVM.Types.VM t s)
- EVM.Types: instance GHC.Show.Show (EVM.Types.Effect t s)
- EVM.Types: instance GHC.Show.Show (EVM.Types.Frame 'EVM.Types.Concrete s)
- EVM.Types: instance GHC.Show.Show (EVM.Types.Frame 'EVM.Types.Symbolic s)
- EVM.Types: instance GHC.Show.Show (EVM.Types.FrameState 'EVM.Types.Concrete s)
- EVM.Types: instance GHC.Show.Show (EVM.Types.FrameState 'EVM.Types.Symbolic s)
- EVM.Types: instance GHC.Show.Show (EVM.Types.Memory s)
- EVM.Types: instance GHC.Show.Show (EVM.Types.Query t s)
- EVM.Types: instance GHC.Show.Show (EVM.Types.RunAll s)
- EVM.Types: instance GHC.Show.Show (EVM.Types.RunBoth s)
- EVM.Types: instance GHC.Show.Show (EVM.Types.VM 'EVM.Types.Concrete s)
- EVM.Types: instance GHC.Show.Show (EVM.Types.VM 'EVM.Types.Symbolic s)
- EVM.Types: instance GHC.Show.Show (EVM.Types.VMResult t s)
- EVM.UnitTest: getReproFailures :: App m => Sig -> Expr 'Buf -> [SMTCex] -> m [Err ReproducibleCex]
+ EVM: accessConcreteStorage :: Expr 'Storage -> W256 -> W256
+ EVM: fork :: Maybe Int -> Int -> BranchContext -> EVM 'Symbolic ()
+ EVM.Expr: [lowerBounds] :: ConstState -> Map (Expr 'EWord) W256
+ EVM.Expr: [upperBounds] :: ConstState -> Map (Expr 'EWord) W256
+ EVM.Fetch: Cached :: FetchStatus
+ EVM.Fetch: FetchError :: Text -> FetchResult a
+ EVM.Fetch: FetchFailure :: FetchStatus -> FetchResult a
+ EVM.Fetch: FetchSuccess :: a -> FetchStatus -> FetchResult a
+ EVM.Fetch: Fresh :: FetchStatus
+ EVM.Fetch: RPCContract :: ByteStringS -> W64 -> W256 -> RPCContract
+ EVM.Fetch: [balance] :: RPCContract -> W256
+ EVM.Fetch: [cacheDir] :: Session -> Maybe FilePath
+ EVM.Fetch: [code] :: RPCContract -> ByteStringS
+ EVM.Fetch: [failedContracts] :: Session -> MVar (Set Addr)
+ EVM.Fetch: [failedSlots] :: Session -> MVar (Set (Addr, W256))
+ EVM.Fetch: [nonce] :: RPCContract -> W64
+ EVM.Fetch: data FetchResult a
+ EVM.Fetch: data FetchStatus
+ EVM.Fetch: data RPCContract
+ EVM.Fetch: fetchSlotWithCache :: Config -> Session -> BlockNumber -> Text -> Addr -> W256 -> IO (FetchResult W256)
+ EVM.Fetch: getCacheState :: Session -> IO (Map Addr (Maybe Contract), Map Addr (Map W256 (Maybe W256)))
+ EVM.Fetch: instance Data.Aeson.Types.FromJSON.FromJSON EVM.Fetch.FetchCache
+ EVM.Fetch: instance Data.Aeson.Types.ToJSON.ToJSON EVM.Fetch.FetchCache
+ EVM.Fetch: instance GHC.Classes.Eq EVM.Fetch.FetchStatus
+ EVM.Fetch: instance GHC.Classes.Eq a => GHC.Classes.Eq (EVM.Fetch.FetchResult a)
+ EVM.Fetch: instance GHC.Generics.Generic EVM.Fetch.FetchCache
+ EVM.Fetch: instance GHC.Generics.Generic EVM.Fetch.RPCContract
+ EVM.Fetch: instance GHC.Show.Show EVM.Fetch.FetchStatus
+ EVM.Fetch: instance GHC.Show.Show EVM.Fetch.Signedness
+ EVM.Fetch: instance GHC.Show.Show a => GHC.Show.Show (EVM.Fetch.FetchResult a)
+ EVM.Fetch: makeContractFromRPC :: RPCContract -> Contract
+ EVM.Fetch: mkSessionWithoutCache :: App m => m Session
+ EVM.Fetch: newtype RpcInfo
+ EVM.Fetch: noRpc :: RpcInfo
+ EVM.Fetch: noRpcFetcher :: forall (t :: VMType) m. App m => SolverGroup -> Fetcher t m
+ EVM.Fetch: saveCache :: FilePath -> W256 -> FetchCache -> IO ()
+ EVM.Format: prettyvmresults :: [Expr 'End] -> String
+ EVM.SymExec: InterpTask :: Fetcher 'Symbolic m -> IterConfig -> VM 'Symbolic -> Chan (InterpTask m a) -> TVar Natural -> Stepper 'Symbolic (Expr 'End) -> (Expr 'End -> m a) -> InterpTask (m :: Type -> Type) a
+ EVM.SymExec: Process :: Expr 'End -> (Expr 'End -> m a) -> Process (m :: k -> Type) (a :: k)
+ EVM.SymExec: [fetcher] :: InterpTask (m :: Type -> Type) a -> Fetcher 'Symbolic m
+ EVM.SymExec: [handler] :: Process (m :: k -> Type) (a :: k) -> Expr 'End -> m a
+ EVM.SymExec: [numTasks] :: InterpTask (m :: Type -> Type) a -> TVar Natural
+ EVM.SymExec: [result] :: Process (m :: k -> Type) (a :: k) -> Expr 'End
+ EVM.SymExec: [stepper] :: InterpTask (m :: Type -> Type) a -> Stepper 'Symbolic (Expr 'End)
+ EVM.SymExec: [taskQ] :: InterpTask (m :: Type -> Type) a -> Chan (InterpTask m a)
+ EVM.SymExec: [vm] :: InterpTask (m :: Type -> Type) a -> VM 'Symbolic
+ EVM.SymExec: data InterpTask (m :: Type -> Type) a
+ EVM.SymExec: data Process (m :: k -> Type) (a :: k)
+ EVM.SymExec: executeVM :: App m => Fetcher 'Symbolic m -> IterConfig -> VM 'Symbolic -> (Expr 'End -> m a) -> m [a]
+ EVM.SymExec: exploreContract :: App m => SolverGroup -> ByteString -> Maybe Sig -> [String] -> VeriOpts -> Maybe Precondition -> m [Expr 'End]
+ EVM.SymExec: getOneExpr :: App m => InterpTask m a -> Chan () -> Chan (Process m a) -> TVar Natural -> TVar Natural -> m ()
+ EVM.SymExec: interpretInternal :: App m => InterpTask m a -> m (Expr 'End)
+ EVM.SymExec: verifyInputsWithHandler :: App m => SolverGroup -> VeriOpts -> Fetcher 'Symbolic m -> VM 'Symbolic -> Postcondition -> Maybe (VM 'Symbolic -> SMTResult -> Expr 'End -> m ()) -> m ([(SMTResult, Expr 'End)], [(PartialExec, Expr 'End)])
+ EVM.SymExec: verifyResult :: VM 'Symbolic -> (SMTResult, Expr 'End) -> (Expr 'End, VerifyResult)
+ EVM.Types: [Branch] :: BranchContext -> Effect 'Symbolic
+ EVM.Types: data BranchContext
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Map.Internal.Map EVM.Types.Addr Data.Text.Internal.Text, b GHC.Types.~ Data.Map.Internal.Map EVM.Types.Addr Data.Text.Internal.Text) => Optics.Label.LabelOptic "labels" k (EVM.Types.VM t) (EVM.Types.VM t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Map.Internal.Map EVM.Types.CodeLocation (GHC.Types.Int, [EVM.Types.Expr 'EVM.Types.EWord]), b GHC.Types.~ Data.Map.Internal.Map EVM.Types.CodeLocation (GHC.Types.Int, [EVM.Types.Expr 'EVM.Types.EWord])) => Optics.Label.LabelOptic "iterations" k (EVM.Types.VM t) (EVM.Types.VM t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Map.Internal.Map GHC.Base.String GHC.Base.String, b GHC.Types.~ Data.Map.Internal.Map GHC.Base.String GHC.Base.String) => Optics.Label.LabelOptic "osEnv" k (EVM.Types.VM t) (EVM.Types.VM t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Sequence.Internal.Seq EVM.Types.ForkState, b GHC.Types.~ Data.Sequence.Internal.Seq EVM.Types.ForkState) => Optics.Label.LabelOptic "forks" k (EVM.Types.VM t) (EVM.Types.VM t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Set.Internal.Set (Data.ByteString.Internal.Type.ByteString, EVM.Types.W256), b GHC.Types.~ Data.Set.Internal.Set (Data.ByteString.Internal.Type.ByteString, EVM.Types.W256)) => Optics.Label.LabelOptic "keccakPreImgs" k (EVM.Types.VM t) (EVM.Types.VM t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Tree.Zipper.TreePos Data.Tree.Zipper.Empty EVM.Types.Trace, b GHC.Types.~ Data.Tree.Zipper.TreePos Data.Tree.Zipper.Empty EVM.Types.Trace) => Optics.Label.LabelOptic "traces" k (EVM.Types.VM t) (EVM.Types.VM t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Block, b GHC.Types.~ EVM.Types.Block) => Optics.Label.LabelOptic "block" k (EVM.Types.VM t) (EVM.Types.VM t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.ContractCode, b GHC.Types.~ EVM.Types.ContractCode) => Optics.Label.LabelOptic "code" k (EVM.Types.FrameState t) (EVM.Types.FrameState t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Env, b GHC.Types.~ EVM.Types.Env) => Optics.Label.LabelOptic "env" k (EVM.Types.VM t) (EVM.Types.VM t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Expr 'EVM.Types.Buf, b GHC.Types.~ EVM.Types.Expr 'EVM.Types.Buf) => Optics.Label.LabelOptic "calldata" k (EVM.Types.FrameState t) (EVM.Types.FrameState t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Expr 'EVM.Types.Buf, b GHC.Types.~ EVM.Types.Expr 'EVM.Types.Buf) => Optics.Label.LabelOptic "returndata" k (EVM.Types.FrameState t) (EVM.Types.FrameState t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Expr 'EVM.Types.EAddr, b GHC.Types.~ EVM.Types.Expr 'EVM.Types.EAddr) => Optics.Label.LabelOptic "caller" k (EVM.Types.FrameState t) (EVM.Types.FrameState t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Expr 'EVM.Types.EAddr, b GHC.Types.~ EVM.Types.Expr 'EVM.Types.EAddr) => Optics.Label.LabelOptic "codeContract" k (EVM.Types.FrameState t) (EVM.Types.FrameState t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Expr 'EVM.Types.EAddr, b GHC.Types.~ EVM.Types.Expr 'EVM.Types.EAddr) => Optics.Label.LabelOptic "contract" k (EVM.Types.FrameState t) (EVM.Types.FrameState t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Expr 'EVM.Types.EWord, b GHC.Types.~ EVM.Types.Expr 'EVM.Types.EWord) => Optics.Label.LabelOptic "callvalue" k (EVM.Types.FrameState t) (EVM.Types.FrameState t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.FrameContext, b GHC.Types.~ EVM.Types.FrameContext) => Optics.Label.LabelOptic "context" k (EVM.Types.Frame t) (EVM.Types.Frame t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.FrameState t, b GHC.Types.~ EVM.Types.FrameState t) => Optics.Label.LabelOptic "state" k (EVM.Types.VM t) (EVM.Types.VM t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.FrameState t1, b GHC.Types.~ EVM.Types.FrameState t2) => Optics.Label.LabelOptic "state" k (EVM.Types.Frame t1) (EVM.Types.Frame t2) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Gas t, b GHC.Types.~ EVM.Types.Gas t) => Optics.Label.LabelOptic "burned" k (EVM.Types.VM t) (EVM.Types.VM t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Gas t1, b GHC.Types.~ EVM.Types.Gas t2) => Optics.Label.LabelOptic "gas" k (EVM.Types.FrameState t1) (EVM.Types.FrameState t2) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Memory, b GHC.Types.~ EVM.Types.Memory) => Optics.Label.LabelOptic "memory" k (EVM.Types.FrameState t) (EVM.Types.FrameState t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.PathsVisited, b GHC.Types.~ EVM.Types.PathsVisited) => Optics.Label.LabelOptic "pathsVisited" k (EVM.Types.VM t) (EVM.Types.VM t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.RuntimeConfig, b GHC.Types.~ EVM.Types.RuntimeConfig) => Optics.Label.LabelOptic "config" k (EVM.Types.VM t) (EVM.Types.VM t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.TxState, b GHC.Types.~ EVM.Types.TxState) => Optics.Label.LabelOptic "tx" k (EVM.Types.VM t) (EVM.Types.VM t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ GHC.Maybe.Maybe (EVM.Types.Expr 'EVM.Types.EAddr), b GHC.Types.~ GHC.Maybe.Maybe (EVM.Types.Expr 'EVM.Types.EAddr)) => Optics.Label.LabelOptic "overrideCaller" k (EVM.Types.FrameState t) (EVM.Types.FrameState t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ GHC.Maybe.Maybe (EVM.Types.VMResult t), b GHC.Types.~ GHC.Maybe.Maybe (EVM.Types.VMResult t)) => Optics.Label.LabelOptic "result" k (EVM.Types.VM t) (EVM.Types.VM t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ GHC.Types.Bool, b GHC.Types.~ GHC.Types.Bool) => Optics.Label.LabelOptic "resetCaller" k (EVM.Types.FrameState t) (EVM.Types.FrameState t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ GHC.Types.Bool, b GHC.Types.~ GHC.Types.Bool) => Optics.Label.LabelOptic "static" k (EVM.Types.FrameState t) (EVM.Types.FrameState t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ GHC.Types.Int, b GHC.Types.~ GHC.Types.Int) => Optics.Label.LabelOptic "currentFork" k (EVM.Types.VM t) (EVM.Types.VM t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ GHC.Types.Int, b GHC.Types.~ GHC.Types.Int) => Optics.Label.LabelOptic "exploreDepth" k (EVM.Types.VM t) (EVM.Types.VM t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ GHC.Types.Int, b GHC.Types.~ GHC.Types.Int) => Optics.Label.LabelOptic "freshVar" k (EVM.Types.VM t) (EVM.Types.VM t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ GHC.Types.Int, b GHC.Types.~ GHC.Types.Int) => Optics.Label.LabelOptic "pc" k (EVM.Types.FrameState t) (EVM.Types.FrameState t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ GHC.Word.Word64, b GHC.Types.~ GHC.Word.Word64) => Optics.Label.LabelOptic "memorySize" k (EVM.Types.FrameState t) (EVM.Types.FrameState t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ [EVM.Types.Expr 'EVM.Types.EWord], b GHC.Types.~ [EVM.Types.Expr 'EVM.Types.EWord]) => Optics.Label.LabelOptic "stack" k (EVM.Types.FrameState t) (EVM.Types.FrameState t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ [EVM.Types.Expr 'EVM.Types.Log], b GHC.Types.~ [EVM.Types.Expr 'EVM.Types.Log]) => Optics.Label.LabelOptic "logs" k (EVM.Types.VM t) (EVM.Types.VM t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ [EVM.Types.Frame t], b GHC.Types.~ [EVM.Types.Frame t]) => Optics.Label.LabelOptic "frames" k (EVM.Types.VM t) (EVM.Types.VM t) a b
+ EVM.Types: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ [EVM.Types.Prop], b GHC.Types.~ [EVM.Types.Prop]) => Optics.Label.LabelOptic "constraints" k (EVM.Types.VM t) (EVM.Types.VM t) a b
+ EVM.Types: instance GHC.Generics.Generic (EVM.Types.FrameState t)
+ EVM.Types: instance GHC.Generics.Generic (EVM.Types.VM t)
+ EVM.Types: instance GHC.Show.Show (EVM.Types.Effect t)
+ EVM.Types: instance GHC.Show.Show (EVM.Types.Frame 'EVM.Types.Concrete)
+ EVM.Types: instance GHC.Show.Show (EVM.Types.Frame 'EVM.Types.Symbolic)
+ EVM.Types: instance GHC.Show.Show (EVM.Types.FrameState 'EVM.Types.Concrete)
+ EVM.Types: instance GHC.Show.Show (EVM.Types.FrameState 'EVM.Types.Symbolic)
+ EVM.Types: instance GHC.Show.Show (EVM.Types.Query t)
+ EVM.Types: instance GHC.Show.Show (EVM.Types.VM 'EVM.Types.Concrete)
+ EVM.Types: instance GHC.Show.Show (EVM.Types.VM 'EVM.Types.Symbolic)
+ EVM.Types: instance GHC.Show.Show (EVM.Types.VMResult t)
+ EVM.Types: instance GHC.Show.Show EVM.Types.BranchContext
+ EVM.Types: instance GHC.Show.Show EVM.Types.Memory
+ EVM.UnitTest: getReproFailure :: App m => Sig -> Expr 'Buf -> SMTCex -> m (Err ReproducibleCex)
- EVM: accessAccountForGas :: forall (t :: VMType) s. Expr 'EAddr -> EVM t s Bool
+ EVM: accessAccountForGas :: forall (t :: VMType). Expr 'EAddr -> EVM t Bool
- EVM: accessAndBurn :: forall (t :: VMType) s. VMOps t => Expr 'EAddr -> EVM t s () -> EVM t s ()
+ EVM: accessAndBurn :: forall (t :: VMType). VMOps t => Expr 'EAddr -> EVM t () -> EVM t ()
- EVM: accessMemoryRange :: forall (t :: VMType) s. VMOps t => Expr 'EWord -> Expr 'EWord -> EVM t s () -> EVM t s ()
+ EVM: accessMemoryRange :: forall (t :: VMType). VMOps t => Expr 'EWord -> Expr 'EWord -> EVM t () -> EVM t ()
- EVM: accessMemoryWord :: forall (t :: VMType) s. VMOps t => Expr 'EWord -> EVM t s () -> EVM t s ()
+ EVM: accessMemoryWord :: forall (t :: VMType). VMOps t => Expr 'EWord -> EVM t () -> EVM t ()
- EVM: accessStorage :: forall s (t :: VMType). (?conf :: Config, VMOps t, Typeable t) => Expr 'EAddr -> Expr 'EWord -> (Expr 'EWord -> EVM t s ()) -> EVM t s ()
+ EVM: accessStorage :: forall (t :: VMType). (?conf :: Config, VMOps t, Typeable t) => Expr 'EAddr -> Expr 'EWord -> (Expr 'EWord -> EVM t ()) -> EVM t ()
- EVM: accessStorageForGas :: forall (t :: VMType) s. Expr 'EAddr -> Expr 'EWord -> EVM t s Bool
+ EVM: accessStorageForGas :: forall (t :: VMType). Expr 'EAddr -> W256 -> EVM t Bool
- EVM: accessTStorage :: forall (t :: VMType) s. VMOps t => Expr 'EAddr -> Expr 'EWord -> (Expr 'EWord -> EVM t s ()) -> EVM t s ()
+ EVM: accessTStorage :: forall (t :: VMType). VMOps t => Expr 'EAddr -> Expr 'EWord -> (Expr 'EWord -> EVM t ()) -> EVM t ()
- EVM: accessUnboundedMemoryRange :: forall (t :: VMType) s. VMOps t => Word64 -> Word64 -> EVM t s () -> EVM t s ()
+ EVM: accessUnboundedMemoryRange :: forall (t :: VMType). VMOps t => Word64 -> Word64 -> EVM t () -> EVM t ()
- EVM: accountExists :: forall (t :: VMType) s. Expr 'EAddr -> VM t s -> Bool
+ EVM: accountExists :: forall (t :: VMType). Expr 'EAddr -> VM t -> Bool
- EVM: addAliasConstraints :: forall (t :: VMType) s. EVM t s ()
+ EVM: addAliasConstraints :: forall (t :: VMType). EVM t ()
- EVM: blankState :: forall (t :: VMType) s. VMOps t => ST s (FrameState t s)
+ EVM: blankState :: forall (t :: VMType). VMOps t => ST RealWorld (FrameState t)
- EVM: burn :: forall (t :: VMType) s. VMOps t => Word64 -> EVM t s () -> EVM t s ()
+ EVM: burn :: forall (t :: VMType). VMOps t => Word64 -> EVM t () -> EVM t ()
- EVM: callChecks :: forall (t :: VMType) s. (?op :: Word8, ?conf :: Config, VMOps t) => Contract -> Gas t -> Expr 'EAddr -> Expr 'EAddr -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> [Expr 'EWord] -> (Gas t -> EVM t s ()) -> EVM t s ()
+ EVM: callChecks :: forall (t :: VMType). (?op :: Word8, ?conf :: Config, VMOps t) => Contract -> Gas t -> Expr 'EAddr -> Expr 'EAddr -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> [Expr 'EWord] -> (Gas t -> EVM t ()) -> EVM t ()
- EVM: cheat :: forall (t :: VMType) s. (?conf :: Config, ?op :: Word8, VMOps t, Typeable t) => Gas t -> (Expr 'EWord, Expr 'EWord) -> (Expr 'EWord, Expr 'EWord) -> [Expr 'EWord] -> EVM t s ()
+ EVM: cheat :: forall (t :: VMType). (?conf :: Config, ?op :: Word8, VMOps t, Typeable t) => Gas t -> (Expr 'EWord, Expr 'EWord) -> (Expr 'EWord, Expr 'EWord) -> [Expr 'EWord] -> EVM t ()
- EVM: cheatActions :: forall (t :: VMType) s. (?conf :: Config, VMOps t, Typeable t) => Map FunctionSelector (CheatAction t s)
+ EVM: cheatActions :: forall (t :: VMType). (?conf :: Config, VMOps t, Typeable t) => Map FunctionSelector (CheatAction t)
- EVM: checkJump :: forall (t :: VMType) s. VMOps t => Int -> [Expr 'EWord] -> EVM t s ()
+ EVM: checkJump :: forall (t :: VMType). VMOps t => Int -> [Expr 'EWord] -> EVM t ()
- EVM: clearTStorages :: forall (t :: VMType) s. EVM t s ()
+ EVM: clearTStorages :: forall (t :: VMType). EVM t ()
- EVM: codeloc :: forall (t :: VMType) s. EVM t s CodeLocation
+ EVM: codeloc :: forall (t :: VMType). EVM t CodeLocation
- EVM: copyBytesToMemory :: forall (t :: VMType) s. Expr 'Buf -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> EVM t s ()
+ EVM: copyBytesToMemory :: forall (t :: VMType). Expr 'Buf -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> EVM t ()
- EVM: copyCallBytesToMemory :: forall (t :: VMType) s. Expr 'Buf -> Expr 'EWord -> Expr 'EWord -> EVM t s ()
+ EVM: copyCallBytesToMemory :: forall (t :: VMType). Expr 'Buf -> Expr 'EWord -> Expr 'EWord -> EVM t ()
- EVM: create :: forall (t :: VMType) s. (?op :: Word8, ?conf :: Config, VMOps t) => Expr 'EAddr -> Contract -> Expr 'EWord -> Gas t -> Expr 'EWord -> [Expr 'EWord] -> Expr 'EAddr -> Expr 'Buf -> EVM t s ()
+ EVM: create :: forall (t :: VMType). (?op :: Word8, ?conf :: Config, VMOps t) => Expr 'EAddr -> Contract -> Expr 'EWord -> Gas t -> Expr 'EWord -> [Expr 'EWord] -> Expr 'EAddr -> Expr 'Buf -> EVM t ()
- EVM: create2Address :: forall (t :: VMType) s. Expr 'EAddr -> W256 -> ByteString -> EVM t s (Expr 'EAddr)
+ EVM: create2Address :: forall (t :: VMType). Expr 'EAddr -> W256 -> ByteString -> EVM t (Expr 'EAddr)
- EVM: createAddress :: forall (t :: VMType) s. Expr 'EAddr -> Maybe W64 -> EVM t s (Expr 'EAddr)
+ EVM: createAddress :: forall (t :: VMType). Expr 'EAddr -> Maybe W64 -> EVM t (Expr 'EAddr)
- EVM: currentContract :: forall (t :: VMType) s. VM t s -> Maybe Contract
+ EVM: currentContract :: forall (t :: VMType). VM t -> Maybe Contract
- EVM: delegateCall :: forall (t :: VMType) s. (VMOps t, ?op :: Word8, ?conf :: Config, Typeable t) => Contract -> Gas t -> Expr 'EAddr -> Expr 'EAddr -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> [Expr 'EWord] -> (Expr 'EAddr -> EVM t s ()) -> (Expr 'EAddr -> EVM t s ()) -> EVM t s ()
+ EVM: delegateCall :: forall (t :: VMType). (VMOps t, ?op :: Word8, ?conf :: Config, Typeable t) => Contract -> Gas t -> Expr 'EAddr -> Expr 'EAddr -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> [Expr 'EWord] -> (Expr 'EAddr -> EVM t ()) -> (Expr 'EAddr -> EVM t ()) -> EVM t ()
- EVM: exec1 :: forall (t :: VMType) s. (VMOps t, Typeable t) => Config -> EVM t s ()
+ EVM: exec1 :: forall (t :: VMType). (VMOps t, Typeable t) => Config -> EVM t ()
- EVM: executePrecompile :: forall (t :: VMType) s. (?op :: Word8, VMOps t) => Addr -> Gas t -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> [Expr 'EWord] -> EVM t s ()
+ EVM: executePrecompile :: forall (t :: VMType). (?op :: Word8, VMOps t) => Addr -> Gas t -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> [Expr 'EWord] -> EVM t ()
- EVM: fetchAccount :: forall (t :: VMType) s. VMOps t => Expr 'EAddr -> (Contract -> EVM t s ()) -> EVM t s ()
+ EVM: fetchAccount :: forall (t :: VMType). VMOps t => Expr 'EAddr -> (Contract -> EVM t ()) -> EVM t ()
- EVM: fetchAccountWithFallback :: forall (t :: VMType) s. VMOps t => Expr 'EAddr -> (Expr 'EAddr -> EVM t s ()) -> (Contract -> EVM t s ()) -> EVM t s ()
+ EVM: fetchAccountWithFallback :: forall (t :: VMType). VMOps t => Expr 'EAddr -> (Expr 'EAddr -> EVM t ()) -> (Contract -> EVM t ()) -> EVM t ()
- EVM: finalize :: forall (t :: VMType) s. VMOps t => EVM t s ()
+ EVM: finalize :: forall (t :: VMType). VMOps t => EVM t ()
- EVM: finishAllFramesAndStop :: forall (t :: VMType) s. VMOps t => EVM t s ()
+ EVM: finishAllFramesAndStop :: forall (t :: VMType). VMOps t => EVM t ()
- EVM: finishFrame :: forall (t :: VMType) s. VMOps t => FrameResult -> EVM t s ()
+ EVM: finishFrame :: forall (t :: VMType). VMOps t => FrameResult -> EVM t ()
- EVM: forceAddr :: forall (t :: VMType) s. (?conf :: Config, VMOps t, Typeable t) => Expr 'EWord -> (Expr 'EWord -> EVM t s ()) -> (Expr 'EAddr -> EVM t s ()) -> EVM t s ()
+ EVM: forceAddr :: forall (t :: VMType). (?conf :: Config, VMOps t, Typeable t) => Expr 'EWord -> (Expr 'EWord -> EVM t ()) -> (Expr 'EAddr -> EVM t ()) -> EVM t ()
- EVM: forceConcrete :: forall (t :: VMType) s. (?conf :: Config, VMOps t) => Expr 'EWord -> String -> (W256 -> EVM t s ()) -> EVM t s ()
+ EVM: forceConcrete :: forall (t :: VMType). (?conf :: Config, VMOps t) => Expr 'EWord -> String -> (W256 -> EVM t ()) -> EVM t ()
- EVM: forceConcrete2 :: forall (t :: VMType) s. VMOps t => (Expr 'EWord, Expr 'EWord) -> String -> ((W256, W256) -> EVM t s ()) -> EVM t s ()
+ EVM: forceConcrete2 :: forall (t :: VMType). VMOps t => (Expr 'EWord, Expr 'EWord) -> String -> ((W256, W256) -> EVM t ()) -> EVM t ()
- EVM: forceConcreteAddr :: forall (t :: VMType) s. (?conf :: Config, VMOps t) => Expr 'EAddr -> String -> (Addr -> EVM t s ()) -> EVM t s ()
+ EVM: forceConcreteAddr :: forall (t :: VMType). (?conf :: Config, VMOps t) => Expr 'EAddr -> String -> (Addr -> EVM t ()) -> EVM t ()
- EVM: forceConcreteAddr2 :: forall (t :: VMType) s. VMOps t => (Expr 'EAddr, Expr 'EAddr) -> String -> ((Addr, Addr) -> EVM t s ()) -> EVM t s ()
+ EVM: forceConcreteAddr2 :: forall (t :: VMType). VMOps t => (Expr 'EAddr, Expr 'EAddr) -> String -> ((Addr, Addr) -> EVM t ()) -> EVM t ()
- EVM: forceConcreteBuf :: forall (t :: VMType) s. VMOps t => Expr 'Buf -> String -> (ByteString -> EVM t s ()) -> EVM t s ()
+ EVM: forceConcreteBuf :: forall (t :: VMType). VMOps t => Expr 'Buf -> String -> (ByteString -> EVM t ()) -> EVM t ()
- EVM: forceConcreteLimitSz :: forall (t :: VMType) s. (?conf :: Config, VMOps t) => Expr 'EWord -> Int -> String -> (W256 -> EVM t s ()) -> EVM t s ()
+ EVM: forceConcreteLimitSz :: forall (t :: VMType). (?conf :: Config, VMOps t) => Expr 'EWord -> Int -> String -> (W256 -> EVM t ()) -> EVM t ()
- EVM: freezeMemory :: forall s (t :: VMType). MutableMemory s -> EVM t s (Expr 'Buf)
+ EVM: freezeMemory :: forall (t :: VMType). MutableMemory -> EVM t (Expr 'Buf)
- EVM: freshBufFallback :: forall (t :: VMType) s. (?conf :: Config, VMOps t, ?op :: Word8) => [Expr 'EWord] -> EVM t s ()
+ EVM: freshBufFallback :: forall (t :: VMType). (?conf :: Config, VMOps t, ?op :: Word8) => [Expr 'EWord] -> EVM t ()
- EVM: freshSymAddr :: forall (t :: VMType) s. EVM t s (Expr 'EAddr)
+ EVM: freshSymAddr :: forall (t :: VMType). EVM t (Expr 'EAddr)
- EVM: freshVarFallback :: forall (t :: VMType) (a :: EType) s. (VMOps t, ?op :: Word8) => [Expr 'EWord] -> Expr a -> EVM t s ()
+ EVM: freshVarFallback :: forall (t :: VMType) (a :: EType). (VMOps t, ?op :: Word8) => [Expr 'EWord] -> Expr a -> EVM t ()
- EVM: getCodeLocation :: forall (t :: VMType) s. VM t s -> CodeLocation
+ EVM: getCodeLocation :: forall (t :: VMType). VM t -> CodeLocation
- EVM: getOpName :: forall (t :: VMType) s. FrameState t s -> [Char]
+ EVM: getOpName :: forall (t :: VMType). FrameState t -> [Char]
- EVM: getOpW8 :: forall (t :: VMType) s. FrameState t s -> Word8
+ EVM: getOpW8 :: forall (t :: VMType). FrameState t -> Word8
- EVM: insertTrace :: forall (t :: VMType) s. TraceData -> EVM t s ()
+ EVM: insertTrace :: forall (t :: VMType). TraceData -> EVM t ()
- EVM: isValidJumpDest :: forall (t :: VMType) s. VM t s -> Int -> Bool
+ EVM: isValidJumpDest :: forall (t :: VMType). VM t -> Int -> Bool
- EVM: limitStack :: forall (t :: VMType) s. VMOps t => Int -> EVM t s () -> EVM t s ()
+ EVM: limitStack :: forall (t :: VMType). VMOps t => Int -> EVM t () -> EVM t ()
- EVM: loadContract :: forall (t :: VMType) s. Expr 'EAddr -> State (VM t s) ()
+ EVM: loadContract :: forall (t :: VMType). Expr 'EAddr -> State (VM t) ()
- EVM: makeVm :: forall (t :: VMType) s. VMOps t => VMOpts t -> ST s (VM t s)
+ EVM: makeVm :: forall (t :: VMType). VMOps t => VMOpts t -> ST RealWorld (VM t)
- EVM: next :: forall (t :: VMType) s. (?op :: Word8) => EVM t s ()
+ EVM: next :: forall (t :: VMType). (?op :: Word8) => EVM t ()
- EVM: noJumpIntoInitData :: forall (t :: VMType) s. VMOps t => Int -> EVM t s () -> EVM t s ()
+ EVM: noJumpIntoInitData :: forall (t :: VMType). VMOps t => Int -> EVM t () -> EVM t ()
- EVM: notStatic :: forall (t :: VMType) s. VMOps t => EVM t s () -> EVM t s ()
+ EVM: notStatic :: forall (t :: VMType). VMOps t => EVM t () -> EVM t ()
- EVM: onlyDeployed :: forall (t :: VMType) s. (?conf :: Config, VMOps t, Typeable t) => Expr 'EWord -> (Expr 'EWord -> EVM t s ()) -> (Expr 'EAddr -> EVM t s ()) -> EVM t s ()
+ EVM: onlyDeployed :: forall (t :: VMType). (?conf :: Config, VMOps t, Typeable t) => Expr 'EWord -> (Expr 'EWord -> EVM t ()) -> (Expr 'EAddr -> EVM t ()) -> EVM t ()
- EVM: popTrace :: forall (t :: VMType) s. EVM t s ()
+ EVM: popTrace :: forall (t :: VMType). EVM t ()
- EVM: precompiledContract :: forall (t :: VMType) s. (?conf :: Config, ?op :: Word8, VMOps t) => Contract -> Gas t -> Addr -> Addr -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> [Expr 'EWord] -> EVM t s ()
+ EVM: precompiledContract :: forall (t :: VMType). (?conf :: Config, ?op :: Word8, VMOps t) => Contract -> Gas t -> Addr -> Addr -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> [Expr 'EWord] -> EVM t ()
- EVM: push :: forall (t :: VMType) s. W256 -> EVM t s ()
+ EVM: push :: forall (t :: VMType). W256 -> EVM t ()
- EVM: pushAddr :: forall (t :: VMType) s. Expr 'EAddr -> EVM t s ()
+ EVM: pushAddr :: forall (t :: VMType). Expr 'EAddr -> EVM t ()
- EVM: pushSym :: forall (t :: VMType) s. Expr 'EWord -> EVM t s ()
+ EVM: pushSym :: forall (t :: VMType). Expr 'EWord -> EVM t ()
- EVM: pushTrace :: forall (t :: VMType) s. TraceData -> EVM t s ()
+ EVM: pushTrace :: forall (t :: VMType). TraceData -> EVM t ()
- EVM: query :: forall (t :: VMType) s. Query t s -> EVM t s ()
+ EVM: query :: forall (t :: VMType). Query t -> EVM t ()
- EVM: readMemory :: forall (t :: VMType) s. Expr 'EWord -> Expr 'EWord -> EVM t s (Expr 'Buf)
+ EVM: readMemory :: forall (t :: VMType). Expr 'EWord -> Expr 'EWord -> EVM t (Expr 'Buf)
- EVM: refund :: forall (t :: VMType) s. Word64 -> EVM t s ()
+ EVM: refund :: forall (t :: VMType). Word64 -> EVM t ()
- EVM: replaceCode :: forall (t :: VMType) s. Expr 'EAddr -> ContractCode -> EVM t s ()
+ EVM: replaceCode :: forall (t :: VMType). Expr 'EAddr -> ContractCode -> EVM t ()
- EVM: replaceCodeOfSelf :: forall (t :: VMType) s. ContractCode -> EVM t s ()
+ EVM: replaceCodeOfSelf :: forall (t :: VMType). ContractCode -> EVM t ()
- EVM: resetState :: forall (t :: VMType) s. VMOps t => EVM t s ()
+ EVM: resetState :: forall (t :: VMType). VMOps t => EVM t ()
- EVM: selfdestruct :: forall (t :: VMType) s. Expr 'EAddr -> EVM t s ()
+ EVM: selfdestruct :: forall (t :: VMType). Expr 'EAddr -> EVM t ()
- EVM: setEIP4788Storage :: forall (t :: VMType) s. VMOpts t -> VM t s -> VM t s
+ EVM: setEIP4788Storage :: forall (t :: VMType). VMOpts t -> VM t -> VM t
- EVM: stackOp1 :: forall (t :: VMType) s. (?op :: Word8, VMOps t) => Word64 -> (Expr 'EWord -> Expr 'EWord) -> EVM t s ()
+ EVM: stackOp1 :: forall (t :: VMType). (?op :: Word8, VMOps t) => Word64 -> (Expr 'EWord -> Expr 'EWord) -> EVM t ()
- EVM: stackOp2 :: forall (t :: VMType) s. (?op :: Word8, VMOps t) => Word64 -> (Expr 'EWord -> Expr 'EWord -> Expr 'EWord) -> EVM t s ()
+ EVM: stackOp2 :: forall (t :: VMType). (?op :: Word8, VMOps t) => Word64 -> (Expr 'EWord -> Expr 'EWord -> Expr 'EWord) -> EVM t ()
- EVM: stackOp3 :: forall (t :: VMType) s. (?op :: Word8, VMOps t) => Word64 -> (Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord) -> EVM t s ()
+ EVM: stackOp3 :: forall (t :: VMType). (?op :: Word8, VMOps t) => Word64 -> (Expr 'EWord -> Expr 'EWord -> Expr 'EWord -> Expr 'EWord) -> EVM t ()
- EVM: symbolify :: VM 'Concrete s -> VM 'Symbolic s
+ EVM: symbolify :: VM 'Concrete -> VM 'Symbolic
- EVM: symbolifyFrame :: Frame 'Concrete s -> Frame 'Symbolic s
+ EVM: symbolifyFrame :: Frame 'Concrete -> Frame 'Symbolic
- EVM: symbolifyFrameState :: FrameState 'Concrete s -> FrameState 'Symbolic s
+ EVM: symbolifyFrameState :: FrameState 'Concrete -> FrameState 'Symbolic
- EVM: symbolifyResult :: VMResult 'Concrete s -> VMResult 'Symbolic s
+ EVM: symbolifyResult :: VMResult 'Concrete -> VMResult 'Symbolic
- EVM: touchAccount :: forall (t :: VMType) s. Expr 'EAddr -> EVM t s ()
+ EVM: touchAccount :: forall (t :: VMType). Expr 'EAddr -> EVM t ()
- EVM: touchAddress :: forall (t :: VMType) s. VMOps t => Expr 'EAddr -> EVM t s ()
+ EVM: touchAddress :: forall (t :: VMType). VMOps t => Expr 'EAddr -> EVM t ()
- EVM: traceForest :: forall (t :: VMType) s. VM t s -> Forest Trace
+ EVM: traceForest :: forall (t :: VMType). VM t -> Forest Trace
- EVM: traceTopLog :: forall (t :: VMType) s. [Expr 'Log] -> EVM t s ()
+ EVM: traceTopLog :: forall (t :: VMType). [Expr 'Log] -> EVM t ()
- EVM: transfer :: forall (t :: VMType) s. (VMOps t, ?conf :: Config) => Expr 'EAddr -> Expr 'EAddr -> Expr 'EWord -> EVM t s ()
+ EVM: transfer :: forall (t :: VMType). (VMOps t, ?conf :: Config) => Expr 'EAddr -> Expr 'EAddr -> Expr 'EWord -> EVM t ()
- EVM: type CheatAction (t :: VMType) s = Expr 'Buf -> EVM t s ()
+ EVM: type CheatAction (t :: VMType) = Expr 'Buf -> EVM t ()
- EVM: unRefund :: forall (t :: VMType) s. Word64 -> EVM t s ()
+ EVM: unRefund :: forall (t :: VMType). Word64 -> EVM t ()
- EVM: underrun :: forall (t :: VMType) s. VMOps t => EVM t s ()
+ EVM: underrun :: forall (t :: VMType). VMOps t => EVM t ()
- EVM: unexpectedSymArg :: forall (a :: EType) (t :: VMType) s. (Typeable a, VMOps t) => String -> [Expr a] -> EVM t s ()
+ EVM: unexpectedSymArg :: forall (a :: EType) (t :: VMType). (Typeable a, VMOps t) => String -> [Expr a] -> EVM t ()
- EVM: unexpectedSymArgW :: forall (a :: EType) (t :: VMType) s. (Typeable a, VMOps t) => String -> Expr a -> EVM t s ()
+ EVM: unexpectedSymArgW :: forall (a :: EType) (t :: VMType). (Typeable a, VMOps t) => String -> Expr a -> EVM t ()
- EVM: unknownCode :: forall (t :: VMType) s. VMOps t => Expr 'EAddr -> EVM t s ()
+ EVM: unknownCode :: forall (t :: VMType). VMOps t => Expr 'EAddr -> EVM t ()
- EVM: vmError :: forall (t :: VMType) s. VMOps t => EvmError -> EVM t s ()
+ EVM: vmError :: forall (t :: VMType). VMOps t => EvmError -> EVM t ()
- EVM: vmOp :: forall (t :: VMType) s. VM t s -> Maybe Op
+ EVM: vmOp :: forall (t :: VMType). VM t -> Maybe Op
- EVM: vmOpIx :: forall (t :: VMType) s. VM t s -> Maybe Int
+ EVM: vmOpIx :: forall (t :: VMType). VM t -> Maybe Int
- EVM: withTraceLocation :: forall (t :: VMType) s. TraceData -> EVM t s Trace
+ EVM: withTraceLocation :: forall (t :: VMType). TraceData -> EVM t Trace
- EVM: writeMemory :: forall s (t :: VMType). MutableMemory s -> Int -> ByteString -> EVM t s ()
+ EVM: writeMemory :: forall (t :: VMType). MutableMemory -> Int -> ByteString -> EVM t ()
- EVM.Exec: exec :: forall (t :: VMType) s. (VMOps t, Typeable t) => Config -> EVM t s (VMResult t s)
+ EVM.Exec: exec :: forall (t :: VMType). (VMOps t, Typeable t) => Config -> EVM t (VMResult t)
- EVM.Exec: execWhile :: forall (t :: VMType) s. (VM t s -> Bool) -> State (VM t s) Int
+ EVM.Exec: execWhile :: forall (t :: VMType). (VM t -> Bool) -> State (VM t) Int
- EVM.Exec: run :: forall (t :: VMType) s. (VMOps t, Typeable t) => Config -> EVM t s (VM t s)
+ EVM.Exec: run :: forall (t :: VMType). (VMOps t, Typeable t) => Config -> EVM t (VM t)
- EVM.Exec: vmForEthrunCreation :: forall (t :: VMType) s. VMOps t => ByteString -> ST s (VM t s)
+ EVM.Exec: vmForEthrunCreation :: forall (t :: VMType). VMOps t => ByteString -> ST RealWorld (VM t)
- EVM.Expr: ConstState :: Map (Expr 'EWord) W256 -> Bool -> ConstState
+ EVM.Expr: ConstState :: Map (Expr 'EWord) W256 -> Map (Expr 'EWord) W256 -> Map (Expr 'EWord) W256 -> Bool -> ConstState
- EVM.Fetch: FetchCache :: Map Addr Contract -> Map (Addr, W256) W256 -> Map W256 Block -> FetchCache
+ EVM.Fetch: FetchCache :: Map Addr RPCContract -> Map (Addr, W256) W256 -> Map W256 Block -> FetchCache
- EVM.Fetch: RpcInfo :: Maybe (BlockNumber, Text) -> Maybe (Map Addr RPCContract) -> Maybe (Map (Addr, W256) W256) -> Maybe (Map W256 Block) -> RpcInfo
+ EVM.Fetch: RpcInfo :: Maybe (BlockNumber, Text) -> RpcInfo
- EVM.Fetch: Session :: Session -> MVar (Maybe W256) -> MVar FetchCache -> Session
+ EVM.Fetch: Session :: Session -> MVar (Maybe W256) -> MVar FetchCache -> Maybe FilePath -> MVar (Set Addr) -> MVar (Set (Addr, W256)) -> Session
- EVM.Fetch: [contractCache] :: FetchCache -> Map Addr Contract
+ EVM.Fetch: [contractCache] :: FetchCache -> Map Addr RPCContract
- EVM.Fetch: addFetchCache :: Session -> Addr -> Contract -> IO ()
+ EVM.Fetch: addFetchCache :: Session -> Addr -> RPCContract -> IO ()
- EVM.Fetch: fetchContractWithSession :: Config -> Session -> BlockNumber -> Text -> Addr -> IO (Maybe Contract)
+ EVM.Fetch: fetchContractWithSession :: Config -> Session -> BlockNumber -> Text -> Addr -> IO (FetchResult RPCContract)
- EVM.Fetch: fetchQuery :: Show a => BlockNumber -> (Value -> IO (Maybe Value)) -> RpcQuery a -> IO (Maybe a)
+ EVM.Fetch: fetchQuery :: Show a => BlockNumber -> (Value -> IO (Either Text Value)) -> RpcQuery a -> IO (Either Text a)
- EVM.Fetch: fetchSlotWithSession :: Session -> BlockNumber -> Text -> Addr -> W256 -> IO (Maybe W256)
+ EVM.Fetch: fetchSlotWithSession :: Session -> BlockNumber -> Text -> Addr -> W256 -> IO (Either Text W256)
- EVM.Fetch: fetchWithSession :: Text -> Session -> Value -> IO (Maybe Value)
+ EVM.Fetch: fetchWithSession :: Text -> Session -> Value -> IO (Either Text Value)
- EVM.Fetch: mkSession :: App m => m Session
+ EVM.Fetch: mkSession :: App m => Maybe FilePath -> Maybe W256 -> m Session
- EVM.Fetch: oracle :: forall (t :: VMType) m s. App m => SolverGroup -> Maybe Session -> RpcInfo -> Fetcher t m s
+ EVM.Fetch: oracle :: forall (t :: VMType) m. App m => SolverGroup -> Maybe Session -> RpcInfo -> Fetcher t m
- EVM.Fetch: type Fetcher (t :: VMType) (m :: Type -> Type) s = App m => Query t s -> m EVM t s ()
+ EVM.Fetch: type Fetcher (t :: VMType) (m :: Type -> Type) = App m => Query t -> m EVM t ()
- EVM.Fetch: zero :: forall (t :: VMType) m s. Natural -> Maybe Natural -> Fetcher t m s
+ EVM.Fetch: zero :: forall (t :: VMType) m. Natural -> Maybe Natural -> Fetcher t m
- EVM.Format: formatPartialDetailed :: forall (s :: VMType) t. Maybe (WarningData s t) -> PartialExec -> Text
+ EVM.Format: formatPartialDetailed :: forall (t :: VMType). Maybe (WarningData t) -> PartialExec -> Text
- EVM.Format: showTraceTree :: forall (t :: VMType) s. DappInfo -> VM t s -> Text
+ EVM.Format: showTraceTree :: forall (t :: VMType). DappInfo -> VM t -> Text
- EVM.Solidity: WarningData :: SolcContract -> SourceCache -> VM s t -> WarningData (s :: VMType) t
+ EVM.Solidity: WarningData :: SolcContract -> SourceCache -> VM t -> WarningData (t :: VMType)
- EVM.Solidity: [solcContr] :: WarningData (s :: VMType) t -> SolcContract
+ EVM.Solidity: [solcContr] :: WarningData (t :: VMType) -> SolcContract
- EVM.Solidity: [sourceCache] :: WarningData (s :: VMType) t -> SourceCache
+ EVM.Solidity: [sourceCache] :: WarningData (t :: VMType) -> SourceCache
- EVM.Solidity: [vm] :: WarningData (s :: VMType) t -> VM s t
+ EVM.Solidity: [vm] :: WarningData (t :: VMType) -> VM t
- EVM.Solidity: data WarningData (s :: VMType) t
+ EVM.Solidity: data WarningData (t :: VMType)
- EVM.Stepper: [EVM] :: forall (t :: VMType) s a. EVM t s a -> Action t s a
+ EVM.Stepper: [EVM] :: forall (t :: VMType) a. EVM t a -> Action t a
- EVM.Stepper: [Exec] :: forall (t :: VMType) s. Action t s (VMResult t s)
+ EVM.Stepper: [Exec] :: forall (t :: VMType). Action t (VMResult t)
- EVM.Stepper: [Fork] :: forall s. RunBoth s -> Action 'Symbolic s ()
+ EVM.Stepper: [Fork] :: BranchContext -> Action 'Symbolic ()
- EVM.Stepper: [Wait] :: forall (t :: VMType) s. Query t s -> Action t s ()
+ EVM.Stepper: [Wait] :: forall (t :: VMType). Query t -> Action t ()
- EVM.Stepper: data Action (t :: VMType) s a
+ EVM.Stepper: data Action (t :: VMType) a
- EVM.Stepper: enter :: forall (t :: VMType) s. Text -> Stepper t s ()
+ EVM.Stepper: enter :: forall (t :: VMType). Text -> Stepper t ()
- EVM.Stepper: evm :: forall (t :: VMType) s a. EVM t s a -> Stepper t s a
+ EVM.Stepper: evm :: forall (t :: VMType) a. EVM t a -> Stepper t a
- EVM.Stepper: exec :: forall (t :: VMType) s. Stepper t s (VMResult t s)
+ EVM.Stepper: exec :: forall (t :: VMType). Stepper t (VMResult t)
- EVM.Stepper: execFully :: Stepper 'Concrete s (Either EvmError (Expr 'Buf))
+ EVM.Stepper: execFully :: Stepper 'Concrete (Either EvmError (Expr 'Buf))
- EVM.Stepper: fork :: RunBoth s -> Stepper 'Symbolic s ()
+ EVM.Stepper: fork :: BranchContext -> Stepper 'Symbolic ()
- EVM.Stepper: interpret :: App m => Fetcher 'Concrete m RealWorld -> VM 'Concrete RealWorld -> Stepper 'Concrete RealWorld a -> m a
+ EVM.Stepper: interpret :: App m => Fetcher 'Concrete m -> VM 'Concrete -> Stepper 'Concrete a -> m a
- EVM.Stepper: run :: forall (t :: VMType) s. Stepper t s (VM t s)
+ EVM.Stepper: run :: forall (t :: VMType). Stepper t (VM t)
- EVM.Stepper: runFully :: forall (t :: VMType) s. Stepper t s (VM t s)
+ EVM.Stepper: runFully :: forall (t :: VMType). Stepper t (VM t)
- EVM.Stepper: type Stepper (t :: VMType) s a = Program Action t s a
+ EVM.Stepper: type Stepper (t :: VMType) a = Program Action t a
- EVM.Stepper: wait :: forall (t :: VMType) s. Query t s -> Stepper t s ()
+ EVM.Stepper: wait :: forall (t :: VMType). Query t -> Stepper t ()
- EVM.SymExec: [iterConf] :: VeriOpts -> IterConfig
+ EVM.SymExec: [iterConf] :: InterpTask (m :: Type -> Type) a -> IterConfig
- EVM.SymExec: abstractVM :: (Expr 'Buf, [Prop]) -> ByteString -> Maybe (Precondition s) -> Bool -> ST s (VM 'Symbolic s)
+ EVM.SymExec: abstractVM :: (Expr 'Buf, [Prop]) -> ByteString -> Maybe Precondition -> Bool -> ST RealWorld (VM 'Symbolic)
- EVM.SymExec: askSmtItersReached :: VM 'Symbolic s -> Integer -> Bool
+ EVM.SymExec: askSmtItersReached :: VM 'Symbolic -> Integer -> Bool
- EVM.SymExec: checkAssert :: App m => SolverGroup -> [Word256] -> ByteString -> Maybe Sig -> [String] -> VeriOpts -> m (Expr 'End, [VerifyResult])
+ EVM.SymExec: checkAssert :: App m => SolverGroup -> [Word256] -> ByteString -> Maybe Sig -> [String] -> VeriOpts -> m ([Expr 'End], [VerifyResult])
- EVM.SymExec: checkAssertions :: [Word256] -> Postcondition s
+ EVM.SymExec: checkAssertions :: [Word256] -> Postcondition
- EVM.SymExec: equivalenceCheck :: App m => SolverGroup -> ByteString -> ByteString -> VeriOpts -> (Expr 'Buf, [Prop]) -> Bool -> m EqIssues
+ EVM.SymExec: equivalenceCheck :: App m => SolverGroup -> Maybe Session -> ByteString -> ByteString -> VeriOpts -> (Expr 'Buf, [Prop]) -> Bool -> m EqIssues
- EVM.SymExec: equivalenceCheck' :: App m => SolverGroup -> [Expr 'End] -> [Expr 'End] -> Bool -> m EqIssues
+ EVM.SymExec: equivalenceCheck' :: App m => SolverGroup -> Maybe Session -> [Expr 'End] -> [Expr 'End] -> Bool -> m EqIssues
- EVM.SymExec: expandCex :: VM 'Symbolic s -> SMTCex -> SMTCex
+ EVM.SymExec: expandCex :: VM 'Symbolic -> SMTCex -> SMTCex
- EVM.SymExec: freezeVM :: VM 'Symbolic RealWorld -> ST RealWorld (VM 'Symbolic RealWorld)
+ EVM.SymExec: freezeVM :: VM 'Symbolic -> ST RealWorld (VM 'Symbolic)
- EVM.SymExec: getExpr :: App m => SolverGroup -> ByteString -> Maybe Sig -> [String] -> VeriOpts -> m (Expr 'End)
+ EVM.SymExec: getExpr :: App m => SolverGroup -> ByteString -> Maybe Sig -> [String] -> VeriOpts -> m [Expr 'End]
- EVM.SymExec: getExprEmptyStore :: App m => SolverGroup -> ByteString -> Maybe Sig -> [String] -> VeriOpts -> m (Expr 'End)
+ EVM.SymExec: getExprEmptyStore :: App m => SolverGroup -> ByteString -> Maybe Sig -> [String] -> VeriOpts -> m [Expr 'End]
- EVM.SymExec: groupPartials :: forall (s :: VMType) t. Maybe (WarningData s t) -> [Expr 'End] -> [(Integer, String)]
+ EVM.SymExec: groupPartials :: forall (t :: VMType). Maybe (WarningData t) -> [Expr 'End] -> [(Integer, String)]
- EVM.SymExec: interpret :: App m => Fetcher 'Symbolic m RealWorld -> IterConfig -> VM 'Symbolic RealWorld -> Stepper 'Symbolic RealWorld (Expr 'End) -> m (Expr 'End)
+ EVM.SymExec: interpret :: App m => Fetcher 'Symbolic m -> IterConfig -> VM 'Symbolic -> Stepper 'Symbolic (Expr 'End) -> (Expr 'End -> m a) -> m [a]
- EVM.SymExec: isLoopHead :: LoopHeuristic -> VM 'Symbolic s -> Maybe Bool
+ EVM.SymExec: isLoopHead :: LoopHeuristic -> VM 'Symbolic -> Maybe Bool
- EVM.SymExec: loadEmptySymVM :: ContractCode -> Expr 'EWord -> (Expr 'Buf, [Prop]) -> ST s (VM 'Symbolic s)
+ EVM.SymExec: loadEmptySymVM :: ContractCode -> Expr 'EWord -> (Expr 'Buf, [Prop]) -> ST RealWorld (VM 'Symbolic)
- EVM.SymExec: loadSymVM :: ContractCode -> Expr 'EWord -> (Expr 'Buf, [Prop]) -> Bool -> ST s (VM 'Symbolic s)
+ EVM.SymExec: loadSymVM :: ContractCode -> Expr 'EWord -> (Expr 'Buf, [Prop]) -> Bool -> ST RealWorld (VM 'Symbolic)
- EVM.SymExec: maxIterationsReached :: VM 'Symbolic s -> Maybe Integer -> Maybe Bool
+ EVM.SymExec: maxIterationsReached :: VM 'Symbolic -> Maybe Integer -> Maybe Bool
- EVM.SymExec: produceModels :: App m => SolverGroup -> Expr 'End -> m [(Expr 'End, SMTResult)]
+ EVM.SymExec: produceModels :: App m => SolverGroup -> [Expr 'End] -> m [(Expr 'End, SMTResult)]
- EVM.SymExec: reachable :: App m => SolverGroup -> Expr 'End -> m (Expr 'End)
+ EVM.SymExec: reachable :: App m => SolverGroup -> [Expr 'End] -> m [Expr 'End]
- EVM.SymExec: runExpr :: Stepper 'Symbolic RealWorld (Expr 'End)
+ EVM.SymExec: runExpr :: Stepper 'Symbolic (Expr 'End)
- EVM.SymExec: type Postcondition s = VM 'Symbolic s -> Expr 'End -> Prop
+ EVM.SymExec: type Postcondition = VM 'Symbolic -> Expr 'End -> Prop
- EVM.SymExec: type Precondition s = VM 'Symbolic s -> Prop
+ EVM.SymExec: type Precondition = VM 'Symbolic -> Prop
- EVM.SymExec: verify :: App m => SolverGroup -> Fetcher 'Symbolic m RealWorld -> VeriOpts -> VM 'Symbolic RealWorld -> Maybe (Postcondition RealWorld) -> m (Expr 'End, [VerifyResult])
+ EVM.SymExec: verify :: App m => SolverGroup -> Fetcher 'Symbolic m -> VeriOpts -> VM 'Symbolic -> Postcondition -> Maybe (VM 'Symbolic -> SMTResult -> Expr 'End -> m ()) -> m ([Expr 'End], [VerifyResult])
- EVM.SymExec: verifyContract :: App m => SolverGroup -> ByteString -> Maybe Sig -> [String] -> VeriOpts -> Maybe (Precondition RealWorld) -> Maybe (Postcondition RealWorld) -> m (Expr 'End, [VerifyResult])
+ EVM.SymExec: verifyContract :: App m => SolverGroup -> ByteString -> Maybe Sig -> [String] -> VeriOpts -> Maybe Precondition -> Postcondition -> m ([Expr 'End], [VerifyResult])
- EVM.Tracing: execWithTrace :: forall (m :: Type -> Type). App m => StateT (TraceState RealWorld) m (VMResult 'Concrete RealWorld)
+ EVM.Tracing: execWithTrace :: forall (m :: Type -> Type). App m => StateT TraceState m (VMResult 'Concrete)
- EVM.Tracing: interpretWithTrace :: App m => Fetcher 'Concrete m RealWorld -> Stepper 'Concrete RealWorld a -> StateT (TraceState RealWorld) m a
+ EVM.Tracing: interpretWithTrace :: App m => Fetcher 'Concrete m -> Stepper 'Concrete a -> StateT TraceState m a
- EVM.Tracing: vmTraceStep :: VM 'Concrete s -> VMTraceStep
+ EVM.Tracing: vmTraceStep :: VM 'Concrete -> VMTraceStep
- EVM.Transaction: initTx :: forall (t :: VMType) s. VM t s -> VM t s
+ EVM.Transaction: initTx :: forall (t :: VMType). VM t -> VM t
- EVM.Types: ConcreteMemory :: MutableMemory s -> Memory s
+ EVM.Types: ConcreteMemory :: MutableMemory -> Memory
- EVM.Types: Frame :: FrameContext -> FrameState t s -> Frame (t :: VMType) s
+ EVM.Types: Frame :: FrameContext -> FrameState t -> Frame (t :: VMType)
- EVM.Types: FrameState :: Expr 'EAddr -> Expr 'EAddr -> ContractCode -> {-# UNPACK #-} !Int -> [Expr 'EWord] -> Memory s -> Word64 -> Expr 'Buf -> Expr 'EWord -> Expr 'EAddr -> !Gas t -> Expr 'Buf -> Bool -> Maybe (Expr 'EAddr) -> Bool -> FrameState (t :: VMType) s
+ EVM.Types: FrameState :: Expr 'EAddr -> Expr 'EAddr -> ContractCode -> {-# UNPACK #-} !Int -> [Expr 'EWord] -> Memory -> Word64 -> Expr 'Buf -> Expr 'EWord -> Expr 'EAddr -> !Gas t -> Expr 'Buf -> Bool -> Maybe (Expr 'EAddr) -> Bool -> FrameState (t :: VMType)
- EVM.Types: SymbolicMemory :: !Expr 'Buf -> Memory s
+ EVM.Types: SymbolicMemory :: !Expr 'Buf -> Memory
- EVM.Types: VM :: Maybe (VMResult t s) -> FrameState t s -> [Frame t s] -> Env -> Block -> TxState -> [Expr 'Log] -> TreePos Empty Trace -> PathsVisited -> !Gas t -> Map CodeLocation (Int, [Expr 'EWord]) -> [Prop] -> RuntimeConfig -> Seq ForkState -> Int -> Map Addr Text -> Map String String -> Int -> Int -> Set (ByteString, W256) -> VM (t :: VMType) s
+ EVM.Types: VM :: Maybe (VMResult t) -> FrameState t -> [Frame t] -> Env -> Block -> TxState -> [Expr 'Log] -> TreePos Empty Trace -> PathsVisited -> !Gas t -> Map CodeLocation (Int, [Expr 'EWord]) -> [Prop] -> RuntimeConfig -> Seq ForkState -> Int -> Map Addr Text -> Map String String -> Int -> Int -> Set (ByteString, W256) -> VM (t :: VMType)
- EVM.Types: [HandleEffect] :: forall (t :: VMType) s. Effect t s -> VMResult t s
+ EVM.Types: [HandleEffect] :: forall (t :: VMType). Effect t -> VMResult t
- EVM.Types: [PleaseAskSMT] :: forall s. Expr 'EWord -> [Prop] -> (BranchCondition -> EVM 'Symbolic s ()) -> Query 'Symbolic s
+ EVM.Types: [PleaseAskSMT] :: Expr 'EWord -> [Prop] -> (BranchCondition -> EVM 'Symbolic ()) -> Query 'Symbolic
- EVM.Types: [PleaseDoFFI] :: forall (t :: VMType) s. [String] -> Map String String -> (ByteString -> EVM t s ()) -> Query t s
+ EVM.Types: [PleaseDoFFI] :: forall (t :: VMType). [String] -> Map String String -> (ByteString -> EVM t ()) -> Query t
- EVM.Types: [PleaseFetchContract] :: forall (t :: VMType) s. Addr -> BaseState -> (Contract -> EVM t s ()) -> Query t s
+ EVM.Types: [PleaseFetchContract] :: forall (t :: VMType). Addr -> BaseState -> (Contract -> EVM t ()) -> Query t
- EVM.Types: [PleaseFetchSlot] :: forall (t :: VMType) s. Addr -> W256 -> (W256 -> EVM t s ()) -> Query t s
+ EVM.Types: [PleaseFetchSlot] :: forall (t :: VMType). Addr -> W256 -> (W256 -> EVM t ()) -> Query t
- EVM.Types: [PleaseGetSols] :: forall s. Expr 'EWord -> Int -> [Prop] -> (Maybe [W256] -> EVM 'Symbolic s ()) -> Query 'Symbolic s
+ EVM.Types: [PleaseGetSols] :: Expr 'EWord -> Int -> [Prop] -> (Maybe [W256] -> EVM 'Symbolic ()) -> Query 'Symbolic
- EVM.Types: [PleaseReadEnv] :: forall (t :: VMType) s. String -> (String -> EVM t s ()) -> Query t s
+ EVM.Types: [PleaseReadEnv] :: forall (t :: VMType). String -> (String -> EVM t ()) -> Query t
- EVM.Types: [PleaseRunAll] :: forall s. Expr 'EWord -> [Expr 'EWord] -> (Expr 'EWord -> EVM 'Symbolic s ()) -> RunAll s
+ EVM.Types: [PleaseRunAll] :: [Expr 'EWord] -> (Expr 'EWord -> EVM 'Symbolic ()) -> BranchContext
- EVM.Types: [PleaseRunBoth] :: forall s. Expr 'EWord -> (Bool -> EVM 'Symbolic s ()) -> RunBoth s
+ EVM.Types: [PleaseRunBoth] :: (Bool -> EVM 'Symbolic ()) -> BranchContext
- EVM.Types: [Query] :: forall (t :: VMType) s. Query t s -> Effect t s
+ EVM.Types: [Query] :: forall (t :: VMType). Query t -> Effect t
- EVM.Types: [Unfinished] :: forall s. PartialExec -> VMResult 'Symbolic s
+ EVM.Types: [Unfinished] :: PartialExec -> VMResult 'Symbolic
- EVM.Types: [VMFailure] :: forall (t :: VMType) s. EvmError -> VMResult t s
+ EVM.Types: [VMFailure] :: forall (t :: VMType). EvmError -> VMResult t
- EVM.Types: [VMSuccess] :: forall (t :: VMType) s. Expr 'Buf -> VMResult t s
+ EVM.Types: [VMSuccess] :: forall (t :: VMType). Expr 'Buf -> VMResult t
- EVM.Types: [burned] :: VM (t :: VMType) s -> !Gas t
+ EVM.Types: [burned] :: VM (t :: VMType) -> !Gas t
- EVM.Types: [callvalue] :: FrameState (t :: VMType) s -> Expr 'EWord
+ EVM.Types: [callvalue] :: FrameState (t :: VMType) -> Expr 'EWord
- EVM.Types: [codeContract] :: FrameState (t :: VMType) s -> Expr 'EAddr
+ EVM.Types: [codeContract] :: FrameState (t :: VMType) -> Expr 'EAddr
- EVM.Types: [config] :: VM (t :: VMType) s -> RuntimeConfig
+ EVM.Types: [config] :: VM (t :: VMType) -> RuntimeConfig
- EVM.Types: [constraints] :: VM (t :: VMType) s -> [Prop]
+ EVM.Types: [constraints] :: VM (t :: VMType) -> [Prop]
- EVM.Types: [currentFork] :: VM (t :: VMType) s -> Int
+ EVM.Types: [currentFork] :: VM (t :: VMType) -> Int
- EVM.Types: [exploreDepth] :: VM (t :: VMType) s -> Int
+ EVM.Types: [exploreDepth] :: VM (t :: VMType) -> Int
- EVM.Types: [forks] :: VM (t :: VMType) s -> Seq ForkState
+ EVM.Types: [forks] :: VM (t :: VMType) -> Seq ForkState
- EVM.Types: [frames] :: VM (t :: VMType) s -> [Frame t s]
+ EVM.Types: [frames] :: VM (t :: VMType) -> [Frame t]
- EVM.Types: [freshVar] :: VM (t :: VMType) s -> Int
+ EVM.Types: [freshVar] :: VM (t :: VMType) -> Int
- EVM.Types: [iterations] :: VM (t :: VMType) s -> Map CodeLocation (Int, [Expr 'EWord])
+ EVM.Types: [iterations] :: VM (t :: VMType) -> Map CodeLocation (Int, [Expr 'EWord])
- EVM.Types: [keccakPreImgs] :: VM (t :: VMType) s -> Set (ByteString, W256)
+ EVM.Types: [keccakPreImgs] :: VM (t :: VMType) -> Set (ByteString, W256)
- EVM.Types: [logs] :: VM (t :: VMType) s -> [Expr 'Log]
+ EVM.Types: [logs] :: VM (t :: VMType) -> [Expr 'Log]
- EVM.Types: [memorySize] :: FrameState (t :: VMType) s -> Word64
+ EVM.Types: [memorySize] :: FrameState (t :: VMType) -> Word64
- EVM.Types: [memory] :: FrameState (t :: VMType) s -> Memory s
+ EVM.Types: [memory] :: FrameState (t :: VMType) -> Memory
- EVM.Types: [osEnv] :: VM (t :: VMType) s -> Map String String
+ EVM.Types: [osEnv] :: VM (t :: VMType) -> Map String String
- EVM.Types: [overrideCaller] :: FrameState (t :: VMType) s -> Maybe (Expr 'EAddr)
+ EVM.Types: [overrideCaller] :: FrameState (t :: VMType) -> Maybe (Expr 'EAddr)
- EVM.Types: [pc] :: FrameState (t :: VMType) s -> {-# UNPACK #-} !Int
+ EVM.Types: [pc] :: FrameState (t :: VMType) -> {-# UNPACK #-} !Int
- EVM.Types: [resetCaller] :: FrameState (t :: VMType) s -> Bool
+ EVM.Types: [resetCaller] :: FrameState (t :: VMType) -> Bool
- EVM.Types: [result] :: VM (t :: VMType) s -> Maybe (VMResult t s)
+ EVM.Types: [result] :: VM (t :: VMType) -> Maybe (VMResult t)
- EVM.Types: [returndata] :: FrameState (t :: VMType) s -> Expr 'Buf
+ EVM.Types: [returndata] :: FrameState (t :: VMType) -> Expr 'Buf
- EVM.Types: [stack] :: FrameState (t :: VMType) s -> [Expr 'EWord]
+ EVM.Types: [stack] :: FrameState (t :: VMType) -> [Expr 'EWord]
- EVM.Types: [state] :: Frame (t :: VMType) s -> FrameState t s
+ EVM.Types: [state] :: Frame (t :: VMType) -> FrameState t
- EVM.Types: [static] :: FrameState (t :: VMType) s -> Bool
+ EVM.Types: [static] :: FrameState (t :: VMType) -> Bool
- EVM.Types: [tx] :: VM (t :: VMType) s -> TxState
+ EVM.Types: [tx] :: VM (t :: VMType) -> TxState
- EVM.Types: branch :: VMOps t => Maybe Int -> Expr 'EWord -> (Bool -> EVM t s ()) -> EVM t s ()
+ EVM.Types: branch :: VMOps t => Maybe Int -> Expr 'EWord -> (Bool -> EVM t ()) -> EVM t ()
- EVM.Types: burn' :: VMOps t => Gas t -> EVM t s () -> EVM t s ()
+ EVM.Types: burn' :: VMOps t => Gas t -> EVM t () -> EVM t ()
- EVM.Types: burnCalldatacopy :: VMOps t => Expr 'EWord -> EVM t s () -> EVM t s ()
+ EVM.Types: burnCalldatacopy :: VMOps t => Expr 'EWord -> EVM t () -> EVM t ()
- EVM.Types: burnCodecopy :: VMOps t => Expr 'EWord -> EVM t s () -> EVM t s ()
+ EVM.Types: burnCodecopy :: VMOps t => Expr 'EWord -> EVM t () -> EVM t ()
- EVM.Types: burnExp :: VMOps t => Expr 'EWord -> EVM t s () -> EVM t s ()
+ EVM.Types: burnExp :: VMOps t => Expr 'EWord -> EVM t () -> EVM t ()
- EVM.Types: burnExtcodecopy :: VMOps t => Expr 'EAddr -> Expr 'EWord -> EVM t s () -> EVM t s ()
+ EVM.Types: burnExtcodecopy :: VMOps t => Expr 'EAddr -> Expr 'EWord -> EVM t () -> EVM t ()
- EVM.Types: burnLog :: VMOps t => Expr 'EWord -> Word8 -> EVM t s () -> EVM t s ()
+ EVM.Types: burnLog :: VMOps t => Expr 'EWord -> Word8 -> EVM t () -> EVM t ()
- EVM.Types: burnReturndatacopy :: VMOps t => Expr 'EWord -> EVM t s () -> EVM t s ()
+ EVM.Types: burnReturndatacopy :: VMOps t => Expr 'EWord -> EVM t () -> EVM t ()
- EVM.Types: burnSha3 :: VMOps t => Expr 'EWord -> EVM t s () -> EVM t s ()
+ EVM.Types: burnSha3 :: VMOps t => Expr 'EWord -> EVM t () -> EVM t ()
- EVM.Types: costOfCall :: VMOps t => FeeSchedule Word64 -> Bool -> Expr 'EWord -> Gas t -> Gas t -> Expr 'EAddr -> (Word64 -> Word64 -> EVM t s ()) -> EVM t s ()
+ EVM.Types: costOfCall :: VMOps t => FeeSchedule Word64 -> Bool -> Expr 'EWord -> Gas t -> Gas t -> Expr 'EAddr -> (Word64 -> Word64 -> EVM t ()) -> EVM t ()
- EVM.Types: data Effect (t :: VMType) s
+ EVM.Types: data Effect (t :: VMType)
- EVM.Types: data Frame (t :: VMType) s
+ EVM.Types: data Frame (t :: VMType)
- EVM.Types: data FrameState (t :: VMType) s
+ EVM.Types: data FrameState (t :: VMType)
- EVM.Types: data Memory s
+ EVM.Types: data Memory
- EVM.Types: data Query (t :: VMType) s
+ EVM.Types: data Query (t :: VMType)
- EVM.Types: data VM (t :: VMType) s
+ EVM.Types: data VM (t :: VMType)
- EVM.Types: data VMResult (t :: VMType) s
+ EVM.Types: data VMResult (t :: VMType)
- EVM.Types: ensureGas :: VMOps t => Word64 -> EVM t s () -> EVM t s ()
+ EVM.Types: ensureGas :: VMOps t => Word64 -> EVM t () -> EVM t ()
- EVM.Types: manySolutions :: VMOps t => Maybe Int -> Expr 'EWord -> Int -> (Maybe W256 -> EVM t s ()) -> EVM t s ()
+ EVM.Types: manySolutions :: VMOps t => Maybe Int -> Expr 'EWord -> Int -> (Maybe W256 -> EVM t ()) -> EVM t ()
- EVM.Types: partial :: VMOps t => PartialExec -> EVM t s ()
+ EVM.Types: partial :: VMOps t => PartialExec -> EVM t ()
- EVM.Types: payRefunds :: VMOps t => EVM t s ()
+ EVM.Types: payRefunds :: VMOps t => EVM t ()
- EVM.Types: pushGas :: VMOps t => EVM t s ()
+ EVM.Types: pushGas :: VMOps t => EVM t ()
- EVM.Types: reclaimRemainingGasAllowance :: VMOps t => VM t s -> EVM t s ()
+ EVM.Types: reclaimRemainingGasAllowance :: VMOps t => VM t -> EVM t ()
- EVM.Types: type EVM (t :: VMType) s a = StateT VM t s ST s a
+ EVM.Types: type EVM (t :: VMType) a = StateT VM t ST RealWorld a
- EVM.Types: type MutableMemory s = STVector s Word8
+ EVM.Types: type MutableMemory = STVector RealWorld Word8
- EVM.Types: whenSymbolicElse :: VMOps t => EVM t s a -> EVM t s a -> EVM t s a
+ EVM.Types: whenSymbolicElse :: VMOps t => EVM t a -> EVM t a -> EVM t a
- EVM.UnitTest: UnitTestOptions :: RpcInfo -> SolverGroup -> Session -> Maybe Integer -> Integer -> Maybe Natural -> Text -> Text -> DappInfo -> TestVMParams -> Bool -> Bool -> LoopHeuristic -> UnitTestOptions (s :: k)
+ EVM.UnitTest: UnitTestOptions :: RpcInfo -> SolverGroup -> Session -> Maybe Integer -> Integer -> Maybe Natural -> Text -> Text -> DappInfo -> TestVMParams -> Bool -> Bool -> LoopHeuristic -> UnitTestOptions
- EVM.UnitTest: [askSmtIters] :: UnitTestOptions (s :: k) -> Integer
+ EVM.UnitTest: [askSmtIters] :: UnitTestOptions -> Integer
- EVM.UnitTest: [checkFailBit] :: UnitTestOptions (s :: k) -> Bool
+ EVM.UnitTest: [checkFailBit] :: UnitTestOptions -> Bool
- EVM.UnitTest: [dapp] :: UnitTestOptions (s :: k) -> DappInfo
+ EVM.UnitTest: [dapp] :: UnitTestOptions -> DappInfo
- EVM.UnitTest: [ffiAllowed] :: UnitTestOptions (s :: k) -> Bool
+ EVM.UnitTest: [ffiAllowed] :: UnitTestOptions -> Bool
- EVM.UnitTest: [loopHeuristic] :: UnitTestOptions (s :: k) -> LoopHeuristic
+ EVM.UnitTest: [loopHeuristic] :: UnitTestOptions -> LoopHeuristic
- EVM.UnitTest: [match] :: UnitTestOptions (s :: k) -> Text
+ EVM.UnitTest: [match] :: UnitTestOptions -> Text
- EVM.UnitTest: [maxIter] :: UnitTestOptions (s :: k) -> Maybe Integer
+ EVM.UnitTest: [maxIter] :: UnitTestOptions -> Maybe Integer
- EVM.UnitTest: [prefix] :: UnitTestOptions (s :: k) -> Text
+ EVM.UnitTest: [prefix] :: UnitTestOptions -> Text
- EVM.UnitTest: [rpcInfo] :: UnitTestOptions (s :: k) -> RpcInfo
+ EVM.UnitTest: [rpcInfo] :: UnitTestOptions -> RpcInfo
- EVM.UnitTest: [sess] :: UnitTestOptions (s :: k) -> Session
+ EVM.UnitTest: [sess] :: UnitTestOptions -> Session
- EVM.UnitTest: [smtTimeout] :: UnitTestOptions (s :: k) -> Maybe Natural
+ EVM.UnitTest: [smtTimeout] :: UnitTestOptions -> Maybe Natural
- EVM.UnitTest: [solvers] :: UnitTestOptions (s :: k) -> SolverGroup
+ EVM.UnitTest: [solvers] :: UnitTestOptions -> SolverGroup
- EVM.UnitTest: [testParams] :: UnitTestOptions (s :: k) -> TestVMParams
+ EVM.UnitTest: [testParams] :: UnitTestOptions -> TestVMParams
- EVM.UnitTest: abiCall :: forall (t :: VMType) s. VMOps t => TestVMParams -> Either (Text, AbiValue) ByteString -> EVM t s ()
+ EVM.UnitTest: abiCall :: forall (t :: VMType). VMOps t => TestVMParams -> Either (Text, AbiValue) ByteString -> EVM t ()
- EVM.UnitTest: data UnitTestOptions (s :: k)
+ EVM.UnitTest: data UnitTestOptions
- EVM.UnitTest: dsTestFailedSym :: forall (s :: VMType) t. Map (Expr 'EAddr) (Expr 'EContract) -> VM s t -> Prop
+ EVM.UnitTest: dsTestFailedSym :: forall (t :: VMType). Map (Expr 'EAddr) (Expr 'EContract) -> VM t -> Prop
- EVM.UnitTest: failOutput :: forall m (t :: VMType) s. App m => VM t s -> UnitTestOptions s -> Text -> m Text
+ EVM.UnitTest: failOutput :: forall m (t :: VMType). App m => VM t -> UnitTestOptions -> Text -> m Text
- EVM.UnitTest: initialUnitTestVm :: forall (t :: VMType) s. VMOps t => UnitTestOptions s -> SolcContract -> ST s (VM t s)
+ EVM.UnitTest: initialUnitTestVm :: forall (t :: VMType). VMOps t => UnitTestOptions -> SolcContract -> ST RealWorld (VM t)
- EVM.UnitTest: initializeUnitTest :: UnitTestOptions s -> SolcContract -> Stepper 'Concrete s ()
+ EVM.UnitTest: initializeUnitTest :: UnitTestOptions -> SolcContract -> Stepper 'Concrete ()
- EVM.UnitTest: makeTxCall :: forall (t :: VMType) s. VMOps t => TestVMParams -> (Expr 'Buf, [Prop]) -> EVM t s ()
+ EVM.UnitTest: makeTxCall :: forall (t :: VMType). VMOps t => TestVMParams -> (Expr 'Buf, [Prop]) -> EVM t ()
- EVM.UnitTest: makeVeriOpts :: forall {k} (s :: k). UnitTestOptions s -> VeriOpts
+ EVM.UnitTest: makeVeriOpts :: UnitTestOptions -> VeriOpts
- EVM.UnitTest: printWarnings :: forall (s :: VMType) t b a. Maybe (WarningData s t) -> GetUnknownStr b => [Expr 'End] -> [ProofResult a b] -> String -> IO ()
+ EVM.UnitTest: printWarnings :: forall (t :: VMType) b a. Maybe (WarningData t) -> GetUnknownStr b => [Expr 'End] -> [ProofResult a b] -> String -> IO ()
- EVM.UnitTest: runUnitTestContract :: App m => UnitTestOptions RealWorld -> BuildOutput -> (Text, [Sig]) -> m [(Bool, Bool)]
+ EVM.UnitTest: runUnitTestContract :: App m => UnitTestOptions -> BuildOutput -> (Text, [Sig]) -> m [(Bool, Bool)]
- EVM.UnitTest: symFailure :: App m => UnitTestOptions RealWorld -> Text -> Expr 'Buf -> [AbiType] -> [(Expr 'End, SMTCex, Err Bool)] -> m Text
+ EVM.UnitTest: symFailure :: App m => UnitTestOptions -> Text -> Expr 'Buf -> [AbiType] -> (Expr 'End, SMTCex, Err Bool) -> m Text
- EVM.UnitTest: symRun :: App m => UnitTestOptions RealWorld -> VM 'Concrete RealWorld -> Sig -> SolcContract -> SourceCache -> m (Bool, Bool)
+ EVM.UnitTest: symRun :: App m => UnitTestOptions -> VM 'Concrete -> Sig -> SolcContract -> SourceCache -> m (Bool, Bool)
- EVM.UnitTest: unitTest :: App m => UnitTestOptions RealWorld -> BuildOutput -> m (Bool, Bool)
+ EVM.UnitTest: unitTest :: App m => UnitTestOptions -> BuildOutput -> m (Bool, Bool)
- EVM.UnitTest: validateCex :: App m => UnitTestOptions RealWorld -> Fetcher 'Concrete m RealWorld -> VM 'Concrete RealWorld -> ReproducibleCex -> m Bool
+ EVM.UnitTest: validateCex :: App m => UnitTestOptions -> Fetcher 'Concrete m -> VM 'Concrete -> ReproducibleCex -> m Bool
- EVM.UnitTest: writeTrace :: forall m (t :: VMType). App m => VM t RealWorld -> m ()
+ EVM.UnitTest: writeTrace :: forall m (t :: VMType). App m => VM t -> m ()
- EVM.UnitTest: writeTraceDapp :: forall m (t :: VMType). App m => DappInfo -> VM t RealWorld -> m ()
+ EVM.UnitTest: writeTraceDapp :: forall m (t :: VMType). App m => DappInfo -> VM t -> m ()

Files

CHANGELOG.md view
@@ -5,6 +5,33 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.57.0] - 2026-01-08++## Added+- We support RPC in equivalence checking now+- Inequality propagation in constant propagation to prune impossible execution paths earlier.+  The constraint solver now tracks lower and upper bounds for symbolic values and detects+  conflicts (e.g., x < 5 && x > 10), significantly reducing the number of paths explored+- Encode symbolic power of 2 as bit-shift in SMT encoding.+- Limit the expansion of the EXP operation to avoid blow-up in the size of the SMT expressions.+- New EXP rewrite rule for base-2 exponents++## Fixed+- Fix incorrect simplification rule for `PEq (Lit 1) (IsZero (LT a b))`++## Changed+- Replaced RPC mocking by a full block cache support. This allows users to cache responses from an RPC+  node via `--cache-dir dir`.+- Changed `verify*` methods to always require postcodition.+- We now use a symbolic execution queue, so as not to run out of resources when there are+  too many branches to explore.+- Removed type parameter of mutable memory from VM definition.+- Removed simplification that were rewriting concrete bytes-to-be-overwritten+  with zero bytes. Benefits were unclear while it had negative effect on+  analysis' performance.+- We now use the symbolic execution queue to also run the SMT solver in `test` mode,+  and verify the results using a cexHandler+ ## [0.56.0] - 2025-10-13  ## Added
bench/bench-perf.hs view
@@ -24,7 +24,7 @@  -- benchmark hevm using tasty-bench -vmFromRawByteString :: App m => ByteString -> m (VM Concrete RealWorld)+vmFromRawByteString :: App m => ByteString -> m (VM Concrete) vmFromRawByteString bs = liftIO $   bs     & ConcreteRuntimeCode@@ -34,7 +34,7 @@     & stToIO     & fmap EVM.Transaction.initTx -vm0 :: Contract -> ST s (VM Concrete s)+vm0 :: Contract -> ST RealWorld (VM Concrete) vm0 c = makeVm $ vm0Opts c  vm0Opts :: Contract -> VMOpts Concrete
bench/bench.hs view
@@ -4,18 +4,14 @@ import Control.Monad import Control.Monad.IO.Unlift import Data.Maybe-import System.Environment (getEnv)  import qualified Paths_hevm as Paths  import Test.Tasty (localOption, withResource) import Test.Tasty.Bench import Data.ByteString (ByteString)-import System.FilePath.Posix import qualified Data.Map.Strict as Map import qualified Data.Text as T-import qualified System.FilePath.Find as Find-import qualified Data.ByteString.Lazy as LazyByteString  import EVM.SymExec import EVM.Solidity@@ -34,30 +30,12 @@   , mkbench (pure vat) "vat" 0 [4]   , mkbench (pure deposit) "deposit" 32 [4]   , mkbench (pure uniV2Pair) "uniV2" 10 [4]-  , withResource bcjsons (pure . const ()) blockchainTests+  , withResource BCTests.allTestCases (pure . const ()) blockchainTests   ]   --- General State Tests ---------------------------------------------------------------------------- ---- | loads and parses all blockchain test files--- We pull this out into a separate stage to ensure that we only benchmark the--- actual time spent executing tests, and not the IO & parsing overhead-bcjsons :: IO (Map.Map FilePath (Map.Map String BCTests.Case))-bcjsons = do-  repo <- getEnv "HEVM_ETHEREUM_TESTS_REPO"-  let testsDir = "BlockchainTests/GeneralStateTests"-      dir = repo </> testsDir-  jsons <- Find.find Find.always (Find.extension Find.==? ".json") dir-  Map.fromList <$> mapM parseSuite jsons-  where-    parseSuite path = do-      contents <- LazyByteString.readFile path-      case BCTests.parseBCSuite contents of-        Left _ -> pure (path, mempty)-        Right tests -> pure (path, tests)- -- | executes all provided bc tests in sequence and accumulates a boolean value representing their success. -- the accumulated value ensures that we actually have to execute all the tests as a part of this benchmark blockchainTests :: IO (Map.Map FilePath (Map.Map String BCTests.Case)) -> Benchmark@@ -65,7 +43,7 @@   tests <- ts   putStrLn "    executing blockchain tests"   let cases = concat . Map.elems . (fmap Map.toList) $ tests-      ignored = Map.keys BCTests.commonProblematicTests+      ignored = Map.keys BCTests.problematicTests   foldM (\acc (n, c) ->       if n `elem` ignored       then pure True@@ -81,9 +59,7 @@   vm0 <- liftIO $ BCTests.vmForCase x   result <- Stepper.interpret (Fetch.zero 0 Nothing) vm0 Stepper.runFully   writeTrace vm0--  maybeReason <- BCTests.checkExpectation x result-  pure $ isNothing maybeReason+  pure $ isNothing $ BCTests.checkExpectation x result   --- Helpers ----------------------------------------------------------------------------------------@@ -92,7 +68,7 @@ findPanics :: App m => Solver -> Natural -> Integer -> ByteString -> m () findPanics solver count iters c = do   _ <- withSolvers solver count 1 Nothing $ \s -> do-    let opts = defaultVeriOpts { iterConf = defaultIterConf {maxIter = Just iters, askSmtIters = iters + 1 }}+    let opts = (defaultVeriOpts :: VeriOpts) { iterConf = defaultIterConf {maxIter = Just iters, askSmtIters = iters + 1 }}     checkAssert s allPanicCodes c Nothing [] opts   liftIO $ putStrLn "done" 
cli/cli.hs view
@@ -9,10 +9,11 @@  import Control.Monad (when, forM_, unless) import Control.Monad.State.Strict (runStateT)-import Control.Monad.ST (RealWorld, stToIO)+import Control.Monad.ST (stToIO) import Control.Monad.IO.Unlift import Control.Exception (try, IOException) import Data.ByteString (ByteString)+import Control.Concurrent.MVar (readMVar) import qualified Data.ByteString.Lazy as BS import Data.ByteString.Builder (toLazyByteString) import qualified Data.ByteString.Char8 as BC@@ -24,6 +25,7 @@ import Data.Version (showVersion) import Data.Word (Word64) import GHC.Conc (getNumProcessors)+import GitHash import Numeric.Natural (Natural) import Optics.Core ((&), set) import Witch (unsafeInto)@@ -42,10 +44,9 @@ import EVM.Dapp (dappInfo, DappInfo, emptyDapp) import EVM.Expr qualified as Expr import EVM.Concrete qualified as Concrete-import GitHash import EVM.FeeSchedule (feeSchedule) import EVM.Fetch qualified as Fetch-import EVM.Format (hexByteString, strip0x, formatExpr)+import EVM.Format (hexByteString, strip0x, formatExpr, indent) import EVM.Solidity import EVM.Solvers import EVM.Stepper qualified@@ -99,6 +100,7 @@   , maxDepth      ::Maybe Int   , noSimplify    ::Bool   , onlyDeployed  ::Bool+  , cacheDir      ::Maybe String   }  commonOptions :: Parser CommonOptions@@ -127,6 +129,7 @@   <*> (optional $ option auto $ long "max-depth" <> help "Limit maximum depth of branching during exploration (default: unlimited)")   <*> (switch $ long "no-simplify" <> help "Don't perform simplification of expressions")   <*> (switch $ long "only-deployed" <> help "When trying to resolve unknown addresses, only use addresses of deployed contracts")+  <*> (optional $ strOption $ long "cache-dir" <> help "Directory to save and load RPC cache")  data CommonExecOptions = CommonExecOptions   { address       ::Maybe Addr@@ -188,7 +191,6 @@   , match         ::Maybe String   , prefix        ::String   , ffi           ::Bool-  , mockFile      ::Maybe String   }  testOptions :: Parser TestOptions@@ -200,9 +202,7 @@   <*> (optional $ strOption $ long "match" <> help "Test case filter - only run methods matching regex")   <*> (strOption $ long "prefix"  <> showDefault <> value "prove" <> help "Prefix for test cases to prove")   <*> (switch $ long "ffi" <> help "Allow the usage of the hevm.ffi() cheatcode (WARNING: this allows test authors to execute arbitrary code on your machine)")-  <*> (optional $ strOption $ long "mock-file" <> help "Read mocked RPC response data from JSON file") - data EqOptions = EqOptions   { codeA         ::Maybe ByteString   , codeB         ::Maybe ByteString@@ -340,6 +340,9 @@             -- TODO: which functions here actually require a BuildOutput, and which can take it as a Maybe?             unitTestOpts <- unitTestOptions testOpts cOpts solvers (Just out)             res <- unitTest unitTestOpts out+            liftIO $ forM_ ((,) <$> cOpts.cacheDir <*> testOpts.number) $ \(dir, fetchedBlock) -> do+              cache <- readMVar (unitTestOpts.sess.sharedCache)+              Fetch.saveCache dir fetchedBlock cache             liftIO $ unless (uncurry (&&) res) exitFailure     Exec cFileOpts execOpts cExecOpts cOpts-> do       env <- makeEnv cOpts@@ -402,19 +405,19 @@   when (isNothing bytecodeB) $ liftIO $ do     putStrLn "Error: invalid or no bytecode for program B. Provide a valid one with --code-b or --code-b-file"     exitFailure-  let veriOpts = VeriOpts { iterConf = IterConfig {+  let veriOpts = (defaultVeriOpts :: VeriOpts) { iterConf = IterConfig {                             maxIter = parseMaxIters cOpts.maxIterations                             , askSmtIters = cOpts.askSmtIterations                             , loopHeuristic = cOpts.loopDetectionHeuristic                             }-                          , rpcInfo = mempty                           }   calldata <- buildCalldata cOpts eqOpts.sig eqOpts.arg   solver <- liftIO $ getSolver cOpts.solver   cores <- liftIO $ unsafeInto <$> getNumProcessors   let solverCount = fromMaybe cores cOpts.numSolvers   withSolvers solver solverCount cOpts.solverThreads (Just cOpts.smttimeout) $ \s -> do-    eq <- equivalenceCheck s (fromJust bytecodeA) (fromJust bytecodeB) veriOpts calldata eqOpts.create+    sess <- Fetch.mkSession cOpts.cacheDir Nothing+    eq <- equivalenceCheck s (Just sess) (fromJust bytecodeA) (fromJust bytecodeB) veriOpts calldata eqOpts.create     let anyIssues =  not (null eq.partials) || any (isUnknown . fst) eq.res  || any (isError . fst) eq.res     liftIO $ case (any (isCex . fst) eq.res, anyIssues) of       (False, False) -> putStrLn "   \x1b[32m[PASS]\x1b[0m Contracts behave equivalently"@@ -496,7 +499,7 @@ symbCheck cFileOpts sOpts cExecOpts cOpts = do   let block' = maybe Fetch.Latest Fetch.BlockNumber cExecOpts.block       blockUrlInfo = (,) block' <$> cExecOpts.rpc-  sess <- Fetch.mkSession+  sess <- Fetch.mkSession cOpts.cacheDir cExecOpts.block   calldata <- buildCalldata cOpts sOpts.sig sOpts.arg   preState <- symvmFromCommand cExecOpts sOpts cFileOpts sess calldata   errCodes <- case sOpts.assertions of@@ -516,12 +519,15 @@                               , askSmtIters = cOpts.askSmtIterations                               , loopHeuristic = cOpts.loopDetectionHeuristic                               }-                            , rpcInfo = mempty {Fetch.blockNumURL = blockUrlInfo}+                            , rpcInfo = Fetch.RpcInfo blockUrlInfo                             }     let fetcher = Fetch.oracle solvers (Just sess) veriOpts.rpcInfo-    (expr, res) <- verify solvers fetcher veriOpts preState (Just $ checkAssertions errCodes)+    (expr, res) <- verify solvers fetcher veriOpts preState (checkAssertions errCodes) Nothing+    liftIO $ forM_ ((,) <$> cOpts.cacheDir <*> cExecOpts.block) $ \(dir, block) -> do+      cache <- readMVar sess.sharedCache+      Fetch.saveCache dir block cache     case res of-      [Qed] -> do+      [] -> do         liftIO $ putStrLn "\nQED: No reachable property violations discovered\n"         showExtras solvers sOpts calldata expr       _ -> do@@ -534,26 +540,29 @@                  , ""                  ] <> fmap (formatCex (fst calldata) Nothing) cexs         liftIO $ T.putStrLn $ T.unlines counterexamples-        liftIO $ printWarnings Nothing [expr] res "symbolically"+        liftIO $ printWarnings Nothing expr res "symbolically"         showExtras solvers sOpts calldata expr         liftIO exitFailure -showExtras :: App m => SolverGroup ->SymbolicOptions -> (Expr Buf, [Prop]) -> Expr End -> m ()+showExtras :: App m => SolverGroup ->SymbolicOptions -> (Expr Buf, [Prop]) -> [Expr End] -> m () showExtras solvers sOpts calldata expr = do   when sOpts.showTree $ liftIO $ do-    putStrLn "=== Expression ===\n"-    T.putStrLn $ formatExpr $ Expr.simplify expr+    putStrLn "=== Leafs ===\n"+    printLeafs $ map (formatExpr . Expr.simplify) expr     putStrLn ""   when sOpts.showReachableTree $ do     reached <- reachable solvers expr     liftIO $ do-      putStrLn "=== Potentially Reachable Expression ===\n"-      T.putStrLn (formatExpr . Expr.simplify $ reached)+      putStrLn "=== Potentially Reachable Leafs ===\n"+      printLeafs $ map (formatExpr . Expr.simplify) reached       putStrLn ""   when sOpts.getModels $ do-    liftIO $ putStrLn $ "=== Models for " <> show (Expr.numBranches expr) <> " branches ==="+    liftIO $ putStrLn $ "=== Models for " <> show (length expr) <> " branches ==="     ms <- produceModels solvers expr     liftIO $ forM_ ms (showModel (fst calldata))+  where+    printLeafs leafs =+      T.putStrLn $ indent 2 $ T.unlines $ zipWith (\i r -> "Leaf " <> T.pack (show (i :: Integer)) <> ":\n" <> r) [0..] leafs  isTestOrLib :: Text -> Bool isTestOrLib file = T.isSuffixOf ".t.sol" file || areAnyPrefixOf ["src/test/", "src/tests/", "lib/"] file@@ -564,12 +573,12 @@ launchExec :: App m => CommonFileOptions -> ExecOptions -> CommonExecOptions -> CommonOptions -> m () launchExec cFileOpts execOpts cExecOpts cOpts = do   dapp <- getSrcInfo execOpts cOpts-  sess <- Fetch.mkSession+  sess <- Fetch.mkSession cOpts.cacheDir cExecOpts.block   vm <- vmFromCommand cOpts cExecOpts cFileOpts execOpts sess   let     block = maybe Fetch.Latest Fetch.BlockNumber cExecOpts.block     blockUrlInfo = (,) block <$> cExecOpts.rpc-    rpcDat :: Fetch.RpcInfo = mempty { Fetch.blockNumURL = blockUrlInfo }+    rpcDat :: Fetch.RpcInfo = Fetch.RpcInfo blockUrlInfo    -- TODO: we shouldn't need solvers to execute this code   withSolvers Z3 0 1 Nothing $ \solvers -> do@@ -590,6 +599,9 @@              pure vm'            else EVM.Stepper.interpret fetcher vm EVM.Stepper.runFully     writeTraceDapp dapp vm'+    liftIO $ forM_ ((,) <$> cOpts.cacheDir <*> cExecOpts.block) $ \(dir, fetchedBlock) -> do+      cache <- readMVar sess.sharedCache+      Fetch.saveCache dir fetchedBlock cache     case vm'.result of       Just (VMFailure (Revert msg)) -> liftIO $ do         let res = case msg of@@ -609,7 +621,7 @@         internalError "no EVM result"  -- | Creates a (concrete) VM from command line options-vmFromCommand :: App m => CommonOptions -> CommonExecOptions -> CommonFileOptions -> ExecOptions -> Fetch.Session -> m (VM Concrete RealWorld)+vmFromCommand :: App m => CommonOptions -> CommonExecOptions -> CommonFileOptions -> ExecOptions -> Fetch.Session -> m (VM Concrete) vmFromCommand cOpts cExecOpts cFileOpts execOpts sess = do   conf <- readConfig   (miner,ts,baseFee,blockNum,prevRan) <- case cExecOpts.rpc of@@ -634,23 +646,28 @@         exitFailure       else         Fetch.fetchContractWithSession conf sess block url addr' >>= \case-          Nothing -> do+          Fetch.FetchFailure _ -> do             putStrLn $ "Error: contract not found: " <> show address             exitFailure-          Just contract ->+          Fetch.FetchError e -> do+            putStrLn $ "Error: RPC failure: " <> show e+            exitFailure+          Fetch.FetchSuccess rpcContract _ ->             -- if both code and url is given,             -- fetch the contract and overwrite the code-            pure $ initialContract (mkCode $ fromJust code)-                & set #balance  (contract.balance)-                & set #nonce    (contract.nonce)-                & set #external (contract.external)+              pure $ initialContract (mkCode $ fromJust code)+                & set #balance  (Lit rpcContract.balance)+                & set #nonce    (Just rpcContract.nonce)      (Just url, Just addr', Nothing) ->       liftIO $ Fetch.fetchContractWithSession conf sess block url addr' >>= \case-        Nothing -> do+        Fetch.FetchFailure _ -> do           putStrLn $ "Error, contract not found: " <> show address           exitFailure-        Just contract -> pure contract+        Fetch.FetchError e -> do+          putStrLn $ "Error: RPC failure: " <> show e+          exitFailure+        Fetch.FetchSuccess rpcContract _ -> pure $ Fetch.makeContractFromRPC rpcContract      (_, _, Just c)  -> do       let code = hexByteString $ strip0x c@@ -723,7 +740,7 @@  symvmFromCommand :: App m =>   CommonExecOptions -> SymbolicOptions -> CommonFileOptions -> Fetch.Session ->-  (Expr Buf, [Prop]) -> m (VM EVM.Types.Symbolic RealWorld)+  (Expr Buf, [Prop]) -> m (VM EVM.Types.Symbolic) symvmFromCommand cExecOpts sOpts cFileOpts sess calldata = do   conf <- readConfig   (miner,blockNum,baseFee,prevRan) <- case cExecOpts.rpc of@@ -748,11 +765,14 @@   contract <- case (cExecOpts.rpc, cExecOpts.address, codeWrapped) of     (Just url, Just addr', _) ->       liftIO $ Fetch.fetchContractWithSession conf sess block url addr' >>= \case-        Nothing -> do+        Fetch.FetchFailure _ -> do           putStrLn "Error, contract not found."           exitFailure-        Just contract' -> case codeWrapped of-              Nothing -> pure contract'+        Fetch.FetchError e -> do+          putStrLn $ "Error: RPC failure: " <> show e+          exitFailure+        Fetch.FetchSuccess rpcContract' _ -> case codeWrapped of+              Nothing -> pure $ Fetch.makeContractFromRPC rpcContract'               -- if both code and url is given,               -- fetch the contract and overwrite the code               Just c -> do@@ -762,10 +782,8 @@                   exitFailure                 else pure $ do                   initialContract (mkCode $ fromJust c')-                        & set #origStorage (contract'.origStorage)-                        & set #balance     (contract'.balance)-                        & set #nonce       (contract'.nonce)-                        & set #external    (contract'.external)+                        & set #balance (Lit rpcContract'.balance)+                        & set #nonce (Just rpcContract'.nonce)      (_, _, Just c) -> liftIO $ do       let c' = decipher c@@ -825,25 +843,17 @@     word64 f def = fromMaybe def (f cExecOpts)     eaddr f def = maybe def LitAddr (f cExecOpts) -unitTestOptions :: App m => TestOptions -> CommonOptions -> SolverGroup -> Maybe BuildOutput -> m (UnitTestOptions RealWorld)+unitTestOptions :: App m => TestOptions -> CommonOptions -> SolverGroup -> Maybe BuildOutput -> m (UnitTestOptions) unitTestOptions testOpts cOpts solvers buildOutput = do   root <- liftIO $ getRoot cOpts-  mockData <- if isJust testOpts.mockFile then liftIO $ do-      ret <- Fetch.readMockData (fromJust testOpts.mockFile)-      case ret of-        Left err -> do-          putStrLn $ "Error reading mock file: " <> err-          exitFailure-        Right md -> pure md-    else pure mempty    let srcInfo = maybe emptyDapp (dappInfo root) buildOutput   let blockUrlInfo = case (testOpts.number, testOpts.rpc) of           (Just block, Just url) -> Just (Fetch.BlockNumber block, url)           (Nothing, Just url) -> Just (Fetch.Latest, url)           _ -> Nothing-      rpcDat = Fetch.mkRpcInfo blockUrlInfo mockData-  sess <- Fetch.mkSession+      rpcDat = Fetch.RpcInfo blockUrlInfo+  sess <- Fetch.mkSession cOpts.cacheDir testOpts.number   params <- paramsFromRpc rpcDat sess   let testn = params.number       block' = if 0 == testn
hevm.cabal view
@@ -2,7 +2,7 @@ name:   hevm version:-  0.56.0+  0.57.0 synopsis:   Symbolic EVM Evaluator description:@@ -143,6 +143,7 @@   install-includes:     ethjet/tinykeccak.h, ethjet/ethjet.h, ethjet/ethjet-ff.h, ethjet/blake2.h   build-depends:+    directory                         >= 1.3.6 && < 1.4,     system-cxx-std-lib                >= 1.0 && < 2.0,     QuickCheck                        >= 2.13.2 && < 2.16,     Decimal                           >= 0.5.1 && < 0.6,@@ -187,6 +188,7 @@     template-haskell                  >= 2.19.0 && < 3,     extra                             >= 1.7.14 && < 2,     aeson-pretty                      >= 0.8.8 && < 0.9.0,+    monad-loops                       >= 0.4.1 && < 0.5,   hs-source-dirs:     src @@ -359,8 +361,6 @@     text,     hevm,     test-utils,-    filemanip,-    filepath,     containers,     unliftio-core 
src/EVM.hs view
@@ -26,7 +26,7 @@ import EVM.Effects (Config (..))  import Control.Monad (unless, when)-import Control.Monad.ST (ST)+import Control.Monad.ST (ST, RealWorld) import Control.Monad.State.Strict (MonadState, State, get, gets, lift, modify', put) import Data.Bits (FiniteBits, countLeadingZeros, finiteBitSize) import Data.ByteArray qualified as BA@@ -66,7 +66,7 @@ import Crypto.Hash qualified as Crypto import Crypto.Number.ModArithmetic (expFast) -blankState :: VMOps t => ST s (FrameState t s)+blankState :: VMOps t => ST RealWorld (FrameState t) blankState = do   memory <- ConcreteMemory <$> VS.Mutable.new 0   pure $ FrameState@@ -98,13 +98,13 @@  -- * Data accessors -currentContract :: VM t s -> Maybe Contract+currentContract :: VM t -> Maybe Contract currentContract vm =   Map.lookup vm.state.codeContract vm.env.contracts  -- * Data constructors ---makeVm :: VMOps t => VMOpts t -> ST s (VM t s)+makeVm :: VMOps t => VMOpts t -> ST RealWorld (VM t) makeVm o = do   let txaccessList = o.txAccessList       txorigin = o.origin@@ -186,7 +186,7 @@       }  -- https://eips.ethereum.org/EIPS/eip-4788-setEIP4788Storage :: VMOpts t -> VM t s -> VM t s+setEIP4788Storage :: VMOpts t -> VM t -> VM t setEIP4788Storage o vm = do   let beaconRootsAddress = LitAddr 0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02   case Map.lookup beaconRootsAddress vm.env.contracts of@@ -272,10 +272,10 @@ -- * Opcode dispatch (exec1)  -- | Update program counter-next :: (?op :: Word8) => EVM t s ()+next :: (?op :: Word8) => EVM t () next = modifying' (#state % #pc) (+ (opSize ?op)) -getOpW8 :: forall (t :: VMType) s . FrameState t s -> Word8+getOpW8 :: forall (t :: VMType) . FrameState t -> Word8 getOpW8 state = case state.code of       UnknownCode _ -> internalError "Cannot execute unknown code"       InitCode conc _ -> BS.index conc state.pc@@ -284,11 +284,11 @@         fromMaybe (internalError "could not analyze symbolic code") $           maybeLitByteSimp $ ops V.! state.pc -getOpName :: forall (t :: VMType) s . FrameState t s -> [Char]+getOpName :: forall (t :: VMType) . FrameState t -> [Char] getOpName state = intToOpName $ fromEnum $ getOpW8 state  -- | Executes the EVM one step-exec1 :: forall (t :: VMType) s. (VMOps t, Typeable t) => Config ->  EVM t s ()+exec1 :: forall (t :: VMType). (VMOps t, Typeable t) => Config ->  EVM t () exec1 conf = do   vm <- get @@ -727,63 +727,60 @@          OpSload -> {-# SCC "OpSload" #-}           case stk of-            x:xs -> do-              acc <- accessStorageForGas self x-              let cost = if acc then g_warm_storage_read else g_cold_sload-              burn cost $-                accessStorage self x $ \y -> do-                  next-                  assign' (#state % #stack) (y:xs)+            x:xs ->+              let+                finalizeLoad readValue = do next; assign' (#state % #stack) (readValue:xs)++                symbolicRead :: EVM t () = if this.external+                  then accessStorage self x finalizeLoad+                  else finalizeLoad $ Expr.readStorage' (Expr.concKeccakOnePass x) this.storage++                concreteRead :: EVM t () = do+                  acc <- accessStorageForGas self (forceLit x)+                  let cost = if acc then g_warm_storage_read else g_cold_sload+                  burn cost $ if this.external+                    then accessStorage self x finalizeLoad+                    else finalizeLoad $ Lit $ accessConcreteStorage this.storage (forceLit x)+              in whenSymbolicElse symbolicRead concreteRead             _ -> underrun          OpSstore -> {-# SCC "OpSstore" #-}           notStatic $           case stk of             x:new:xs ->-              accessStorage self x $ \current -> do-                ensureGas g_callstipend $ do-                  let-                    original =-                      case Expr.concKeccakSimpExpr $ SLoad x this.origStorage of-                        Lit v -> v-                        _ -> 0-                    storage_cost =-                      case (maybeLitWordSimp current, maybeLitWordSimp new) of-                        (Just current', Just new') ->-                           if (current' == new') then g_sload-                           else if (current' == original) && (original == 0) then g_sset-                           else if (current' == original) then g_sreset-                           else g_sload--                        -- if any of the arguments are symbolic,-                        -- assume worst case scenario-                        _-> g_sset+              let+                updateVMState :: EVM t () = do+                  next+                  assign' (#state % #stack) xs+                  modifying (#env % #contracts % ix self % #storage) (writeStorage x new) -                  acc <- accessStorageForGas self x-                  let cold_storage_cost = if acc then 0 else g_cold_sload-                  burn (storage_cost + cold_storage_cost) $ do-                    next-                    assign' (#state % #stack) xs-                    modifying (#env % #contracts % ix self % #storage) (writeStorage x new)+                concreteSstore :: EVM t () = do+                  let+                    slot = forceLit x+                    currentVal = accessConcreteStorage this.storage slot+                    newVal = forceLit new+                    originalVal = accessConcreteStorage this.origStorage slot+                  ensureGas g_callstipend $ do+                    let storage_cost+                          | (currentVal == newVal) = g_sload+                          | (currentVal == originalVal) && (originalVal == 0) = g_sset+                          | (currentVal == originalVal) = g_sreset+                          | otherwise = g_sload -                    case (maybeLitWordSimp current, maybeLitWordSimp new) of-                       (Just current', Just new') ->-                          unless (current' == new') $-                            if current' == original then-                              when (original /= 0 && new' == 0) $-                                refund (g_sreset + g_access_list_storage_key)-                            else do-                              when (original /= 0) $-                                if current' == 0-                                then unRefund (g_sreset + g_access_list_storage_key)-                                else when (new' == 0) $ refund (g_sreset + g_access_list_storage_key)-                              when (original == new') $-                                if original == 0-                                then refund (g_sset - g_sload)-                                else refund (g_sreset - g_sload)-                       -- if any of the arguments are symbolic,-                       -- don't change the refund counter-                       _ -> noop+                    acc <- accessStorageForGas self slot+                    let cold_storage_cost = if acc then 0 else g_cold_sload+                    burn (storage_cost + cold_storage_cost) $ do+                      updateVMState+                      case (originalVal, currentVal, newVal) of+                        (o, c, n)+                          | c == n -> pure ()+                          | o /= 0 && n == 0 -> refund (g_sreset + g_access_list_storage_key)+                          | o /= 0 && c == 0 -> do unRefund (g_sreset + g_access_list_storage_key); when (o == n) $ refund (g_sreset - g_sload)+                          | o /= 0 && o == n -> refund (g_sreset - g_sload)+                          | o == 0 && o == n -> refund (g_sset - g_sload)+                          | otherwise -> pure ()+              in+                whenSymbolicElse updateVMState concreteSstore             _ -> underrun          OpTload -> {-# SCC "OpTload" #-}@@ -818,7 +815,7 @@           case stk of             x:y:xs -> forceConcreteLimitSz x 2 "JUMPI: symbolic jumpdest" $ \x' ->               burn g_high $-                let jump :: Bool -> EVM t s ()+                let jump :: Bool -> EVM t ()                     jump False = assign' (#state % #stack) xs >> next                     jump _    = case tryInto x' of                       Left _ -> vmError BadJumpDestination@@ -1054,7 +1051,7 @@          OpUnknown xxx -> {-# SCC "OpUnknown" #-} vmError $ UnrecognizedOpcode xxx -transfer :: (VMOps t, ?conf::Config) => Expr EAddr -> Expr EAddr -> Expr EWord -> EVM t s ()+transfer :: (VMOps t, ?conf::Config) => Expr EAddr -> Expr EAddr -> Expr EWord -> EVM t () transfer _ _ (Lit 0) = pure () transfer src dst val = do   sb <- preuse $ #env % #contracts % ix src % #balance@@ -1086,7 +1083,7 @@  -- | Checks a *CALL for failure; OOG, too many callframes, memory access etc. callChecks-  :: forall (t :: VMType) s. (?op :: Word8, ?conf :: Config, VMOps t)+  :: forall (t :: VMType). (?op :: Word8, ?conf :: Config, VMOps t)   => Contract   -> Gas t   -> Expr EAddr@@ -1098,8 +1095,8 @@   -> Expr EWord   -> [Expr EWord]   -- continuation with gas available for call-  -> (Gas t -> EVM t s ())-  -> EVM t s ()+  -> (Gas t -> EVM t ())+  -> EVM t () callChecks this xGas xContext xTo xValue xInOffset xInSize xOutOffset xOutSize xs continue = do   vm <- get   let fees = vm.block.schedule@@ -1157,7 +1154,7 @@   -> Expr EWord   -> Expr EWord -> Expr EWord -> Expr EWord -> Expr EWord   -> [Expr EWord]-  -> EVM t s ()+  -> EVM t () precompiledContract this xGas precompileAddr recipient xValue inOffset inSize outOffset outSize xs   = callChecks this xGas (LitAddr recipient) (LitAddr precompileAddr) xValue inOffset inSize outOffset outSize xs $ \gas' ->     do@@ -1183,7 +1180,7 @@   :: (?op :: Word8, VMOps t)   => Addr   -> Gas t -> Expr EWord -> Expr EWord -> Expr EWord -> Expr EWord -> [Expr EWord]-  -> EVM t s ()+  -> EVM t () executePrecompile preCompileAddr gasCap inOffset inSize outOffset outSize xs  = do   vm <- get   input <- readMemory inOffset inSize@@ -1368,35 +1365,27 @@ pushToSequence :: MonadState s m => Setter s s (Seq a) (Seq a) -> a -> m () pushToSequence f x = f %= (Seq.|> x) -getCodeLocation :: VM t s -> CodeLocation+getCodeLocation :: VM t -> CodeLocation getCodeLocation vm = (vm.state.contract, vm.state.pc) -query :: Query t s -> EVM t s ()+query :: Query t -> EVM t () query q = assign #result $ Just $ HandleEffect (Query q) -runBoth :: Maybe Int -> Int -> RunBoth s -> EVM Symbolic s ()-runBoth depthLimit exploreDepth c = do-  if (isNothing depthLimit || (exploreDepth < fromJust depthLimit)) then do-    assign #result $ Just $ HandleEffect (RunBoth c)-  else do-    vm <- get-    assign #result $ Just $ Unfinished (BranchTooDeep {pc = vm.state.pc, addr = vm.state.contract})--runAll :: Maybe Int -> Int -> RunAll s -> EVM Symbolic s ()-runAll depthLimit exploreDepth c = do+fork :: Maybe Int -> Int -> BranchContext -> EVM Symbolic ()+fork depthLimit exploreDepth forkContext = do   if (isNothing depthLimit || (exploreDepth < fromJust depthLimit)) then do-    assign #result $ Just $ HandleEffect (RunAll c)+    assign #result $ Just $ HandleEffect (Branch forkContext)   else do     vm <- get     assign #result $ Just $ Unfinished (BranchTooDeep {pc = vm.state.pc, addr = vm.state.contract}) -fetchAccount :: VMOps t => Expr EAddr -> (Contract -> EVM t s ()) -> EVM t s ()+fetchAccount :: VMOps t => Expr EAddr -> (Contract -> EVM t ()) -> EVM t () fetchAccount addr continue =   let fallback = unexpectedSymArgW "trying to access a symbolic address that isn't already present in storage"   in fetchAccountWithFallback addr fallback continue  -- | Construct RPC Query and halt execution until resolved-fetchAccountWithFallback :: VMOps t => Expr EAddr -> (Expr EAddr -> EVM t s ()) -> (Contract -> EVM t s ()) -> EVM t s ()+fetchAccountWithFallback :: VMOps t => Expr EAddr -> (Expr EAddr -> EVM t ()) -> (Contract -> EVM t ()) -> EVM t () fetchAccountWithFallback addr fallback continue =   use (#env % #contracts % at addr) >>= \case     Just c -> continue c@@ -1411,10 +1400,16 @@             continue c       GVar _ -> internalError "Unexpected GVar" -accessStorage :: forall s t . (?conf :: Config, VMOps t, Typeable t) => Expr EAddr+accessConcreteStorage :: Expr Storage -> W256 -> W256+accessConcreteStorage storage slot' =+  case storage of+    (ConcreteStore m) -> fromMaybe 0 $ Map.lookup slot' m+    _ -> internalError "Storage must be concrete"++accessStorage :: forall t . (?conf :: Config, VMOps t, Typeable t) => Expr EAddr   -> Expr EWord-  -> (Expr EWord -> EVM t s ())-  -> EVM t s ()+  -> (Expr EWord -> EVM t ())+  -> EVM t () accessStorage addr slot continue = do   let slotConc = Expr.concKeccakSimpExpr slot   use (#env % #contracts % at addr) >>= \case@@ -1450,7 +1445,7 @@           -- So we store and return 0, as it is the only sound option           modifying (#env % #contracts % ix addr % #storage) (writeStorage slot (Lit 0))           continue $ Lit 0-      mkQuery :: Addr -> W256 -> EVM t s ()+      mkQuery :: Addr -> W256 -> EVM t ()       mkQuery a s = query $ PleaseFetchSlot a s $ \x -> do         modifying (#env % #contracts % ix (LitAddr a) % #storage) (writeStorage (Lit s) (Lit x))         assign #result Nothing@@ -1459,8 +1454,8 @@ accessTStorage   :: VMOps t => Expr EAddr   -> Expr EWord-  -> (Expr EWord -> EVM t s ())-  -> EVM t s ()+  -> (Expr EWord -> EVM t ())+  -> EVM t () accessTStorage addr slot continue = do   let slotConc = Expr.concKeccakSimpExpr slot   use (#env % #contracts % at addr) >>= \case@@ -1476,10 +1471,10 @@       fetchAccount addr $ \_ ->         accessTStorage addr slot continue -clearTStorages :: EVM t s ()+clearTStorages :: EVM t () clearTStorages = (#env % #contracts) %= fmap (\c -> c { tStorage = ConcreteStore mempty } :: Contract) -accountExists :: Expr EAddr -> VM t s -> Bool+accountExists :: Expr EAddr -> VM t -> Bool accountExists addr vm =   case Map.lookup addr vm.env.contracts of     Just c -> not (accountEmpty c)@@ -1498,7 +1493,7 @@  -- Adds constraints such that two symbolic addresses cannot alias each other -- and symbolic addresses cannot alias concrete addresses-addAliasConstraints :: EVM t s ()+addAliasConstraints :: EVM t () addAliasConstraints = do   vm <- get   let addrConstr = noClash $ Map.keys vm.env.contracts@@ -1507,7 +1502,7 @@     noClash addrs = [a ./= b | a <- addrs, b <- addrs, Expr.isSymAddr b, a < b]  -- * How to finalize a transaction-finalize :: VMOps t => EVM t s ()+finalize :: VMOps t => EVM t () finalize = do   let     revertContracts  = use (#tx % #txReversion) >>= assign (#env % #contracts)@@ -1565,7 +1560,7 @@       (\k a -> not ((k `elem` touchedAddresses) && accountEmpty a)))  -- | Loads the selected contract as the current contract to execute-loadContract :: Expr EAddr -> State (VM t s) ()+loadContract :: Expr EAddr -> State (VM t) () loadContract target =   preuse (#env % #contracts % ix target % #code) >>=     \case@@ -1576,14 +1571,14 @@         assign (#state % #code)     targetCode         assign (#state % #codeContract) target -limitStack :: VMOps t => Int -> EVM (t :: VMType) s () -> EVM t s ()+limitStack :: VMOps t => Int -> EVM (t :: VMType) () -> EVM t () limitStack n continue = do   stk <- use (#state % #stack)   if length stk + n > 1024     then vmError StackLimitExceeded     else continue -notStatic :: VMOps t => EVM t s () -> EVM t s ()+notStatic :: VMOps t => EVM t () -> EVM t () notStatic continue = do   bad <- use (#state % #static)   if bad@@ -1593,7 +1588,7 @@ -- Ensures the account `addr` exists on the VM environment. -- Useful when `addr` needs to e.g. keep a eth balance or -- be the source of contract deployments via pranks-touchAddress :: VMOps t => Expr EAddr -> EVM t s ()+touchAddress :: VMOps t => Expr EAddr -> EVM t () touchAddress addr = do   baseState <- use (#config % #baseState)   let mkc = case baseState of@@ -1601,21 +1596,21 @@               EmptyBase -> const emptyContract   (#env % #contracts) %= (Map.insertWith (\_ e -> e) addr (mkc addr)) -onlyDeployed :: forall t s . (?conf :: Config, VMOps t, Typeable t) =>+onlyDeployed :: forall t . (?conf :: Config, VMOps t, Typeable t) =>   Expr EWord-  -> (Expr EWord -> EVM t s ())-  -> (Expr EAddr -> EVM t s ())-  -> EVM t s ()+  -> (Expr EWord -> EVM t ())+  -> (Expr EAddr -> EVM t ())+  -> EVM t () onlyDeployed addrExpr fallback continue = do     vm <- get     if not (?conf.onlyDeployed) then fallback addrExpr     else case eqT @t @Symbolic of       Just Refl -> do         let deployedAddrs = map forceEAddrToEWord $ mapMaybe (codeMustExist vm) $ Map.keys vm.env.contracts-        runAll (?conf.maxDepth) vm.exploreDepth $ PleaseRunAll addrExpr deployedAddrs runAllPaths+        fork (?conf.maxDepth) vm.exploreDepth $ PleaseRunAll deployedAddrs runAllPaths       _ -> internalError "Unknown address in Concrete mode"   where-    codeMustExist :: (VM t s) -> Expr EAddr -> Maybe (Expr EAddr)+    codeMustExist :: (VM t) -> Expr EAddr -> Maybe (Expr EAddr)     codeMustExist vm addr = do       contr <- Map.lookup addr vm.env.contracts       case contr.code of@@ -1626,11 +1621,11 @@         pushTo #constraints $ Expr.simplifyProp (addrExpr .== val)         continue (forceEWordToEAddr val) -forceAddr :: forall t s . (?conf :: Config, VMOps t, Typeable t) =>+forceAddr :: forall t . (?conf :: Config, VMOps t, Typeable t) =>   Expr EWord-  -> (Expr EWord -> EVM t s ())-  -> (Expr EAddr -> EVM t s ())-  -> EVM t s ()+  -> (Expr EWord -> EVM t ())+  -> (Expr EAddr -> EVM t ())+  -> EVM t () forceAddr addrExpr fallback continue = case wordToAddr addrExpr of   Nothing -> manySolutions (?conf).maxDepth addrExpr 20 $ \case     Just sol -> continue $ LitAddr (truncateToAddr sol)@@ -1638,20 +1633,20 @@   Just c -> continue c  -unexpectedSymArg :: (Typeable a, VMOps t) => String -> [Expr a] -> EVM t s ()+unexpectedSymArg :: (Typeable a, VMOps t) => String -> [Expr a] -> EVM t () unexpectedSymArg msg n = do   pc <- use (#state % #pc)   state <- use #state   let opName = getOpName state   partial $ UnexpectedSymbolicArg pc state.contract opName msg (wrap n) -unexpectedSymArgW :: (Typeable a, VMOps t) => String -> Expr a -> EVM t s ()+unexpectedSymArgW :: (Typeable a, VMOps t) => String -> Expr a -> EVM t () unexpectedSymArgW msg n = unexpectedSymArg msg [n] -unknownCode :: VMOps t => Expr EAddr -> EVM t s ()+unknownCode :: VMOps t => Expr EAddr -> EVM t () unknownCode n = unexpectedSymArg "call target has unknown code" [n] -freshBufFallback :: (?conf :: Config, VMOps t, ?op :: Word8) => [Expr EWord] -> EVM t s ()+freshBufFallback :: (?conf :: Config, VMOps t, ?op :: Word8) => [Expr EWord] -> EVM t () freshBufFallback xs = do   -- Reset caller if needed   resetCaller <- use $ #state % #resetCaller@@ -1667,7 +1662,7 @@   assign (#state % #returndata) freshReturndataExpr   next >> assign' (#state % #stack) (freshVarExpr:xs) -freshVarFallback:: (VMOps t, ?op :: Word8) => [Expr EWord] -> Expr a -> EVM t s ()+freshVarFallback:: (VMOps t, ?op :: Word8) => [Expr EWord] -> Expr a -> EVM t () freshVarFallback xs _ = do   -- Reset caller if needed   resetCaller <- use $ #state % #resetCaller@@ -1679,55 +1674,55 @@   let freshVarExpr = Var (opName <> "-result-stack-fresh-" <> (pack . show) freshVar)   next >> assign' (#state % #stack) (freshVarExpr:xs) -forceConcrete :: (?conf :: Config, VMOps t) => Expr EWord -> String -> (W256 -> EVM t s ()) -> EVM t s ()+forceConcrete :: (?conf :: Config, VMOps t) => Expr EWord -> String -> (W256 -> EVM t ()) -> EVM t () forceConcrete n = forceConcreteLimitSz n 32 -forceConcreteLimitSz :: (?conf :: Config, VMOps t) => Expr EWord -> Int -> String -> (W256 -> EVM t s ()) -> EVM t s ()+forceConcreteLimitSz :: (?conf :: Config, VMOps t) => Expr EWord -> Int -> String -> (W256 -> EVM t ()) -> EVM t () forceConcreteLimitSz n bytes msg continue = case maybeLitWordSimp n of   Nothing -> manySolutions (?conf).maxDepth n bytes $ maybe fallback continue   Just c -> continue c   where fallback = unexpectedSymArg msg [n] -forceConcreteAddr :: (?conf :: Config, VMOps t) => Expr EAddr -> String -> (Addr -> EVM t s ()) -> EVM t s ()+forceConcreteAddr :: (?conf :: Config, VMOps t) => Expr EAddr -> String -> (Addr -> EVM t ()) -> EVM t () forceConcreteAddr n msg continue = case maybeLitAddrSimp n of   Nothing -> manySolutions (?conf).maxDepth (WAddr n) 20 $ maybe fallback $ \c -> continue (truncateToAddr c)   Just c -> continue c   where fallback = unexpectedSymArg msg [n] -forceConcreteAddr2 :: VMOps t => (Expr EAddr, Expr EAddr) -> String -> ((Addr, Addr) -> EVM t s ()) -> EVM t s ()+forceConcreteAddr2 :: VMOps t => (Expr EAddr, Expr EAddr) -> String -> ((Addr, Addr) -> EVM t ()) -> EVM t () forceConcreteAddr2 (n,m) msg continue = case (maybeLitAddrSimp n, maybeLitAddrSimp m) of   (Just c, Just d) -> continue (c,d)   _ -> unexpectedSymArg msg [n, m] -forceConcrete2 :: VMOps t => (Expr EWord, Expr EWord) -> String -> ((W256, W256) -> EVM t s ()) -> EVM t s ()+forceConcrete2 :: VMOps t => (Expr EWord, Expr EWord) -> String -> ((W256, W256) -> EVM t ()) -> EVM t () forceConcrete2 (n,m) msg continue = case (maybeLitWordSimp n, maybeLitWordSimp m) of   (Just c, Just d) -> continue (c, d)   _ -> unexpectedSymArg msg [n, m] -forceConcreteBuf :: VMOps t => Expr Buf -> String -> (ByteString -> EVM t s ()) -> EVM t s ()+forceConcreteBuf :: VMOps t => Expr Buf -> String -> (ByteString -> EVM t ()) -> EVM t () forceConcreteBuf (ConcreteBuf b) _ continue = continue b forceConcreteBuf b msg _ = unexpectedSymArg msg [b]  -- * Substate manipulation-refund :: Word64 -> EVM t s ()+refund :: Word64 -> EVM t () refund n = do   self <- use (#state % #contract)   pushTo (#tx % #subState % #refunds) (self, n) -unRefund :: Word64 -> EVM t s ()+unRefund :: Word64 -> EVM t () unRefund n = do   self <- use (#state % #contract)   refs <- use (#tx % #subState % #refunds)   assign (#tx % #subState % #refunds)     (filter (\(a,b) -> not (a == self && b == n)) refs) -touchAccount :: Expr EAddr -> EVM t s ()+touchAccount :: Expr EAddr -> EVM t () touchAccount = pushTo ((#tx % #subState) % #touchedAccounts) -selfdestruct :: Expr EAddr -> EVM t s ()+selfdestruct :: Expr EAddr -> EVM t () selfdestruct = pushTo ((#tx % #subState) % #selfdestructs) -accessAndBurn :: VMOps t => Expr EAddr -> EVM t s () -> EVM t s ()+accessAndBurn :: VMOps t => Expr EAddr -> EVM t () -> EVM t () accessAndBurn x cont = do   FeeSchedule {..} <- use (#block % #schedule)   acc <- accessAccountForGas x@@ -1736,7 +1731,7 @@  -- | returns a wrapped boolean- if true, this address has been touched before in the txn (warm gas cost as in EIP 2929) -- otherwise cold-accessAccountForGas :: Expr EAddr -> EVM t s Bool+accessAccountForGas :: Expr EAddr -> EVM t Bool accessAccountForGas addr = do   accessedAddrs <- use (#tx % #subState % #accessedAddresses)   let accessed = member addr accessedAddrs@@ -1745,15 +1740,12 @@  -- | returns a wrapped boolean- if true, this slot has been touched before in the txn (warm gas cost as in EIP 2929) -- otherwise cold-accessStorageForGas :: Expr EAddr -> Expr EWord -> EVM t s Bool+accessStorageForGas :: Expr EAddr -> W256 -> EVM t Bool accessStorageForGas addr key = do   accessedStrkeys <- use (#tx % #subState % #accessedStorageKeys)-  case maybeLitWordSimp key of-    Just litword -> do-      let accessed = member (addr, litword) accessedStrkeys-      assign (#tx % #subState % #accessedStorageKeys) (insert (addr, litword) accessedStrkeys)-      pure accessed-    _ -> pure False+  let accessed = member (addr, key) accessedStrkeys+  unless accessed $ assign (#tx % #subState % #accessedStorageKeys) (insert (addr, key) accessedStrkeys)+  pure accessed  -- * Cheat codes @@ -1765,9 +1757,9 @@ cheatCode = LitAddr $ unsafeInto (keccak' "hevm cheat code")  cheat-  :: forall t s . (?conf :: Config, ?op :: Word8, VMOps t, Typeable t)+  :: forall t . (?conf :: Config, ?op :: Word8, VMOps t, Typeable t)   => Gas t -> (Expr EWord, Expr EWord) -> (Expr EWord, Expr EWord) -> [Expr EWord]-  -> EVM t s ()+  -> EVM t () cheat gas (inOffset, inSize) (outOffset, outSize) xs = do   vm <- get   input <- readMemory (Expr.add inOffset (Lit 4)) (Expr.sub inSize (Lit 4))@@ -1789,7 +1781,7 @@       Nothing -> unexpectedSymArg "symbolic cheatcode selector" [abi]     Just concAbi -> runCheat concAbi input   where-    runCheat :: W256 -> Expr 'Buf -> EVM t s ()+    runCheat :: W256 -> Expr 'Buf -> EVM t ()     runCheat abi input =  do       let abi' = unsafeInto abi       case Map.lookup abi' cheatActions of@@ -1798,9 +1790,9 @@           whenSymbolicElse (partial $ CheatCodeMissing vm.state.pc vm.state.contract abi') (vmError $ BadCheatCode "Cannot understand cheatcode." abi')         Just action -> action input -type CheatAction t s = Expr Buf -> EVM t s ()+type CheatAction t = Expr Buf -> EVM t () -cheatActions :: (?conf :: Config, VMOps t, Typeable t) => Map FunctionSelector (CheatAction t s)+cheatActions :: (?conf :: Config, VMOps t, Typeable t) => Map FunctionSelector (CheatAction t) cheatActions = Map.fromList   [ action "ffi(string[])" $       \sig input -> do@@ -2057,13 +2049,13 @@   where     action s f = (abiKeccak s, f (abiKeccak s))     either' v l r = either l r v-    frameReturn :: VMOps t => AbiValue -> EVM t s ()+    frameReturn :: VMOps t => AbiValue -> EVM t ()     frameReturn v = frameReturnBuf $ encodeAbiValue v-    frameReturnBuf :: VMOps t => ByteString -> EVM t s ()+    frameReturnBuf :: VMOps t => ByteString -> EVM t ()     frameReturnBuf buf = frameReturnExpr $ ConcreteBuf buf-    frameReturnExpr :: VMOps t => Expr Buf -> EVM t s ()+    frameReturnExpr :: VMOps t => Expr Buf -> EVM t ()     frameReturnExpr e = finishFrame (FrameReturned e)-    frameRevert :: VMOps t => ByteString -> EVM t s ()+    frameRevert :: VMOps t => ByteString -> EVM t ()     frameRevert err = finishFrame (FrameReverted $ errorMsg err)     errorMsg :: ByteString -> Expr Buf     errorMsg err = ConcreteBuf $ selector "Error(string)" <> encodeAbiValue (AbiTuple $ V.fromList [AbiString err])@@ -2125,7 +2117,7 @@ -- * General call implementation ("delegateCall") -- note that the continuation is ignored in the precompile case delegateCall-  :: forall t s . (VMOps t, ?op :: Word8, ?conf :: Config, Typeable t)+  :: forall t . (VMOps t, ?op :: Word8, ?conf :: Config, Typeable t)   => Contract   -> Gas t   -> Expr EAddr@@ -2136,9 +2128,9 @@   -> Expr EWord   -> Expr EWord   -> [Expr EWord]-  -> (Expr EAddr -> EVM t s ()) -- fallback-  -> (Expr EAddr -> EVM t s ()) -- continue-  -> EVM t s ()+  -> (Expr EAddr -> EVM t ()) -- fallback+  -> (Expr EAddr -> EVM t ()) -- continue+  -> EVM t () delegateCall this gasGiven xTo xContext xValue xInOffset xInSize xOutOffset xOutSize xs fallback continue   | isPrecompileAddr xTo       = forceConcreteAddr2 (xTo, xContext) "Cannot call precompile with symbolic addresses" $@@ -2156,7 +2148,7 @@               UnknownCode _ -> betterFallback xGas vm0 xTo               _ -> actualCall target xTo xGas vm0   where-    betterFallback :: Gas t -> (VM t s) -> Expr 'EAddr -> EVM t s ()+    betterFallback :: Gas t -> (VM t) -> Expr 'EAddr -> EVM t ()     betterFallback xGas vm0 addr = onlyDeployed (forceEAddrToEWord addr) (fallback . forceEWordToEAddr) $ \a -> do         let target = fromJust $ Map.lookup a vm0.env.contracts         actualCall target a xGas vm0@@ -2213,9 +2205,9 @@     _ -> True   Nothing -> False -create :: forall t s. (?op :: Word8, ?conf::Config, VMOps t)+create :: forall t. (?op :: Word8, ?conf::Config, VMOps t)   => Expr EAddr -> Contract-  -> Expr EWord -> Gas t -> Expr EWord -> [Expr EWord] -> Expr EAddr -> Expr Buf -> EVM t s ()+  -> Expr EWord -> Gas t -> Expr EWord -> [Expr EWord] -> Expr EAddr -> Expr Buf -> EVM t () create self this xSize xGas xValue xs newAddr initCode = do   vm0 <- get   -- are we exceeding the max init code size@@ -2301,7 +2293,7 @@               , state   = vm1.state { stack = xs }               } -            state :: FrameState t s <- lift blankState+            state :: FrameState t <- lift blankState             assign #state $ state               { contract     = newAddr               , codeContract = newAddr@@ -2335,7 +2327,7 @@  -- | Replace a contract's code, like when CREATE returns -- from the constructor code.-replaceCode :: Expr EAddr -> ContractCode -> EVM t s ()+replaceCode :: Expr EAddr -> ContractCode -> EVM t () replaceCode target newCode =   zoom (#env % #contracts % at target) $     get >>= \case@@ -2354,25 +2346,25 @@       Nothing ->         internalError "Can't replace code of nonexistent contract" -replaceCodeOfSelf :: ContractCode -> EVM t s ()+replaceCodeOfSelf :: ContractCode -> EVM t () replaceCodeOfSelf newCode = do   vm <- get   replaceCode vm.state.contract newCode -resetState :: VMOps t => EVM t s ()+resetState :: VMOps t => EVM t () resetState = do   state <- lift blankState   modify' $ \vm -> vm { result = Nothing, frames = [], state }  -- * VM error implementation -vmError :: VMOps t => EvmError -> EVM t s ()+vmError :: VMOps t => EvmError -> EVM t () vmError e = finishFrame (FrameErrored e)  wrap :: Typeable a => [Expr a] -> [SomeExpr] wrap = fmap SomeExpr -underrun :: VMOps t => EVM t s ()+underrun :: VMOps t => EVM t () underrun = vmError StackUnderrun  -- | A stack frame can be popped in three ways.@@ -2382,7 +2374,7 @@   | FrameErrored EvmError -- ^ Any other error   deriving Show -finishAllFramesAndStop :: VMOps t => EVM t s ()+finishAllFramesAndStop :: VMOps t => EVM t () finishAllFramesAndStop = do   vm <- get   case vm.frames of@@ -2396,7 +2388,7 @@ -- -- It also handles the case when the current stack frame is the only one; -- in this case, we set the final '_result' of the VM execution.-finishFrame :: VMOps t => FrameResult -> EVM t s ()+finishFrame :: VMOps t => FrameResult -> EVM t () finishFrame how = do   oldVm <- get @@ -2524,8 +2516,8 @@ accessUnboundedMemoryRange   :: VMOps t => Word64   -> Word64-  -> EVM t s ()-  -> EVM t s ()+  -> EVM t ()+  -> EVM t () accessUnboundedMemoryRange _ 0 continue = continue accessUnboundedMemoryRange f l continue = do   m0 <- use (#state % #memorySize)@@ -2539,8 +2531,8 @@   :: VMOps t   => Expr EWord   -> Expr EWord-  -> EVM t s ()-  -> EVM t s ()+  -> EVM t ()+  -> EVM t () accessMemoryRange _ (Lit 0) continue = continue accessMemoryRange (Lit offs) (Lit sz) continue =   case (,) <$> toWord64 offs <*> toWord64 sz of@@ -2559,11 +2551,11 @@ accessMemoryRange _ _ continue = continue  accessMemoryWord-  :: VMOps t => Expr EWord -> EVM t s () -> EVM t s ()+  :: VMOps t => Expr EWord -> EVM t () -> EVM t () accessMemoryWord x = accessMemoryRange x (Lit 32)  copyBytesToMemory-  :: Expr Buf -> Expr EWord -> Expr EWord -> Expr EWord -> EVM t s ()+  :: Expr Buf -> Expr EWord -> Expr EWord -> Expr EWord -> EVM t () copyBytesToMemory bs size srcOffset memOffset =   if size == Lit 0 then noop   else do@@ -2589,11 +2581,11 @@         assign (#state % #memory) $ SymbolicMemory $ copySlice srcOffset memOffset size bs mem  copyCallBytesToMemory-  :: Expr Buf -> Expr EWord -> Expr EWord -> EVM t s ()+  :: Expr Buf -> Expr EWord -> Expr EWord -> EVM t () copyCallBytesToMemory bs size yOffset =   copyBytesToMemory bs (Expr.min size (bufLength bs)) (Lit 0) yOffset -readMemory :: Expr EWord -> Expr EWord -> EVM t s (Expr Buf)+readMemory :: Expr EWord -> Expr EWord -> EVM t (Expr Buf) readMemory offset' size' = do   vm <- get   case vm.state.memory of@@ -2621,7 +2613,7 @@  -- * Tracing -withTraceLocation :: TraceData -> EVM t s Trace+withTraceLocation :: TraceData -> EVM t Trace withTraceLocation x = do   vm <- get   let this = fromJust $ currentContract vm@@ -2631,19 +2623,19 @@     , opIx = fromMaybe 0 $ this.opIxMap VS.!? vm.state.pc     } -pushTrace :: TraceData -> EVM t s ()+pushTrace :: TraceData -> EVM t () pushTrace x = do   trace <- withTraceLocation x   modifying #traces $     \t -> Zipper.children $ Zipper.insert (Node trace []) t -insertTrace :: TraceData -> EVM t s ()+insertTrace :: TraceData -> EVM t () insertTrace x = do   trace <- withTraceLocation x   modifying #traces $     \t -> Zipper.nextSpace $ Zipper.insert (Node trace []) t -popTrace :: EVM t s ()+popTrace :: EVM t () popTrace =   modifying #traces $     \t -> case Zipper.parent t of@@ -2656,24 +2648,22 @@     Nothing -> Zipper.toForest z     Just z' -> zipperRootForest (Zipper.nextSpace z') -traceForest :: VM t s -> Forest Trace+traceForest :: VM t -> Forest Trace traceForest vm = zipperRootForest vm.traces  traceForest' :: Expr End -> Forest Trace traceForest' (Success _ (TraceContext f _ _) _ _) = f traceForest' (Partial _ (TraceContext f _ _) _) = f traceForest' (Failure _ (TraceContext f _ _) _) = f-traceForest' (ITE {}) = internalError"Internal Error: ITE does not contain a trace" traceForest' (GVar {}) = internalError"Internal Error: Unexpected GVar"  traceContext :: Expr End -> TraceContext traceContext (Success _ c _ _) = c traceContext (Partial _ c _) = c traceContext (Failure _ c _) = c-traceContext (ITE {}) = internalError"Internal Error: ITE does not contain a trace" traceContext (GVar {}) = internalError"Internal Error: Unexpected GVar" -traceTopLog :: [Expr Log] -> EVM t s ()+traceTopLog :: [Expr Log] -> EVM t () traceTopLog [] = noop traceTopLog ((LogEntry addr bytes topics) : _) = do   trace <- withTraceLocation (EventTrace addr bytes topics)@@ -2683,13 +2673,13 @@  -- * Stack manipulation -push :: W256 -> EVM t s ()+push :: W256 -> EVM t () push = pushSym . Lit -pushSym :: Expr EWord -> EVM t s ()+pushSym :: Expr EWord -> EVM t () pushSym x = modifying' (#state % #stack) (x :) -pushAddr :: Expr EAddr -> EVM t s ()+pushAddr :: Expr EAddr -> EVM t () pushAddr (LitAddr x) = modifying' (#state % #stack) (Lit (into x) :) pushAddr x@(SymAddr _) = modifying' (#state % #stack) (WAddr x :) pushAddr (GVar _) = internalError "Unexpected GVar"@@ -2698,7 +2688,7 @@   :: (?op :: Word8, VMOps t)   => Word64   -> (Expr EWord -> Expr EWord)-  -> EVM t s ()+  -> EVM t () stackOp1 cost f =   use (#state % #stack) >>= \case     x:xs ->@@ -2713,7 +2703,7 @@   :: (?op :: Word8, VMOps t)   => Word64   -> (Expr EWord -> Expr EWord -> Expr EWord)-  -> EVM t s ()+  -> EVM t () stackOp2 cost f =   use (#state % #stack) >>= \case     x:y:xs ->@@ -2727,7 +2717,7 @@   :: (?op :: Word8, VMOps t)   => Word64   -> (Expr EWord -> Expr EWord -> Expr EWord -> Expr EWord)-  -> EVM t s ()+  -> EVM t () stackOp3 cost f =   use (#state % #stack) >>= \case     x:y:z:xs ->@@ -2739,7 +2729,7 @@  -- * Bytecode data functions -checkJump :: VMOps t => Int -> [Expr EWord] -> EVM t s ()+checkJump :: VMOps t => Int -> [Expr EWord] -> EVM t () checkJump x xs = noJumpIntoInitData x $ do   vm <- get   case isValidJumpDest vm x of@@ -2749,7 +2739,7 @@     False -> vmError BadJumpDestination  -- fails with partial if we're trying to jump into the symbolic region of an `InitCode`-noJumpIntoInitData :: VMOps t => Int -> EVM t s () -> EVM t s ()+noJumpIntoInitData :: VMOps t => Int -> EVM t () -> EVM t () noJumpIntoInitData idx cont = do   vm <- get   case vm.state.code of@@ -2764,7 +2754,7 @@     -- we're not executing init code, so nothing to check here     _ -> cont -isValidJumpDest :: VM t s -> Int -> Bool+isValidJumpDest :: VM t -> Int -> Bool isValidJumpDest vm x = let     code = vm.state.code     self = vm.state.codeContract@@ -2830,7 +2820,7 @@           {- PUSH data. -}        (n - 1,        i + 1, j,     m >> VS.Mutable.write v i j)  -vmOp :: VM t s -> Maybe Op+vmOp :: VM t -> Maybe Op vmOp vm =   let i  = vm ^. #state % #pc       code' = vm ^. #state % #code@@ -2846,7 +2836,7 @@      then Nothing      else Just (readOp op pushdata) -vmOpIx :: VM t s -> Maybe Int+vmOpIx :: VM t -> Maybe Int vmOpIx vm =   do self <- currentContract vm      self.opIxMap VS.!? vm.state.pc@@ -2975,22 +2965,22 @@ toBuf (RuntimeCode (ConcreteRuntimeCode ops)) = Just $ ConcreteBuf ops toBuf (RuntimeCode (SymbolicRuntimeCode ops)) = Just $ Expr.fromList ops -codeloc :: EVM t s CodeLocation+codeloc :: EVM t CodeLocation codeloc = do   vm <- get   pure (vm.state.contract, vm.state.pc) -createAddress :: Expr EAddr -> Maybe W64 -> EVM t s (Expr EAddr)+createAddress :: Expr EAddr -> Maybe W64 -> EVM t (Expr EAddr) createAddress (LitAddr a) (Just n) = pure $ Concrete.createAddress a n createAddress (GVar _) _ = internalError "Unexpected GVar" createAddress _ _ = freshSymAddr -create2Address :: Expr EAddr -> W256 -> ByteString -> EVM t s (Expr EAddr)+create2Address :: Expr EAddr -> W256 -> ByteString -> EVM t (Expr EAddr) create2Address (LitAddr a) s b = pure $ Concrete.create2Address a s b create2Address (SymAddr _) _ _ = freshSymAddr create2Address (GVar _) _ _ = internalError "Unexpected GVar" -freshSymAddr :: EVM t s (Expr EAddr)+freshSymAddr :: EVM t (Expr EAddr) freshSymAddr = do   modifying (#env % #freshAddresses) (+ 1)   n <- use (#env % #freshAddresses)@@ -3013,7 +3003,7 @@ log2 :: FiniteBits b => b -> Int log2 x = finiteBitSize x - 1 - countLeadingZeros x -writeMemory :: MutableMemory s -> Int -> ByteString -> EVM t s ()+writeMemory :: MutableMemory -> Int -> ByteString -> EVM t () writeMemory memory offset buf = do   memory' <- expandMemory (offset + BS.length buf)   VS.iforM_ (byteStringToVector buf) $ \i v -> do@@ -3036,7 +3026,7 @@     else       pure memory -freezeMemory :: MutableMemory s -> EVM t s (Expr Buf)+freezeMemory :: MutableMemory -> EVM t (Expr Buf) freezeMemory memory =   ConcreteBuf . vectorToByteString <$> VS.freeze memory @@ -3074,12 +3064,11 @@     vm <- get     query $ PleaseAskSMT cond pathconds (runBothPaths loc vm.exploreDepth)     where-      condSimp = Expr.simplify cond-      condSimpConc = Expr.concKeccakSimpExpr condSimp       runBothPaths loc _ (Case v) = do         assign #result Nothing-        pushTo #constraints $ if v then Expr.simplifyProp (Lit 0 ./= condSimpConc)-                                   else Expr.simplifyProp (Lit 0 .== condSimpConc)+        let condSimp = Expr.simplify cond+        pushTo #constraints $ if v then Expr.simplifyProp (Lit 0 ./= condSimp)+                                   else Expr.simplifyProp (Lit 0 .== condSimp)         (iteration, _) <- use (#iterations % at loc % non (0,[]))         stack <- use (#state % #stack)         assign (#pathsVisited % at (loc, iteration)) (Just v)@@ -3087,7 +3076,7 @@         continue v       -- Both paths are possible; we ask for more input       runBothPaths loc exploreDepth UnknownBranch =-        (runBoth depthLimit exploreDepth ) . PleaseRunBoth condSimp $ (runBothPaths loc exploreDepth) . Case+        (fork depthLimit exploreDepth ) . PleaseRunBoth $ (runBothPaths loc exploreDepth) . Case    -- numBytes allows us to specify how many bytes of the returned value is relevant   -- if it's e.g.a JUMP, only 2 bytes can be relevant. This allows us to avoid@@ -3106,7 +3095,7 @@             assign #result Nothing             pushTo #constraints $ Expr.simplifyProp (ewordExpr .== (Lit val))             continue $ Just val-          _ -> runAll maxDepth vm.exploreDepth $ PleaseRunAll ewordExpr (map Lit concVals) runAllPaths+          _ -> fork maxDepth vm.exploreDepth $ PleaseRunAll (map Lit concVals) runAllPaths       Nothing -> do         assign #result Nothing         continue Nothing@@ -3248,7 +3237,7 @@   manySolutions _ _ _ = internalError "SMT solver should never be needed in concrete mode"  -- Create symbolic VM from concrete VM-symbolify :: VM Concrete s -> VM Symbolic s+symbolify :: VM Concrete -> VM Symbolic symbolify vm =   vm { result = symbolifyResult <$> vm.result      , state  = symbolifyFrameState vm.state@@ -3256,13 +3245,13 @@      , burned = ()      } -symbolifyFrameState :: FrameState Concrete s -> FrameState Symbolic s+symbolifyFrameState :: FrameState Concrete -> FrameState Symbolic symbolifyFrameState state = state { gas = () } -symbolifyFrame :: Frame Concrete s -> Frame Symbolic s+symbolifyFrame :: Frame Concrete -> Frame Symbolic symbolifyFrame frame = frame { state = symbolifyFrameState frame.state } -symbolifyResult :: VMResult Concrete s -> VMResult Symbolic s+symbolifyResult :: VMResult Concrete -> VMResult Symbolic symbolifyResult result =   case result of     HandleEffect _ -> internalError "shouldn't happen"@@ -3270,5 +3259,5 @@     VMSuccess b -> VMSuccess b  -burn :: VMOps t => Word64 -> EVM t s () -> EVM t s ()+burn :: VMOps t => Word64 -> EVM t () -> EVM t () burn = burn' . toGas
src/EVM/Exec.hs view
@@ -9,14 +9,14 @@ import Data.ByteString (ByteString) import Data.Maybe (isNothing) import Optics.Core-import Control.Monad.ST (ST)+import Control.Monad.ST (ST, RealWorld) import EVM.Effects (Config) import Data.Data (Typeable)  ethrunAddress :: Addr ethrunAddress = Addr 0x00a329c0648769a73afac7f9381e08fb43dbea72 -vmForEthrunCreation :: VMOps t => ByteString -> ST s (VM t s)+vmForEthrunCreation :: VMOps t => ByteString -> ST RealWorld (VM t) vmForEthrunCreation creationCode =   (makeVm $ VMOpts     { contract = initialContract (InitCode creationCode mempty)@@ -48,21 +48,21 @@     }) <&> set (#env % #contracts % at (LitAddr ethrunAddress))              (Just (initialContract (RuntimeCode (ConcreteRuntimeCode "")))) -exec :: (VMOps t, Typeable t) => Config -> EVM t s (VMResult t s)+exec :: (VMOps t, Typeable t) => Config -> EVM t (VMResult t) exec conf = do   vm <- get   case vm.result of     Nothing -> exec1 conf >> exec conf     Just r -> pure r -run :: (VMOps t, Typeable t) => Config -> EVM t s (VM t s)+run :: (VMOps t, Typeable t) => Config -> EVM t (VM t) run conf = do   vm <- get   case vm.result of     Nothing -> exec1 conf >> run conf     Just _ -> pure vm -execWhile :: (VM t s -> Bool) -> State (VM t s) Int+execWhile :: (VM t -> Bool) -> State (VM t) Int execWhile p = go 0   where     go i = do
src/EVM/Expr.hs view
@@ -9,7 +9,7 @@ import Prelude hiding (LT, GT) import Control.Monad (unless, when) import Control.Monad.ST (ST)-import Control.Monad.State (put, get, modify, execState, State)+import Control.Monad.State (put, get, execState, State) import Data.Bits hiding (And, Xor) import Data.ByteString (ByteString) import Data.ByteString qualified as BS@@ -177,7 +177,7 @@ not = op1 Not complement  shl :: Expr EWord -> Expr EWord -> Expr EWord-shl = op2 SHL (\x y -> if x > 256 then 0 else shiftL y (fromIntegral x))+shl = op2 SHL (\x y -> if x >= 256 then 0 else shiftL y (fromIntegral x))  shr :: Expr EWord -> Expr EWord -> Expr EWord shr = op2@@ -1001,20 +1001,6 @@     go (ReadByte idx buf) = readByte idx buf     go (BufLength buf) = bufLength buf -    -- We can zero out any bytes in a base ConcreteBuf that we know will be overwritten by a later write-    -- TODO: make this fully general for entire write chains, not just a single write.-    go o@(WriteWord (Lit idx) val (ConcreteBuf b))-      | idx >= maxBytes = o-      | BS.length b >= (unsafeInto idx + 32) =-          let-            slot = BS.take 32 (BS.drop (unsafeInto idx) b)-            isSlotZero = BS.all (== 0) slot-            content = if isSlotZero-              then b-              else (BS.take (unsafeInto idx) b)-                <> (BS.replicate 32 0)-                <> (BS.drop (unsafeInto idx + 32) b)-          in writeWord (Lit idx) val (ConcreteBuf content)     go (WriteWord a b c) = writeWord a b c      go (WriteByte a b c) = writeByte a b c@@ -1063,6 +1049,7 @@     go (IsZero (IsZero (IsZero a))) = iszero a     go (IsZero (IsZero (LT x y))) = lt x y     go (IsZero (IsZero (Eq x y))) = eq x y+    go (IsZero (IsZero a)) = lt (Lit 0) a     go (IsZero (Xor x y)) = eq x y     go (IsZero a) = iszero a @@ -1076,11 +1063,47 @@       | a == b = Lit 1       | otherwise = eq a b -    -- redundant ITE-    go (ITE (Lit x) a b)-      | x == 0 = b-      | otherwise = a+    -- COMPARISONS+    -- First special cases +    -- we write at least 32, so if x <= 32, it's FALSE+    go o@(EVM.Types.LT (BufLength (WriteWord {})) (Lit x))+      | x <= 32 = Lit 0+      | otherwise = o+    -- we write at least 32, so if x < 32, it's TRUE+    go o@(EVM.Types.LT (Lit x) (BufLength (WriteWord {})))+      | x < 32 = Lit 1+      | otherwise = o++    -- If a >= b then the value of the `Max` expression can never be < b+    go o@(LT (Max (Lit a) _) (Lit b))+      | a >= b = Lit 0+      | otherwise = o+    go o@(SLT (Sub (Max (Lit a) _) (Lit b)) (Lit c))+      = let sa, sb, sc :: Int256+            sa = fromIntegral a+            sb = fromIntegral b+            sc = fromIntegral c+        in if sa >= sb && sa - sb >= sc+           then Lit 0+           else o++    -- normalize all comparisons in terms of (S)LT+    go (EVM.Types.GT a b) = lt b a+    go (EVM.Types.GEq a b) = iszero (lt a b)+    go (EVM.Types.LEq a b) = iszero (lt b a)+    go (SGT a b) = slt b a++    -- LT+    go (EVM.Types.LT _ (Lit 0)) = Lit 0+    go (EVM.Types.LT a (Lit 1)) = iszero a+    go (EVM.Types.LT a b) = lt a b++    -- SLT+    go (SLT _ (Lit a)) | a == minLitSigned = Lit 0+    go (SLT (Lit a) _) | a == maxLitSigned = Lit 0+    go (SLT a b) = slt a b+     -- Masking as as per Solidity bit-packing of e.g. function parameters     go (And (Lit mask1) (Or (And (Lit mask2) _) x)) | (mask1 .&. mask2 == 0)          = And (Lit mask1) x@@ -1172,12 +1195,6 @@       where l = sort [a, b, c]             an = EVM.Expr.and -    -- A special pattern sometimes generated from Solidity that uses exponentiation to simulate bit shift.-    -- We can rewrite the exponentiation into a bit-shift under certain conditions.-    go (Exp (Lit 0x100) offset@(Mul (Lit a) (Mod _ (Lit b))))-      | a * b <= 32 && (maxWord256 `Prelude.div` a) > b = shl (mul (Lit 8) offset) (Lit 1)-    go (Exp (Lit 0x100) offset@(Mod _ (Lit 32))) = (shl (mul (Lit 8) offset)) (Lit 1)-     -- redundant add / sub     go (Sub (Add a b) c)       | a == c = b@@ -1228,22 +1245,6 @@       | b == (Lit 0) = a       | otherwise = EVM.Expr.or a b -    -- If x is ever non zero the Or will always evaluate to some non zero value and the false branch will be unreachable-    -- NOTE: with AND this does not work, because and(0x8, 0x4) = 0-    go (ITE (Or (Lit x) a) t f)-      | x == 0 = ITE a t f-      | otherwise = t-    go (ITE (Or a b@(Lit _)) t f) = ITE (Or b a) t f--    -- we write at least 32, so if x <= 32, it's FALSE-    go o@(EVM.Types.LT (BufLength (WriteWord {})) (Lit x))-      | x <= 32 = Lit 0-      | otherwise = o-    -- we write at least 32, so if x < 32, it's TRUE-    go o@(EVM.Types.LT (Lit x) (BufLength (WriteWord {})))-      | x < 32 = Lit 1-      | otherwise = o-     -- Double NOT is a no-op, since it's a bitwise inversion     go (EVM.Types.Not (EVM.Types.Not a)) = a @@ -1268,42 +1269,21 @@     go (SDiv _ (Lit 0)) = Lit 0 -- divide anything by 0 is zero in EVM     go (SDiv a (Lit 1)) = a     -- NOTE: Div x x is NOT 1, because Div 0 0 is 0, not 1.-    --++    --- Some trivial exp eliminations     go (Exp _ (Lit 0)) = Lit 1 -- everything, including 0, to the power of 0 is 1     go (Exp a (Lit 1)) = a -- everything, including 0, to the power of 1 is itself     go (Exp (Lit 1) _) = Lit 1 -- 1 to any value (including 0) is 1     -- NOTE: we can't simplify (Lit 0)^k. If k is 0 it's 1, otherwise it's 0.     --       this is encoded in SMT.hs instead, via an SMT "ite"--    -- If a >= b then the value of the `Max` expression can never be < b-    go o@(LT (Max (Lit a) _) (Lit b))-      | a >= b = Lit 0-      | otherwise = o-    go o@(SLT (Sub (Max (Lit a) _) (Lit b)) (Lit c))-      = let sa, sb, sc :: Int256-            sa = fromIntegral a-            sb = fromIntegral b-            sc = fromIntegral c-        in if sa >= sb && sa - sb >= sc-           then Lit 0-           else o--    -- normalize all comparisons in terms of (S)LT-    go (EVM.Types.GT a b) = lt b a-    go (EVM.Types.GEq a b) = leq b a-    go (EVM.Types.LEq a b) = iszero (lt b a)-    go (SGT a b) = slt b a--    -- LT-    go (EVM.Types.LT _ (Lit 0)) = Lit 0-    go (EVM.Types.LT a (Lit 1)) = iszero a-    go (EVM.Types.LT (Lit 0) a) = iszero (Eq (Lit 0) a)-    go (EVM.Types.LT a b) = lt a b--    -- SLT-    go (SLT _ (Lit a)) | a == minLitSigned = Lit 0-    go (SLT (Lit a) _) | a == maxLitSigned = Lit 0-    go (SLT a b) = slt a b+    --+    -- A special pattern sometimes generated from Solidity that uses exponentiation to simulate bit shift.+    -- We can rewrite the exponentiation into a bit-shift under certain conditions.+    go (Exp (Lit 0x100) offset@(Mul (Lit a) (Mod _ (Lit b))))+      | a * b <= 32 && (maxWord256 `Prelude.div` a) > b = shl (mul (Lit 8) offset) (Lit 1)+    go (Exp (Lit 0x100) offset@(Mod _ (Lit 32))) = (shl (mul (Lit 8) offset)) (Lit 1)+    go (Exp (Lit 2) k) = shl k (Lit 1)+    go (Exp a b) = EVM.Expr.exp a b      -- simple div/mod/add/sub     go (Div  o1 o2) = EVM.Expr.div  o1 o2@@ -1333,6 +1313,16 @@   let new = mapProp' go (simpInnerExpr prop)   in if (new == prop) then prop else simplifyProp new   where+    isBoolLike :: Expr EWord -> Bool+    isBoolLike = \case+      LT{} -> True+      SLT{} -> True+      Eq{} -> True+      IsZero{} -> True+      GT{} -> internalError "Should not encounter GT at this point!"+      LEq{} -> internalError "Should not encounter LEq at this point!"+      GEq{} -> internalError "Should not encounter GEq at this point!"+      _ -> False     go :: Prop -> Prop      -- Rewrite PGT/GEq to PLT/PLEq@@ -1355,16 +1345,29 @@     go (PLEq (Sub a b) c) | a == c = PLEq b a     go (PLEq a (Lit 0)) = peq (Lit 0) a     go (PLT (Max (Lit a) b) (Lit c)) | a < c = PLT b (Lit c)-    go (PLT (Lit 0) (Eq a b)) = peq a b-    go (PLEq a b) = pleq a b -    -- when it's PLT but comparison on the RHS then it's just (PEq 1 RHS)-    go (PLT (Lit 0) (a@LT {})) = peq (Lit 1) a-    go (PLT (Lit 0) (a@LEq {})) = peq (Lit 1) a-    go (PLT (Lit 0) (a@SLT {})) = peq (Lit 1) a-    go (PLT (Lit 0) (a@GT {})) = peq (Lit 1) a-    go (PLT (Lit 0) (a@GEq {})) = peq (Lit 1) a-    go (PLT (Lit 0) (a@SGT {})) = peq (Lit 1) a+    go (PLT (Lit 0) e)+      | isBoolLike e = peq (Lit 1) e++    -- all possible simplifications for PLT and PLEq have to be covered by this point+    go p@(PLT {}) = p+    go p@(PLEq {}) = p++    go (PEq (Lit 1) (Eq a b)) = peq a b+    go (PEq (Lit 1) (LT a b)) = PLT a b+    go (PEq (Lit 1) (IsZero e)) = PEq (Lit 0) e++    go (PEq (Lit 0) (IsZero e))+      | isBoolLike e = PEq (Lit 1) e+    go (PEq (Lit 0) (IsZero e)) = PNeg (PEq (Lit 0) e)+    go (PEq (Lit 0) (Eq a b)) = PNeg (peq a b)+    go (PEq (Lit 0) (LT a b)) = PLEq b a++    go (PEq (Lit 0) (Sub a b)) = peq a b+    go (PEq (Lit 0) (Or a b)) = peq (Lit 0) a `PAnd` peq (Lit 0) b+    go (PEq a1 (Add a2 y)) | a1 == a2 = peq (Lit 0) y+    go (PEq l r) = peq l r+     go (POr (PLEq a1 (Lit b)) (PLEq (Lit c) a2)) | a1 == a2 && c == b+1 = PBool True      -- negations@@ -1372,39 +1375,14 @@     go (PNeg (PNeg a)) = a     go (PNeg (PGT a b)) = PLEq a b     go (PNeg (PGEq a b)) = PLT a b-    go (PNeg (PLT a b)) = PGEq a b-    go (PNeg (PLEq a b)) = PGT a b+    go (PNeg (PLT a b)) = PLEq b a+    go (PNeg (PLEq a b)) = PLT b a     go (PNeg (PAnd a b)) = POr (PNeg a) (PNeg b)     go (PNeg (POr a b)) = PAnd (PNeg a) (PNeg b)-    go (PNeg (PEq (Lit 1) (IsZero b))) = PEq (Lit 0) (IsZero b)--    -- Empty buf-    go (PEq (Lit 0) (BufLength k)) = peq k (ConcreteBuf "")-    go (PEq (Lit 0) (Or a b)) = peq (Lit 0) a `PAnd` peq (Lit 0) b--    -- PEq rewrites (notice -- GT/GEq is always rewritten to LT by simplify)-    go (PEq (Lit 1) (IsZero (LT a b))) = PLT a b-    go (PEq (Lit 1) (IsZero (LEq a b))) = PLEq a b-    go (PEq (Lit 0) (IsZero a)) = PLT (Lit 0) a-    go (PEq a1 (Add a2 y)) | a1 == a2 = peq (Lit 0) y--    -- solc specific stuff-    go (PLT (Lit 0) (IsZero (Eq a b))) = PNeg (peq a b)--    -- iszero(a) -> (a == 0)-    -- iszero(iszero(a))) -> ~(a == 0) -> a > 0-    -- iszero(iszero(a)) == 0 -> ~~(a == 0) -> a == 0-    -- ~(iszero(iszero(a)) == 0) -> ~~~(a == 0) -> ~(a == 0) -> a > 0-    go (PNeg (PEq (Lit 0) (IsZero (IsZero a)))) = PLT (Lit 0) a--    -- iszero(a) -> (a == 0)-    -- iszero(a) == 0 -> ~(a == 0)-    -- ~(iszero(a) == 0) -> ~~(a == 0) -> a == 0-    go (PNeg (PEq (Lit 0) (IsZero a))) = peq (Lit 0) a--    -- a < b == 0 -> ~(a < b)-    -- ~(a < b == 0) -> ~~(a < b) -> a < b-    go (PNeg (PEq (Lit 0) (LT a b))) = PLT a b+    go (PNeg (PEq (Lit 1) e))+      | isBoolLike e = PEq (Lit 0) e+    go (PNeg (PEq (Lit 0) e))+      | isBoolLike e = PEq (Lit 1) e      -- And/Or     go (PAnd (PBool l) (PBool r)) = PBool (l && r)@@ -1423,20 +1401,7 @@     go (PImpl (PBool True) b) = b     go (PImpl (PBool False) _) = PBool True -    -- Double negation (no need for GT/GEq, as it's rewritten to LT/LEq) -    -- Eq-    go (PEq (Lit 0) (Eq a b)) = PNeg (peq a b)-    go (PEq (Lit 1) (Eq a b)) = peq a b-    go (PEq (Lit 0) (Sub a b)) = peq a b-    go (PEq (Lit 0) (LT a b)) = PLEq b a-    go (PEq (Lit 0) (LEq a b)) = PLT b a-    go (PEq (Lit 1) (LT a b)) = PLT a b-    go (PEq (Lit 1) (LEq a b)) = PLEq a b-    go (PEq (Lit 1) (GT a b)) = PGT a b-    go (PEq (Lit 1) (GEq a b)) = PGEq a b-    go (PEq l r) = peq l r-     go p = p  @@ -1672,10 +1637,6 @@ max x (Lit 0) = x max x y = normArgs Max Prelude.max x y -numBranches :: Expr End -> Int-numBranches (ITE _ t f) = numBranches t + numBranches f-numBranches _ = 1- allLit :: [Expr Byte] -> Bool allLit = all isLitByte @@ -1698,8 +1659,11 @@ -- | images of keccak(bytes32(x)) where 0 <= x < 256 preImageLookupMap :: Map.Map W256 Word8 preImageLookupMap = Map.fromList preImages+ data ConstState = ConstState   { values :: Map.Map (Expr EWord) W256+  , lowerBounds :: Map.Map (Expr EWord) W256+  , upperBounds :: Map.Map (Expr EWord) W256   , canBeSat :: Bool   }   deriving (Show)@@ -1707,7 +1671,7 @@ -- | Performs constant propagation constPropagate :: [Prop] -> [Prop] constPropagate ps =- let consts = collectConsts ps (ConstState mempty True)+ let consts = collectConsts ps emptyState  in if consts.canBeSat then substitute consts ps ++ fixVals consts     else [PBool False]   where@@ -1720,7 +1684,7 @@     --       hence we need the fixVals function to add them back in     substitute :: ConstState -> [Prop] -> [Prop]     substitute cs ps2 = map (mapProp (subsGo cs)) ps2-    subsGo :: ConstState -> Expr a-> Expr a+    subsGo :: ConstState -> Expr a -> Expr a     subsGo cs (Var v) = case Map.lookup (Var v) cs.values of       Just x -> Lit x       Nothing -> Var v@@ -1728,20 +1692,96 @@      -- Collects all the constants in the given props, and sets canBeSat to False if UNSAT     collectConsts ps2 startState = execState (mapM go ps2) startState+    emptyState = ConstState mempty mempty mempty True+    conflictState = ConstState mempty mempty mempty False+    conflict = put conflictState++    setExactValue :: Expr EWord -> W256 -> State ConstState ()+    setExactValue e v = do+      s <- get+      case Map.lookup e s.values of+        Just old -> when (old /= v) conflict+        _ -> put s { values = Map.insert e v s.values }++    updateLower :: Expr EWord -> W256 -> State ConstState ()+    updateLower a l = do+      s <- get+      let currentL = fromMaybe 0 (Map.lookup a s.lowerBounds)+          currentU = fromMaybe maxLit (Map.lookup a s.upperBounds)+          newL = Prelude.max currentL l+      if newL > currentU+        then conflict+        else put s { lowerBounds = Map.insert a newL s.lowerBounds }+      when (newL == currentU) $ setExactValue a newL++    updateUpper :: Expr EWord -> W256 -> State ConstState ()+    updateUpper a u = do+      s <- get+      let currentL = fromMaybe 0 (Map.lookup a s.lowerBounds)+          currentU = fromMaybe maxLit (Map.lookup a s.upperBounds)+          newU = Prelude.min currentU u+      if currentL > newU+        then conflict+        else put s { upperBounds = Map.insert a newU s.upperBounds }+      -- Check if equal to lower, then it's a constant+      when (currentL == newU) $ setExactValue a newU++    genericEq :: Expr EWord -> W256 -> State ConstState ()+    genericEq a v = do+      setExactValue a v+      updateLower a v+      updateUpper a v+     go :: Prop -> State ConstState ()     go = \case-        PEq (Lit l) a -> do-          s <- get-          case Map.lookup a s.values of-            Just l2 -> unless (l==l2) $ put ConstState {canBeSat=False, values=mempty}-            Nothing -> modify (\s' -> s'{values=Map.insert a l s'.values})-        PEq a b@(Lit _) -> go (PEq b a)+        -- signed inequalities+        PEq (Lit 1) term@(SLT a (Lit 0)) -> do+            genericEq term 1+            updateLower a minLitSigned+        PEq (Lit 1) term@(SLT (Lit 0) a) -> do+            genericEq term 1+            updateLower a 1+            updateUpper a maxLitSigned++        -- normal equality propagation+        PEq (Lit l) a -> genericEq a l+        PEq a (Lit l) -> genericEq a l+         PNeg (PEq (Lit l) a) -> do           s <- get           case Map.lookup a s.values of-            Just l2 -> when (l==l2) $ put ConstState {canBeSat=False, values=mempty}+            Just l2 -> when (l == l2) conflict             Nothing -> pure ()         PNeg (PEq a b@(Lit _)) -> go $ PNeg (PEq b a)++        -- inequalities (with overflow checks to prevent wraparound)+        -- PLT a (Lit b) means a < b, so a <= b-1+        PLT a (Lit b) ->+          if b == 0+            then conflict+            else updateUpper a (b - 1)+        -- PLT (Lit a) b means a < b, so b >= a+1+        PLT (Lit a) b ->+          if a == maxLit+            then conflict+            else updateLower b (a + 1)+        -- PLEq a (Lit b) means a <= b+        PLEq a (Lit b) -> updateUpper a b+        PLEq (Lit a) b -> updateLower b a+        -- PGT a (Lit b) means a > b, so a >= b+1+        PGT a (Lit b) ->+          if b == maxLit+            then conflict+            else updateLower a (b + 1)+        -- PGT (Lit a) b means a > b, so b <= a-1+        PGT (Lit a) b ->+          if a == 0+            then conflict+            else updateUpper b (a - 1)+        -- PGEq a (Lit b) means a >= b+        PGEq a (Lit b) -> updateLower a b+        PGEq (Lit a) b -> updateUpper b a+         PAnd a b -> do           go a           go b@@ -1752,7 +1792,7 @@             v2 = collectConsts [b] s           unless v1.canBeSat $ go b           unless v2.canBeSat $ go a-        PBool False -> put $ ConstState {canBeSat=False, values=mempty}+        PBool False -> conflict         _ -> pure ()  -- Concretize & simplify Keccak expressions until fixed-point.@@ -1827,4 +1867,3 @@ maybeConcStoreSimp e = case concKeccakSimpExpr e of   ConcreteStore s -> Just s   _ -> Nothing-
src/EVM/Fetch.hs view
@@ -2,21 +2,30 @@ module EVM.Fetch   ( fetchContractWithSession   , fetchBlockWithSession-  , fetchSlotWithSession-  , fetchWithSession   , fetchQuery   , oracle   , Fetcher   , RpcInfo (..)   , RpcQuery (..)   , EVM.Fetch.zero-  , readMockData+  , noRpc+  , noRpcFetcher   , BlockNumber (..)-  , mkRpcInfo   , mkSession+  , mkSessionWithoutCache   , Session (..)   , FetchCache (..)   , addFetchCache+  , saveCache+  , RPCContract (..)+  , makeContractFromRPC+  -- Below 4 are needed for Echidna+  , fetchSlotWithSession+  , fetchSlotWithCache+  , fetchWithSession+  , getCacheState+  , FetchStatus(..)+  , FetchResult(..)   ) where  import Prelude hiding (Foldable(..))@@ -27,22 +36,29 @@ import EVM.Format (hexText) import EVM.SMT import EVM.Solvers-import EVM.Types+import EVM.Types hiding (ByteStringS)+import EVM.Types (ByteStringS(..)) import EVM (emptyContract)  import Optics.Core+import GHC.Generics (Generic)+import System.FilePath ((</>))+import System.Directory (createDirectoryIfMissing, doesFileExist)+import Data.Aeson.Encode.Pretty (encodePretty)+import qualified Data.ByteString.Lazy as BSL+import Data.Bifunctor (first)+import Control.Exception (try, SomeException) -import Control.Monad.Trans.Maybe-import Control.Applicative (Alternative(..)) import Data.Aeson hiding (Error) import Data.Aeson.Optics import Data.ByteString qualified as BS import Data.Text (Text, unpack, pack) import Data.Text qualified as T-import Data.Text.Encoding qualified as T import Data.Foldable (Foldable(..)) import Data.Map.Strict qualified as Map-import Data.Maybe (fromMaybe, isJust, fromJust)+import Data.Maybe (fromMaybe, fromJust, isNothing)+import Data.Set qualified as Set+import Data.Set (Set) import Data.Vector qualified as RegularVector import Network.Wreq import Network.Wreq.Session qualified as NetSession@@ -53,31 +69,66 @@ import Control.Monad (when) import EVM.Effects import qualified EVM.Expr as Expr-import Data.Aeson.Encode.Pretty (encodePretty)-import Data.ByteString.Base16 qualified as BS16-import qualified Data.ByteString.Lazy as BSL-import Data.ByteString.Char8 qualified as Char8 import Control.Concurrent.MVar (MVar, newMVar, readMVar, modifyMVar_) -type Fetcher t m s = App m => Query t s -> m (EVM t s ())+type Fetcher t m = App m => Query t -> m (EVM t ()) +data FetchStatus = Cached | Fresh+  deriving (Show, Eq)++data FetchResult a+  = FetchSuccess a FetchStatus+  | FetchFailure FetchStatus+  | FetchError Text+  deriving (Show, Eq)+ data Session = Session-  { sess           :: NetSession.Session-  , latestBlockNum :: MVar (Maybe W256)-  , sharedCache    :: MVar FetchCache+  { sess            :: NetSession.Session+  , latestBlockNum  :: MVar (Maybe W256)+  , sharedCache     :: MVar FetchCache+  , cacheDir        :: Maybe FilePath+  -- Track ephemeral failures (network errors, not found, etc.)+  -- These are NOT persisted to disk+  , failedContracts :: MVar (Set Addr)+  , failedSlots     :: MVar (Set (Addr, W256))   }  data FetchCache = FetchCache-  { contractCache :: Map.Map Addr Contract+  { contractCache :: Map.Map Addr RPCContract   , slotCache     :: Map.Map (Addr, W256) W256   , blockCache    :: Map.Map W256 Block-  }+  } deriving (Generic)+++instance ToJSON FetchCache where+  toJSON (FetchCache cs ss bs) = object+    [ "contracts" .= Map.toList cs+    , "slots"     .= map (first (T.pack . show)) (Map.toList ss)+    , "blocks"    .= bs+    ]++instance FromJSON FetchCache where+  parseJSON = withObject "FetchCache" $ \v -> FetchCache+    <$> (Map.fromList <$> v .: "contracts")+    <*> (Map.fromList . map (first (read . T.unpack)) <$> v .: "slots")+    <*> (v .:? "blocks" .!= Map.empty)+ instance Show FetchCache where   show (FetchCache c s b) =     "FetchCache { contractCache: " ++ show (Map.keys c) ++     ", slotCache: " ++ show (Map.keys s) ++     ", blockCache: " ++ show (Map.keys b) ++ " }" +data Signedness = Signed | Unsigned+  deriving (Show)++showDec :: Signedness -> W256 -> T.Text+showDec signed (W256 w) = T.pack (show (i :: Integer))+  where+    i = case signed of+          Signed   -> fromIntegral (fromIntegral w :: Int)+          Unsigned -> fromIntegral w+ -- | Abstract representation of an RPC fetch request data RpcQuery a where   QueryCode    :: Addr         -> RpcQuery BS.ByteString@@ -93,27 +144,21 @@ deriving instance Show (RpcQuery a)  data RPCContract = RPCContract-  { mcCode    :: BS.ByteString-  , mcNonce   :: W64-  , mcBalance :: W256+  { code    :: ByteStringS+  , nonce   :: W64+  , balance :: W256   }-  deriving (Eq, Show)+  deriving (Eq, Show, Generic) -data RpcInfo = RpcInfo-  { blockNumURL  :: Maybe (BlockNumber, Text) -- ^ (block number, RPC url)-  , mockContract :: Maybe (Map.Map Addr RPCContract) -- ^ mock contracts (addr -> contract)-  , mockSlot     :: Maybe (Map.Map (Addr, W256) W256) -- ^ mock storage slots (addr, slot) -> value-  , mockBlock    :: Maybe (Map.Map W256 Block) -- ^ mock blocks (block number -> block)-  }+instance ToJSON RPCContract++instance FromJSON RPCContract++newtype RpcInfo = RpcInfo { blockNumURL  :: Maybe (BlockNumber, Text)} -- ^ (block number, RPC url)   deriving (Show)-instance Semigroup RpcInfo where-  RpcInfo a1 a2 a3 a4 <> RpcInfo b1 b2 b3 b4 =-    RpcInfo (a1 <|> b1) (a2 <|> b2) (a3 <|> b3) (a4 <|> b4)-instance Monoid RpcInfo where-  mempty = RpcInfo Nothing Nothing Nothing Nothing -mkRpcInfo :: Maybe (BlockNumber, Text) -> MockData -> RpcInfo-mkRpcInfo blockNumURL (MockData {..}) = RpcInfo blockNumURL mockContract mockSlot mockBlock+noRpc :: RpcInfo+noRpc = RpcInfo Nothing  rpc :: String -> [Value] -> Value rpc method args = object@@ -142,7 +187,7 @@ readText :: Read a => Text -> a readText = read . unpack -addFetchCache :: Session -> Addr -> Contract -> IO ()+addFetchCache :: Session -> Addr -> RPCContract -> IO () addFetchCache sess address ctrct = do   cache <- readMVar sess.sharedCache   liftIO $ modifyMVar_ sess.sharedCache $ \c -> pure $ c { contractCache = (Map.insert address ctrct cache.contractCache) }@@ -150,40 +195,34 @@ fetchQuery   :: Show a   => BlockNumber-  -> (Value -> IO (Maybe Value))+  -> (Value -> IO (Either Text Value))   -> RpcQuery a-  -> IO (Maybe a)+  -> IO (Either Text a) fetchQuery n f q =   case q of     QueryCode addr -> do         m <- f (rpc "eth_getCode" [toRPC addr, toRPC n])-        pure $ do-          t <- preview _String <$> m-          hexText <$> t+        pure $ m >>= \v -> maybeToRight "Parse error" (hexText <$> preview _String v)     QueryNonce addr -> do         m <- f (rpc "eth_getTransactionCount" [toRPC addr, toRPC n])-        pure $ do-          t <- preview _String <$> m-          readText <$> t+        pure $ m >>= \v -> maybeToRight "Parse error" (readText <$> preview _String v)     QueryBlock -> do       m <- f (rpc "eth_getBlockByNumber" [toRPC n, toRPC False])-      pure $ m >>= parseBlock+      pure $ m >>= \v -> maybeToRight "Parse error" (parseBlock v)     QueryBalance addr -> do         m <- f (rpc "eth_getBalance" [toRPC addr, toRPC n])-        pure $ do-          t <- preview _String <$> m-          readText <$> t+        pure $ m >>= \v -> maybeToRight "Parse error" (readText <$> preview _String v)     QuerySlot addr slot -> do         m <- f (rpc "eth_getStorageAt" [toRPC addr, toRPC slot, toRPC n])-        pure $ do-          t <- preview _String <$> m-          readText <$> t+        pure $ m >>= \v -> maybeToRight "Parse error" (readText <$> preview _String v)     QueryChainId -> do         m <- f (rpc "eth_chainId" [toRPC n])-        pure $ do-          t <- preview _String <$> m-          readText <$> t+        pure $ m >>= \v -> maybeToRight "Parse error" (readText <$> preview _String v) +maybeToRight :: b -> Maybe a -> Either b a+maybeToRight _ (Just x) = Right x+maybeToRight y Nothing  = Left y+ parseBlock :: (AsValue s, Show s) => s -> Maybe Block parseBlock j = do   coinbase   <- LitAddr . readText <$> j ^? key "miner" % _String@@ -237,80 +276,56 @@       <*> v .: "maxCodeSize"       <*> pure feeSchedule -data MockData = MockData-  { mockContract :: Maybe (Map.Map Addr RPCContract) -- ^ mock contracts (addr -> contract)-  , mockSlot     :: Maybe (Map.Map (Addr, W256) W256) -- ^ mock storage slots (addr, slot) -> value-  , mockBlock    :: Maybe (Map.Map W256 Block) -- ^ mock blocks (block number -> block)-  }-instance Semigroup MockData where-  MockData a1 a2 a3 <> MockData b1 b2 b3 =-    MockData (a1 <|> b1) (a2 <|> b2) (a3 <|> b3)-instance Monoid MockData where-  mempty = MockData Nothing Nothing Nothing-instance ToJSON RPCContract where-  toJSON (RPCContract code nonce balance) = object-    [ "mcCode" .= (T.pack $ "0x" ++ (concatMap (paddedShowHex 2) . BS.unpack $ code))-    , "mcNonce" .= nonce-    , "mcBalance" .= balance-    ]--instance FromJSON RPCContract where-  parseJSON = withObject "RPCContract" $ \v -> do-    codeHex <- v .: "mcCode"-    case (BS16.decodeBase16Untyped . strip0x . T.encodeUtf8) codeHex of-       Left _ -> fail "Invalid hex encoding for mcCode"-       Right bs -> RPCContract bs <$> v .: "mcNonce" <*> v .: "mcBalance"-    where-      strip0x :: BS.ByteString -> BS.ByteString-      strip0x bs = if "0x" `Char8.isPrefixOf` bs then Char8.drop 2 bs else bs--instance ToJSON MockData where-  toJSON (MockData contracts slots blocks) = object-    [ "mockContract" .= contracts-    , "mockSlot" .= slots-    , "mockBlock" .= blocks-    ]--instance FromJSON MockData where-  parseJSON = withObject "MockData" $ \v ->-    MockData <$> v .:? "mockContract" <*> v .:? "mockSlot" <*> v .:? "mockBlock"--readMockData :: FilePath -> IO (Either String MockData)-readMockData filePath = do-  jsonData <- BSL.readFile filePath-  pure $ eitherDecode jsonData--writeMockDataToFile :: FilePath -> MockData -> IO ()-writeMockDataToFile filePath mockData = do-  let jsonData = encodePretty mockData-  BSL.writeFile filePath jsonData-  putStrLn $ "Successfully wrote JSON to: " ++ filePath--fetchWithSession :: Text -> NetSession.Session -> Value -> IO (Maybe Value)+fetchWithSession :: Text -> NetSession.Session -> Value -> IO (Either Text Value) fetchWithSession url sess x = do   r <- asValue =<< NetSession.post sess (unpack url) x-  pure (r ^? (lensVL responseBody) % key "result")+  let body = r ^. (lensVL responseBody)+  case body ^? key "result" of+    Just val -> pure $ Right val+    Nothing -> case body ^? key "error" of+      Just err -> pure $ Left $ pack $ show err+      Nothing -> pure $ Left "Unknown RPC error" -fetchContractWithSession :: Config -> Session -> BlockNumber -> Text -> Addr -> IO (Maybe Contract)+fetchContractWithSession :: Config -> Session -> BlockNumber -> Text -> Addr -> IO (FetchResult RPCContract) fetchContractWithSession conf sess nPre url addr = do   n <- getLatestBlockNum conf sess nPre url+  -- Check successful cache first   cache <- readMVar sess.sharedCache   case Map.lookup addr cache.contractCache of     Just c -> do       when (conf.debug) $ putStrLn $ "-> Using cached contract at " ++ show addr-      pure $ Just c-    Nothing -> runMaybeT $ do-      let fetch :: Show a => RpcQuery a -> IO (Maybe a)-          fetch = fetchQuery n (fetchWithSession url sess.sess)-          fname  = "fetched_contract_" ++ show addr ++ ".json"-      code    <- MaybeT $ fetch (QueryCode addr)-      nonce   <- MaybeT $ fetch (QueryNonce addr)-      balance <- MaybeT $ fetch (QueryBalance addr)-      when (conf.debug) $ liftIO $ writeMockDataToFile fname (MockData (Just (Map.singleton addr (RPCContract code nonce balance))) Nothing Nothing)-      let contr = makeContractFromRPC (RPCContract code nonce balance)-      liftIO $ modifyMVar_ sess.sharedCache $ \c -> pure $ c { contractCache = (Map.insert addr contr cache.contractCache) }-      pure contr+      pure (FetchSuccess c Cached)+    Nothing -> do+      -- Check failure cache+      failures <- readMVar sess.failedContracts+      if Set.member addr failures+      then do+        when (conf.debug) $ putStrLn $ "-> Skipping previously failed contract " ++ show addr+        pure (FetchFailure Cached)+      else do+        -- Attempt fetch+        when (conf.debug) $ putStrLn $ "-> Fetching contract at " ++ show addr+        let fetch :: Show a => RpcQuery a -> IO (Either Text a)+            fetch = fetchQuery n (fetchWithSession url sess.sess) +        codeRes <- fetch (QueryCode addr)+        nonceRes <- fetch (QueryNonce addr)+        balRes <- fetch (QueryBalance addr)++        case (codeRes, nonceRes, balRes) of+          (Right c, Right no, Right ba) -> do+            let contr = RPCContract (ByteStringS c) no ba+            if c /= BS.empty +              then do+                modifyMVar_ sess.sharedCache $ \x -> pure $ x { contractCache = Map.insert addr contr x.contractCache }+                pure (FetchSuccess contr Fresh)+              else do+                modifyMVar_ sess.failedContracts $ \f -> pure $ Set.insert addr f+                pure (FetchFailure Fresh)+          (Left e, _, _) -> pure (FetchError e)+          (_, Left e, _) -> pure (FetchError e)+          (_, _, Left e) -> pure (FetchError e)+ -- In case the user asks for Latest, and we have not yet established what Latest is, -- we fetch the block to find out. Otherwise, we update Latest to the value we have stored getLatestBlockNum :: Config -> Session -> BlockNumber -> Text -> IO BlockNumber@@ -332,73 +347,165 @@    _ -> pure n  makeContractFromRPC :: RPCContract -> Contract-makeContractFromRPC (RPCContract code nonce balance) =+makeContractFromRPC (RPCContract (ByteStringS code) nonce balance) =     initialContract (RuntimeCode (ConcreteRuntimeCode code))       & set #nonce    (Just nonce)       & set #balance  (Lit balance)       & set #external True -fetchSlotWithSession :: NetSession.Session -> BlockNumber -> Text -> Addr -> W256 -> IO (Maybe W256)+-- Needed for Echidna only+fetchSlotWithCache :: Config -> Session -> BlockNumber -> Text -> Addr -> W256 -> IO (FetchResult W256)+fetchSlotWithCache conf sess nPre url addr slot = do+  n <- getLatestBlockNum conf sess nPre url+  -- Check successful cache+  cache <- readMVar sess.sharedCache+  case Map.lookup (addr, slot) cache.slotCache of+    Just s -> do+      when (conf.debug) $ putStrLn $ "-> Using cached slot value for slot " <> show slot <> " at " <> show addr+      pure (FetchSuccess s Cached)+    Nothing -> do+      -- Check failure cache+      failures <- readMVar sess.failedSlots+      if Set.member (addr, slot) failures+      then do+        when (conf.debug) $ putStrLn $ "-> Skipping previously failed slot " <> show slot <> " at " <> show addr+        pure (FetchFailure Cached)+      else do+        -- Attempt fetch+        when (conf.debug) $ putStrLn $ "-> Fetching slot " <> show slot <> " at " <> show addr+        ret <- fetchSlotWithSession sess.sess n url addr slot+        case ret of+          Right val -> do+            -- Success: cache it+            modifyMVar_ sess.sharedCache $ \c ->+              pure $ c { slotCache = Map.insert (addr, slot) val c.slotCache }+            pure (FetchSuccess val Fresh)+          Left err -> do+            pure (FetchError err)++-- | Get the complete cache state including both successes and failures+-- Returns in the format expected by Echidna's UI:+--   - Map Addr (Maybe Contract): Just = success, Nothing = failure+--   - Map Addr (Map W256 (Maybe W256)): Just = success, Nothing = failure+getCacheState+  :: Session+  -> IO (Map.Map Addr (Maybe Contract), Map.Map Addr (Map.Map W256 (Maybe W256)))+getCacheState sess = do+  cache <- readMVar sess.sharedCache+  failedContracts <- readMVar sess.failedContracts+  failedSlots <- readMVar sess.failedSlots++  -- Convert contract cache+  let successfulContracts = fmap (Just . makeContractFromRPC) cache.contractCache+  let allContracts = successfulContracts+                  <> Map.fromSet (const Nothing) failedContracts++  -- Convert slot cache: group by address+  let successfulSlotsByAddr = Map.foldrWithKey+        (\(addr, slot) value acc ->+          Map.insertWith Map.union addr (Map.singleton slot (Just value)) acc)+        Map.empty+        cache.slotCache++  -- Add failed slots+  let allSlots = Set.foldr+        (\(addr, slot) acc ->+          Map.insertWith Map.union addr (Map.singleton slot Nothing) acc)+        successfulSlotsByAddr+        failedSlots++  pure (allContracts, allSlots)++fetchSlotWithSession :: NetSession.Session -> BlockNumber -> Text -> Addr -> W256 -> IO (Either Text W256) fetchSlotWithSession sess n url addr slot =   fetchQuery n (fetchWithSession url sess) (QuerySlot addr slot)  fetchBlockWithSession :: Config -> Session  -> BlockNumber -> Text -> IO (Maybe Block) fetchBlockWithSession conf sess nPre url = do   n <- getLatestBlockNum conf sess nPre url-  internalBlockFetch conf sess n url+  case n of+    Latest -> internalBlockFetch conf sess n url+    EVM.Fetch.BlockNumber blockNum -> do+      cache <- readMVar sess.sharedCache+      case Map.lookup blockNum cache.blockCache of+        Just b -> do+          when (conf.debug) $ putStrLn $ "-> Using cached block " ++ show n+          pure (Just b)+        Nothing -> internalBlockFetch conf sess n url  internalBlockFetch :: Config -> Session -> BlockNumber -> Text -> IO (Maybe Block) internalBlockFetch conf sess n url = do   when (conf.debug) $ putStrLn $ "Fetching block " ++ show n ++ " from " ++ unpack url   ret <- fetchQuery n (fetchWithSession url sess.sess) QueryBlock   case ret of-    Nothing -> pure ret-    Just b -> do+    Left _ -> pure Nothing+    Right b -> do       let bn = forceLit b.number-      cache <- readMVar sess.sharedCache-      liftIO $ modifyMVar_ sess.sharedCache $ \c -> pure $ c { blockCache = (Map.insert bn b cache.blockCache) }-      when (conf.debug) $ do-        let fname = "fetched_block_" ++ show bn ++ ".json"-        writeMockDataToFile fname (MockData Nothing Nothing (Just (Map.singleton bn b)))-      pure ret+      liftIO $ modifyMVar_ sess.sharedCache $ \c ->+        pure $ c { blockCache = Map.insert bn b c.blockCache }+      pure (Just b) -fetchSlotFrom :: App m => Session -> BlockNumber -> Text -> Addr -> W256 -> m (Maybe W256)-fetchSlotFrom sess nPre url addr slot = do-  conf <- readConfig-  n <- liftIO $ getLatestBlockNum conf sess nPre url-  cache <- liftIO $ readMVar sess.sharedCache-  case Map.lookup (addr, slot) cache.slotCache of-    Just s -> do-      when (conf.debug) $ liftIO $ putStrLn $ "-> Using cached slot value for slot " <> show slot <> " at " <> show addr-      pure $ Just s-    Nothing -> do-      ret <- liftIO $ fetchSlotWithSession sess.sess n url addr slot-      when (isJust ret) $ let val = fromJust ret in-        liftIO $ modifyMVar_ sess.sharedCache $ \c -> pure $ c { slotCache = (Map.insert (addr,slot) val cache.slotCache) }-      when (conf.debug) $ liftIO $ do-        let fname = "fetched_slot_" ++ show addr ++ "_" ++ show slot ++ ".json"-        case ret of-          Just v -> writeMockDataToFile fname (MockData Nothing (Just (Map.singleton (addr, slot) v)) Nothing)-          Nothing -> pure ()-      pure ret+cacheFileName :: W256 -> FilePath+cacheFileName n = "rpc-cache-" ++ T.unpack (showDec Unsigned n) ++ ".json" -mkSession :: App m => m Session-mkSession = do+emptyCache :: FetchCache+emptyCache = FetchCache Map.empty Map.empty Map.empty++loadCache :: FilePath -> W256 -> IO FetchCache+loadCache dir n = do+  let fp = dir </> cacheFileName n+  exists <- doesFileExist fp+  if exists+    then do+      res <- try (BSL.readFile fp) :: IO (Either SomeException BSL.ByteString)+      case res of+        Left e -> do+          putStrLn $ "Warning: could not read cache file " ++ fp ++ ": " ++ show e+          pure emptyCache+        Right content ->+          case eitherDecode content of+            Left err -> do+              putStrLn $ "Warning: could not parse cache file " ++ fp ++ ": " ++ err+              pure emptyCache+            Right cache -> pure cache+    else+      pure emptyCache++saveCache :: FilePath -> W256 -> FetchCache -> IO ()+saveCache dir n cache = do+  createDirectoryIfMissing True dir+  let fp = dir </> cacheFileName n+  putStrLn $ "Saving RPC cache to " ++ fp+  BSL.writeFile fp (encodePretty cache)++mkSession :: App m => Maybe FilePath -> Maybe W256 -> m Session+mkSession cacheDir mblock = do   sess <- liftIO NetSession.newAPISession-  let emptyCache = FetchCache Map.empty Map.empty Map.empty-  cache <- liftIO $ newMVar emptyCache+  initialCache <- case (cacheDir, mblock) of+      (Just dir, Just block) -> liftIO $ loadCache dir block+      _ -> pure emptyCache+  cache <- liftIO $ newMVar initialCache   latestBlockNum <- liftIO $ newMVar Nothing-  pure $ Session sess latestBlockNum cache+  -- Initialize ephemeral failure tracking+  failedContracts <- liftIO $ newMVar Set.empty+  failedSlots <- liftIO $ newMVar Set.empty+  pure $ Session sess latestBlockNum cache cacheDir failedContracts failedSlots +mkSessionWithoutCache :: App m => m Session+mkSessionWithoutCache = mkSession Nothing Nothing+ -- Only used for testing (test.hs, BlockchainTests.hs)-zero :: Natural -> Maybe Natural -> Fetcher t m s+zero :: Natural -> Maybe Natural -> Fetcher t m zero smtjobs smttimeout q = do-  sess <- mkSession+  sess <- mkSessionWithoutCache   withSolvers Z3 smtjobs 1 smttimeout $ \s ->-    oracle s (Just sess) mempty q+    oracle s (Just sess) noRpc q +noRpcFetcher :: forall t m . App m => SolverGroup -> Fetcher t m+noRpcFetcher sg = oracle sg Nothing noRpc+ -- SMT solving + RPC data fetching + reading from environment-oracle :: forall t m s . App m => SolverGroup -> Maybe Session -> RpcInfo -> Fetcher t m s+oracle :: forall t m . App m => SolverGroup -> Maybe Session -> RpcInfo -> Fetcher t m oracle solvers preSess rpcInfo q = do   case q of     PleaseDoFFI vals envs continue -> case vals of@@ -414,59 +521,70 @@     PleaseAskSMT branchcondition pathconditions continue -> do          let pathconds = foldl' PAnd (PBool True) pathconditions          -- Is is possible to satisfy the condition?-         continue <$> checkBranch solvers (branchcondition ./= (Lit 0)) pathconds+         case branchcondition of+           Lit 0 -> pure $ continue (Case False)+           Lit _ -> pure $ continue (Case True)+           _     -> continue <$> checkBranch solvers (branchcondition ./= (Lit 0)) pathconds      PleaseGetSols symExpr numBytes pathconditions continue -> do          let pathconds = foldl' PAnd (PBool True) pathconditions          continue <$> getSolutions solvers symExpr numBytes pathconds -    PleaseFetchContract addr base continue -> withSession addr (continue (nothingContract base addr)) $ \sess -> do-      conf <- readConfig-      when (conf.debug) $ liftIO $ putStrLn $ "Fetching contract at " ++ show addr-      when (addr == 0 && conf.verb > 0) $ liftIO $ putStrLn "Warning: fetching contract at address 0"-      contract <- case rpcInfo.mockContract >>= Map.lookup addr of-        Just c  -> do-          when (conf.debug) $ liftIO $ putStrLn $ "Using mocked contract at " ++ show addr-          pure $ Just (makeContractFromRPC c)-        Nothing -> case rpcInfo.blockNumURL of-            Nothing -> pure $ Just $ nothingContract base addr-            Just (block, url) -> liftIO $ fetchContractWithSession conf sess block url addr-      case contract of-        Just x -> pure $ continue x-        Nothing -> internalError $ "oracle error: " ++ show q+    PleaseFetchContract addr base continue+      | isAddressSpecial addr -> pure $ continue nothingContract+      | isNothing rpcInfo.blockNumURL -> pure $ continue nothingContract+      | otherwise -> do+        let sess = fromMaybe (internalError $ "oracle: no session provided for fetch addr: " ++ show addr) preSess+        conf <- readConfig+        cache <- liftIO $ readMVar sess.sharedCache+        case Map.lookup addr cache.contractCache of+          Just c -> do+            when (conf.debug) $ liftIO $ putStrLn $ "-> Using cached contract at " ++ show addr+            pure $ continue $ makeContractFromRPC c+          Nothing -> do+            when (conf.debug) $ liftIO $ putStrLn $ "Fetching contract at " ++ show addr+            let (block, url) = fromJust rpcInfo.blockNumURL+            res <- liftIO $ fetchContractWithSession conf sess block url addr+            case res of+              FetchSuccess x _ -> pure $ continue (makeContractFromRPC x)+              FetchFailure _ -> internalError $ "oracle error: " ++ show q+              FetchError e -> internalError $ "oracle error: " ++ show e+      where+        nothingContract = case base of+          AbstractBase -> unknownContract (LitAddr addr)+          EmptyBase -> emptyContract -    PleaseFetchSlot addr slot continue -> withSession addr (continue 0)$ \sess -> do-      conf <- readConfig-      when (conf.debug) $ liftIO $ putStrLn $ "Fetching slot " <> (show slot) <> " at " <> (show addr)-      when (addr == 0 && conf.verb > 0) $ liftIO $ putStrLn "Warning: fetching slot from a contract at address 0"-      case rpcInfo.mockSlot >>= Map.lookup (addr, slot) of-        Just v  -> do-          when (conf.debug) $ liftIO $ putStrLn $ "Using mocked slot value for slot " <> show slot <> " at " <> show addr-          pure $ continue v-        Nothing -> case rpcInfo.blockNumURL of-            Nothing -> pure $ continue 0-            Just (block, url) -> fetchSlotFrom sess block url addr slot >>= \case-               Just x  -> pure $ continue x-               Nothing -> internalError $ "oracle error: " ++ show q+    PleaseFetchSlot addr slot continue+      | isAddressSpecial addr -> pure $ continue 0+      | isNothing rpcInfo.blockNumURL -> pure $ continue 0+      | otherwise -> do+        let sess = fromMaybe (internalError $ "oracle: no session provided for fetch addr: " ++ show addr) preSess+        conf <- readConfig+        cache <- liftIO $ readMVar sess.sharedCache+        case Map.lookup (addr, slot) cache.slotCache of+          Just s -> do+            when (conf.debug) $ liftIO $ putStrLn $ "-> Using cached slot value for slot " <> show slot <> " at " <> show addr+            pure $ continue s+          Nothing -> do+            when (conf.debug) $ liftIO $ putStrLn $ "Fetching slot " <> (show slot) <> " at " <> (show addr)+            let (block, url) = fromJust rpcInfo.blockNumURL+            n <- liftIO $ getLatestBlockNum conf sess block url+            ret <- liftIO $ fetchSlotWithSession sess.sess n url addr slot+            case ret of+              Right val -> do+                liftIO $ modifyMVar_ sess.sharedCache $ \c ->+                  pure $ c { slotCache = Map.insert (addr, slot) val c.slotCache }+                pure $ continue val+              Left err -> internalError $ "oracle error: " ++ show err      PleaseReadEnv variable continue -> do       value <- liftIO $ lookupEnv variable       pure . continue $ fromMaybe "" value      where-      nothingContract base addr =-        case base of-          AbstractBase -> unknownContract (LitAddr addr)-          EmptyBase -> emptyContract-      withSession addr def f =-        case addr of-          -- special values such as 0, 0xdeadbeef, 0xacab, hevm cheatcodes, and the precompile addresses-          -- do not require a session, there is nothing deployed there, it's way too small or special, RPC would be pointless-          a | a <= 0xdeadbeef -> pure def-          0x7109709ECfa91a80626fF3989D68f67F5b1DD12D -> pure def-          _ -> case preSess of-            Just sess  -> f sess-            Nothing -> internalError $ "oracle: no session provided for fetch addr: " ++ show addr+      -- special values such as 0, 0xdeadbeef, 0xacab, hevm cheatcodes, and the precompile addresses+      isAddressSpecial addr = addr <= 0xdeadbeef || addr == 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D+  getSolutions :: forall m . App m => SolverGroup -> Expr EWord -> Int -> Prop -> m (Maybe [W256]) getSolutions solvers symExprPreSimp numBytes pathconditions = do
src/EVM/Format.hs view
@@ -16,6 +16,7 @@   , showTraceTree'   , showValues   , prettyvmresult+  , prettyvmresults   , showCall   , showWordExact   , showWordExplanation@@ -191,7 +192,7 @@     format (AbstractBuf t) = "<" <> t <> " abstract buf>"     format e2 = T.pack $ "Symbolic expression: " <> show e2 -showTraceTree :: DappInfo -> VM t s -> Text+showTraceTree :: DappInfo -> VM t -> Text showTraceTree dapp vm =   let ?context = DappContext { info = dapp                              , contracts = vm.env.contracts@@ -201,7 +202,6 @@   in pack $ concatMap showTree traces  showTraceTree' :: DappInfo -> Expr End -> Text-showTraceTree' _ (ITE {}) = internalError "ITE does not contain a trace" showTraceTree' dapp leaf =   let ?context = DappContext { info = dapp, contracts, labels }   in let forest = traceForest' leaf@@ -453,6 +453,10 @@ prettyvmresult (Partial _ _ p) = T.unpack $ formatPartial p prettyvmresult r = internalError $ "Invalid result: " <> show r +prettyvmresults :: [Expr End] -> String+prettyvmresults results =+  T.unpack $ indent 2 $ T.unlines $ zipWith (\i r -> T.pack ("Result " <> show (i :: Integer) <> ": " <> prettyvmresult r)) [0..] results+ indent :: Int -> Text -> Text indent n = rstrip . T.unlines . fmap (T.replicate n (T.pack [' ']) <>) . T.lines @@ -520,7 +524,7 @@     ]  -formatPartialDetailed :: Maybe (WarningData s t) -> PartialExec -> Text+formatPartialDetailed :: Maybe (WarningData t) -> PartialExec -> Text formatPartialDetailed warnData p =   let toTxt addr pc = pack $ getSrcInfo warnData addr pc   in case p of@@ -531,7 +535,7 @@     PrecompileMissing {..}     -> "Precompile at address " <> pack (show preAddr) <> " does not exist, called from" <> toTxt addr pc     BranchTooDeep {..}         -> "Branches too deep" <> toTxt addr pc -getSrcInfo :: Maybe (WarningData s t) -> Expr EAddr -> Int -> String+getSrcInfo :: Maybe (WarningData t) -> Expr EAddr -> Int -> String getSrcInfo Nothing addr pc = " at addr: " <> show addr <> " at pc: " <> show pc getSrcInfo (Just dat) addr pc = fromMaybe (getSrcInfo Nothing addr pc) $ do   contr <- Map.lookup addr dat.vm.env.contracts@@ -565,14 +569,6 @@       (GVar v) -> "(GVar " <> T.pack (show v) <> ")"       LitByte w -> T.pack $ show w -      ITE c t f -> T.unlines-        [ "(ITE"-        , indent 2 $ T.unlines-          [ formatExpr c-          , formatExpr t-          , formatExpr f-          ]-        , ")"]       Success asserts _ buf store -> T.unlines         [ "(Success"         , indent 2 $ T.unlines
src/EVM/SMT.hs view
@@ -432,12 +432,16 @@   Sub a b -> op2 "bvsub" a b   Mul a b -> op2 "bvmul" a b   Exp a b -> case a of-    -- Lit 1 has already been handled via Expr.simplify     Lit 0 -> do       benc <- exprToSMT b       pure $ "(ite (= " <> benc `sp` zero <> " ) " <> one `sp` zero <> ")"+    Lit 1 -> pure one+    Lit 2 -> do+        benc <- exprToSMT b+        pure $ "(bvshl " <> one `sp` benc <> ")"     _ -> case b of-      Lit b' -> expandExp a b'+      -- b is limited below, otherwise SMT query will be huge, and eventually Haskell stack overflows+      Lit b' | b' < 1000 -> expandExp a b'       _ -> Left $ "Cannot encode symbolic exponent into SMT. Offending symbolic value: " <> show b   Min a b -> do     aenc <- exprToSMT a
src/EVM/Solidity.hs view
@@ -232,10 +232,10 @@   modifierDepth :: {-# UNPACK #-} !Int } deriving (Show, Eq, Ord, Generic) -data WarningData s t = WarningData+data WarningData t = WarningData   {solcContr :: SolcContract,    sourceCache :: SourceCache,-   vm :: VM s t+   vm :: VM t   }  data SrcMapParseState
src/EVM/Stepper.hs view
@@ -23,7 +23,7 @@  import Control.Monad.IO.Class import Control.Monad.Operational (Program, ProgramViewT(..), ProgramView, singleton, view)-import Control.Monad.ST (stToIO, RealWorld)+import Control.Monad.ST (stToIO) import Control.Monad.State.Strict (execStateT, get, StateT(..)) import Data.Text (Text) @@ -34,43 +34,39 @@ import EVM.Types  -- | The instruction type of the operational monad-data Action t s a where+data Action t a where   -- | Keep executing until an intermediate result is reached-  Exec :: Action t s (VMResult t s)+  Exec :: Action t (VMResult t)   -- | Embed a VM state transformation-  EVM  :: EVM t s a -> Action t s a+  EVM  :: EVM t a -> Action t a   -- | Wait for a query to be resolved-  Wait :: Query t s -> Action t s ()-  -- | Two things can happen-  Fork :: RunBoth s -> Action Symbolic s ()-  -- | Many (>2) things can happen-  ForkMany :: RunAll s -> Action Symbolic s ()+  Wait :: Query t -> Action t ()+  -- | More than one thing can happen+  Fork :: BranchContext -> Action Symbolic () + -- | Type alias for an operational monad of @Action@-type Stepper t s a = Program (Action t s) a+type Stepper t a = Program (Action t) a  -- Singleton actions -exec :: Stepper t s (VMResult t s)+exec :: Stepper t (VMResult t) exec = singleton Exec -run :: Stepper t s (VM t s)+run :: Stepper t (VM t) run = exec >> evm get -wait :: Query t s -> Stepper t s ()+wait :: Query t -> Stepper t () wait = singleton . Wait -fork :: RunBoth s -> Stepper Symbolic s ()+fork :: BranchContext -> Stepper Symbolic () fork = singleton . Fork -forkMany :: RunAll s -> Stepper Symbolic s ()-forkMany = singleton . ForkMany--evm :: EVM t s a -> Stepper t s a+evm :: EVM t a -> Stepper t a evm = singleton . EVM  -- | Run the VM until final result, resolving all queries-execFully :: Stepper Concrete s (Either EvmError (Expr Buf))+execFully :: Stepper Concrete (Either EvmError (Expr Buf)) execFully =   exec >>= \case     HandleEffect (Query q) ->@@ -81,32 +77,31 @@       pure (Right x)  -- | Run the VM until its final state-runFully :: Stepper t s (VM t s)+runFully :: Stepper t (VM t) runFully = do   vm <- run   case vm.result of     Nothing -> internalError "should not occur"     Just (HandleEffect (Query q)) ->       wait q >> runFully-    Just (HandleEffect (RunBoth q)) ->-      fork q >> runFully-    Just (HandleEffect (RunAll q)) ->-      forkMany q >> runFully+    Just (HandleEffect (Branch context)) ->+      fork context >> runFully     Just _ ->       pure vm -enter :: Text -> Stepper t s ()+enter :: Text -> Stepper t () enter t = evm (EVM.pushTrace (EntryTrace t)) +-- Concrete interpretation interpret   :: forall m a . (App m)-  => Fetch.Fetcher Concrete m RealWorld-  -> VM Concrete RealWorld-  -> Stepper Concrete RealWorld a+  => Fetch.Fetcher Concrete m+  -> VM Concrete+  -> Stepper Concrete a   -> m a interpret fetcher vm = eval . view   where-    eval :: ProgramView (Action Concrete RealWorld) a -> m a+    eval :: ProgramView (Action Concrete) a -> m a     eval (Return x) = pure x     eval (action :>>= k) =       case action of
src/EVM/SymExec.hs view
@@ -1,26 +1,31 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE DisambiguateRecordFields #-}  module EVM.SymExec where  import Prelude hiding (Foldable(..)) -import Control.Arrow ((>>>))-import Control.Concurrent.Async (concurrently, mapConcurrently)+import Control.Concurrent (forkIO, killThread)+import Control.Concurrent.Async ( mapConcurrently)+import Control.Concurrent.Chan (Chan, newChan, writeChan, readChan) import Control.Concurrent.Spawn (parMapIO, pool)-import Control.Monad (when, forM_, forM)-import Control.Monad.IO.Unlift+import Control.Concurrent.STM (writeTChan, newTChan, TChan, readTChan, atomically, isEmptyTChan, STM)+import Control.Concurrent.STM.TVar (TVar, newTVarIO, modifyTVar, readTVar, writeTVar)+import Control.Concurrent.STM.TMVar (TMVar, putTMVar, takeTMVar, newEmptyTMVarIO)+import Control.Monad (when, forM_, forM, forever)+import Control.Monad.Loops (whileM)+import Control.Monad.IO.Unlift (MonadUnliftIO, toIO, withRunInIO) import Control.Monad.Operational qualified as Operational import Control.Monad.ST (RealWorld, stToIO, ST)-import Control.Monad.State.Strict (runStateT)+import Control.Monad.State.Strict (liftIO, runStateT) import Data.ByteString (ByteString) import Data.ByteString qualified as BS-import Data.Containers.ListUtils (nubOrd) import Data.DoubleWord (Word256)-import Data.Foldable (Foldable(..))+import Data.Foldable (length, foldl', foldr) import Data.List (sortBy, sort) import Data.List.NonEmpty qualified as NE-import Data.Maybe (fromMaybe, listToMaybe, mapMaybe)+import Data.Maybe (fromMaybe, listToMaybe, mapMaybe, catMaybes) import Data.Map.Strict (Map) import Data.Map.Strict qualified as Map import Data.Map.Merge.Strict qualified as Map@@ -28,15 +33,23 @@ import Data.Set qualified as Set import Data.Text (Text) import Data.Text qualified as T+import Data.Text.Encoding (encodeUtf8) import Data.Text.IO qualified as T import Data.Tree.Zipper qualified as Zipper import Data.Tuple (swap) import Data.Vector qualified as V import Data.Vector.Storable qualified as VS import Data.Vector.Storable.ByteString (vectorToByteString)+import GHC.Conc (numCapabilities, getNumProcessors)+import GHC.Generics (Generic)+import GHC.Num.Natural (Natural)+import Optics.Core+import Options.Generic (ParseField, ParseFields, ParseRecord)+import Text.Printf (printf)+import Witch (into, unsafeInto)  import EVM (makeVm, abstractContract, initialContract, getCodeLocation, isValidJumpDest)-import EVM.Exec+import EVM.Exec (exec) import EVM.Fetch qualified as Fetch import EVM.ABI import EVM.Effects@@ -44,20 +57,12 @@ import EVM.FeeSchedule (feeSchedule) import EVM.Format (formatExpr, formatPartial, formatPartialDetailed, showVal, indent, formatBinary, formatProp, formatState, formatError) import EVM.SMT qualified as SMT-import EVM.Solvers+import EVM.Solvers (SolverGroup, checkSatWithProps) import EVM.Stepper (Stepper) import EVM.Stepper qualified as Stepper-import EVM.Traversals+import EVM.Traversals (mapExpr, mapExprM, foldTerm) import EVM.Types hiding (Comp) import EVM.Types qualified-import EVM.Expr (maybeConcStoreSimp)-import GHC.Conc (getNumProcessors)-import GHC.Generics (Generic)-import Optics.Core-import Options.Generic (ParseField, ParseFields, ParseRecord)-import Text.Printf (printf)-import Witch (into, unsafeInto)-import Data.Text.Encoding (encodeUtf8) import EVM.Solidity (WarningData (..))  data LoopHeuristic@@ -74,7 +79,7 @@     getIssue _ = Nothing     grouped = NE.group $ sort $ mapMaybe getIssue results -groupPartials :: Maybe (WarningData s t) -> [Expr End] -> [(Integer, String)]+groupPartials :: Maybe (WarningData t) -> [Expr End] -> [(Integer, String)] groupPartials warnData e = map (\g -> (into (length g), NE.head g)) grouped   where     getPartial :: Expr End -> Maybe String@@ -105,12 +110,9 @@ defaultVeriOpts :: VeriOpts defaultVeriOpts = VeriOpts   { iterConf = defaultIterConf-  , rpcInfo = mempty+  , rpcInfo = Fetch.noRpc   } -rpcVeriOpts :: (Fetch.BlockNumber, Text) -> VeriOpts-rpcVeriOpts info = defaultVeriOpts { rpcInfo  = mempty { Fetch.blockNumURL = Just info }}- extractCex :: VerifyResult -> Maybe (Expr End, SMTCex) extractCex (Cex c) = Just c extractCex _ = Nothing@@ -213,9 +215,9 @@ abstractVM   :: (Expr Buf, [Prop])   -> ByteString-  -> Maybe (Precondition s)+  -> Maybe (Precondition)   -> Bool-  -> ST s (VM Symbolic s)+  -> ST RealWorld (VM Symbolic) abstractVM cd contractCode maybepre create = do   let value = TxValue   let code = if create then InitCode contractCode (fst cd) else RuntimeCode (ConcreteRuntimeCode contractCode)@@ -230,7 +232,7 @@   :: ContractCode   -> Expr EWord   -> (Expr Buf, [Prop])-  -> ST s (VM Symbolic s)+  -> ST RealWorld (VM Symbolic) loadEmptySymVM x callvalue cd =   (makeVm $ VMOpts     { contract = initialContract x@@ -267,7 +269,7 @@   -> Expr EWord   -> (Expr Buf, [Prop])   -> Bool-  -> ST s (VM Symbolic s)+  -> ST RealWorld (VM Symbolic) loadSymVM x callvalue cd create =   (makeVm $ VMOpts     { contract = if create then initialContract x else abstractContract x (SymAddr "entrypoint")@@ -299,16 +301,16 @@     })  -- freezes any mutable refs, making it safe to share between threads-freezeVM :: VM Symbolic RealWorld -> ST RealWorld (VM Symbolic RealWorld)+freezeVM :: VM Symbolic -> ST RealWorld (VM Symbolic) freezeVM vm = do     state' <- do       mem' <- freeze (vm.state.memory)       pure $ vm.state { memory = mem' }-    frames' <- forM (vm.frames :: [Frame Symbolic RealWorld]) $ \frame -> do+    frames' <- forM (vm.frames :: [Frame Symbolic]) $ \frame -> do       mem' <- freeze frame.state.memory-      pure $ (frame :: Frame Symbolic RealWorld) { state = frame.state { memory = mem' } }+      pure $ (frame :: Frame Symbolic) { state = frame.state { memory = mem' } } -    pure (vm :: VM Symbolic RealWorld)+    pure (vm :: VM Symbolic)       { state = state'       , frames = frames'       }@@ -317,60 +319,192 @@       ConcreteMemory m -> SymbolicMemory . ConcreteBuf . vectorToByteString <$> VS.freeze m       m@(SymbolicMemory _) -> pure m --- | Interpreter which explores all paths at branching points. Returns an--- 'Expr End' representing the possible executions.-interpret-  :: forall m . App m-  => Fetch.Fetcher Symbolic m RealWorld+data InterpTask m a = InterpTask+  {fetcher :: Fetch.Fetcher Symbolic m+  , iterConf :: IterConfig+  , vm :: VM Symbolic+  , taskQ :: Chan (InterpTask m a)+  , numTasks :: TVar Natural+  , stepper :: Stepper Symbolic (Expr End)+  , handler :: Expr End -> m a+  }++data Process m a = Process+  { result :: Expr End+  , handler :: Expr End -> m a+  }++interpret :: forall m a . App m+  => Fetch.Fetcher Symbolic m   -> IterConfig-  -> VM Symbolic RealWorld-  -> Stepper Symbolic RealWorld (Expr End)+  -> VM Symbolic+  -> Stepper Symbolic (Expr End)+  -> (Expr End -> m a)+  -> m [a]+interpret fetcher iterConf vm stepper handler = do+  conf <- readConfig+  taskQ <- liftIO newChan+  processQ <- liftIO newChan++  -- spawn interpreters and process instances+  let interpInstances = replicate numCapabilities ()+      procInstances = replicate numCapabilities ()++  -- result channel+  resChan <- liftIO . atomically $ newTChan++  -- spawn orchestration thread with queues and flags+  availableInstances <- liftIO newChan+  liftIO $ forM_ interpInstances (writeChan availableInstances)+  availableProcs <- liftIO newChan+  liftIO $ forM_ procInstances (writeChan availableProcs)+  numTasks <- liftIO $ newTVarIO 1+  numProcs <- liftIO $ newTVarIO 0+  allProcessDone <- liftIO newEmptyTMVarIO++  -- spawn task orchestration thread+  taskOrchestrate' <- toIO $ taskOrchestrate taskQ availableInstances processQ numTasks numProcs+  taskOrchestrateId <- liftIO $ forkIO taskOrchestrate'++  -- spawn processing orchestration thread+  processOrchestrate' <- toIO $ processOrchestrate processQ availableProcs resChan numProcs numTasks allProcessDone+  processOrchestrateId <- liftIO $ forkIO processOrchestrate'++  -- Add in the first task, further tasks will be added by the interpreters themselves+  let interpTask = InterpTask+        { fetcher = fetcher+        , iterConf = iterConf+        , vm = vm+        , taskQ = taskQ+        , numTasks = numTasks+        , stepper = stepper+        , handler = handler+        }+  liftIO $ writeChan taskQ interpTask++  -- Wait for all done+  liftIO . atomically $ takeTMVar allProcessDone+  liftIO $ killThread taskOrchestrateId+  liftIO $ killThread processOrchestrateId+  res <- liftIO $ atomically (whileM (not <$> isEmptyTChan resChan) (readTChan resChan) :: STM [a])+  when (conf.debug) $ liftIO $ do+    putStrLn $ "Interpretation finished, collected " <> show (length res) <> " results."+  pure res+  where+    -- orchestrator loop+    taskOrchestrate :: App m+      => Chan (InterpTask m a)+      -> Chan () -> Chan (Process m a)+      -> TVar Natural -> TVar Natural -> m b+    taskOrchestrate taskQ avail processQ numTasks numProcs = forever $ do+      _ <- liftIO $ readChan avail+      task <- liftIO $ readChan taskQ+      runTask' <- toIO $ getOneExpr task avail processQ numTasks numProcs+      liftIO $ forkIO runTask'++    -- processing orchestrator loop+    processOrchestrate :: App m => Chan (Process m a) -> Chan () -> TChan a -> TVar Natural -> TVar Natural -> TMVar () -> m b+    processOrchestrate processQ availProcessors resChan numProcs numTasks allProcessDone = forever $ do+      _ <- liftIO $ readChan availProcessors+      proc <- liftIO $ readChan processQ+      runProcess' <- toIO $ processOne proc availProcessors resChan numProcs numTasks allProcessDone+      liftIO $ forkIO runProcess'++    -- process one task+    processOne :: App m => Process m a -> Chan () -> TChan a -> TVar Natural -> TVar Natural -> TMVar () -> m ()+    processOne task availProcs resChan numProcs numTasks allProcessDone = do+      processed <- task.handler task.result+      liftIO . atomically $ writeTChan resChan processed++      -- Return instance to pool immediately after processing+      liftIO $ writeChan availProcs ()++      -- Decrement and check if all done+      liftIO $ atomically $ do+        np <- readTVar numProcs+        let np' = np - 1+        writeTVar numProcs np'+        -- Check if both interpretation and processing are done+        nt <- readTVar numTasks+        when (np' == 0 && nt == 0) $ putTMVar allProcessDone ()++getOneExpr :: forall m a . App m+  => InterpTask m a+  -> Chan ()+  -> Chan (Process m a)+  -> TVar Natural+  -> TVar Natural+  -> m ()+getOneExpr task availableInstances processQ numTasks numProcs = do+  out <- interpretInternal task++  -- Enqueue for processing+  let process = Process { result = out, handler = task.handler }+  liftIO . atomically $ modifyTVar numProcs (+1)++  -- Return instance to pool & decrement tasks+  liftIO $ writeChan availableInstances ()+  liftIO $ atomically $ modifyTVar numTasks (subtract 1)++  -- Finally write to process queue. Must be done after numTasks decrement,+  -- or it could be that when we check in processOne, numTasks is still non-zero+  liftIO $ writeChan processQ process++-- | Symbolic interpreter that explores all paths. Returns an+-- '[Expr End]' representing the possible execution leafs.+interpretInternal :: forall m a . App m+  => InterpTask m a   -> m (Expr End)-interpret fetcher iterConf vm =-  eval . Operational.view+interpretInternal t@InterpTask{..} = eval (Operational.view stepper)   where-  eval :: Operational.ProgramView (Stepper.Action Symbolic RealWorld) (Expr End) -> m (Expr End)+  eval :: Operational.ProgramView (Stepper.Action Symbolic) (Expr End) -> m (Expr End)   eval (Operational.Return x) = pure x   eval (action Operational.:>>= k) =     case action of       Stepper.Exec -> do         conf <- readConfig         (r, vm') <- liftIO $ stToIO $ runStateT (exec conf) vm-        interpret fetcher iterConf vm' (k r)+        interpretInternal t { vm = vm', stepper =  (k r) }       Stepper.EVM m -> do         (r, vm') <- liftIO $ stToIO $ runStateT m vm-        interpret fetcher iterConf vm' (k r)-      Stepper.ForkMany (PleaseRunAll expr vals continue) -> do+        interpretInternal t { vm = vm', stepper = (k r) }+      Stepper.Fork (PleaseRunAll vals continue) -> do         when (length vals < 2) $ internalError "PleaseRunAll requires at least 2 branches"         frozen <- liftIO $ stToIO $ freezeVM vm         let newDepth = vm.exploreDepth+1-        ends <- withRunInIO $ \runInIO -> mapConcurrently (runInIO . runOne frozen newDepth) vals-        pure $ goITE (zip vals ends)+        runOne frozen newDepth vals         where-          goITE :: [(Expr EWord, Expr End)] -> Expr End-          goITE [] = internalError "goITE: empty list"-          goITE [(_, end)] = end-          goITE ((val,end):ps) = ITE (Eq expr val) end (goITE ps)-          runOne :: App m => VM 'Symbolic RealWorld -> Int -> Expr EWord -> m (Expr 'End)-          runOne frozen newDepth v = do+          runOne :: App m => VM 'Symbolic -> Int -> [Expr EWord] -> m (Expr End)+          runOne frozen newDepth [v] = do+            conf <- readConfig             (ra, vma) <- liftIO $ stToIO $ runStateT (continue v) frozen { result = Nothing, exploreDepth = newDepth }-            interpret fetcher iterConf vma (k ra)-      Stepper.Fork (PleaseRunBoth cond continue) -> do+            when (conf.debug && conf.verb >= 2) $ liftIO $ putStrLn $ "Running last task for ForkMany at depth " <> show newDepth+            interpretInternal t { vm = vma, stepper = (k ra) }+          runOne frozen newDepth (v:rest) = do+            conf <- readConfig+            (ra, vma) <- liftIO $ stToIO $ runStateT (continue v) frozen { result = Nothing, exploreDepth = newDepth }+            liftIO $ atomically $ modifyTVar numTasks (+1)+            when (conf.debug && conf.verb >=2) $ liftIO $ putStrLn $ "Queuing new task for ForkMany at depth " <> show newDepth+            liftIO $ writeChan taskQ t { vm = vma, stepper = (k ra) }+            runOne frozen newDepth rest+          runOne _ _ [] = internalError "unreachable"+      Stepper.Fork (PleaseRunBoth continue) -> do+        conf <- readConfig         frozen <- liftIO $ stToIO $ freezeVM vm         let newDepth = vm.exploreDepth+1-        evalLeft <- toIO $ do-          (ra, vma) <- liftIO $ stToIO $ runStateT (continue True) frozen { result = Nothing, exploreDepth = newDepth }-          interpret fetcher iterConf vma (k ra)-        evalRight <- toIO $ do-          (rb, vmb) <- liftIO $ stToIO $ runStateT (continue False) frozen { result = Nothing, exploreDepth = newDepth }-          interpret fetcher iterConf vmb (k rb)-        (a, b) <- liftIO $ concurrently evalLeft evalRight-        pure $ ITE cond a b+        (ra, vma) <- liftIO $ stToIO $ runStateT (continue True) frozen { result = Nothing, exploreDepth = newDepth }+        liftIO $ atomically $ modifyTVar numTasks (+1)+        liftIO $ writeChan taskQ $ t { vm = vma, stepper = (k ra) }+        when (conf.debug && conf.verb >= 2) $ liftIO $ putStrLn $ "Queued new task for Fork at depth " <> show newDepth++        (rb, vmb) <- liftIO $ stToIO $ runStateT (continue False) frozen { result = Nothing, exploreDepth = newDepth }+        when (conf.debug && conf.verb >=2) $ liftIO $ putStrLn $ "Continuing task for Fork at depth " <> show newDepth+        interpretInternal t { vm = vmb, stepper = (k rb) }       Stepper.Wait q -> do         let performQuery = do               m <- fetcher q               (r, vm') <- liftIO$ stToIO $ runStateT m vm-              interpret fetcher iterConf vm' (k r)+              interpretInternal t { vm = vm', stepper = (k r) }          case q of           PleaseAskSMT cond preconds continue -> do@@ -385,7 +519,7 @@                   -- No. keep executing                   _ -> do                     (r, vm') <- liftIO $ stToIO $ runStateT (continue (Case (c > 0))) vm-                    interpret fetcher iterConf vm' (k r)+                    interpretInternal t { vm = vm', stepper = (k r) }                -- the condition is symbolic               _ ->@@ -394,10 +528,12 @@                   -- we're in a loop and maxIters has been reached                   (Just True, _, Just n) -> do                     -- continue execution down the opposite branch than the one that-                    -- got us to this point and return a partial leaf for the other side+                    -- got us to this point and queue a task to return a partial leaf for the other side+                    let partialLeaf = Partial [] (TraceContext (Zipper.toForest vm.traces) vm.env.contracts vm.labels) (MaxIterationsReached vm.state.pc vm.state.contract)+                    liftIO $ atomically $ modifyTVar numTasks (+1)+                    liftIO $ writeChan taskQ $ t { vm = vm, stepper = pure partialLeaf }                     (r, vm') <- liftIO $ stToIO $ runStateT (continue (Case $ not n)) vm-                    a <- interpret fetcher iterConf vm' (k r)-                    pure $ ITE cond a (Partial [] (TraceContext (Zipper.toForest vm.traces) vm.env.contracts vm.labels) (MaxIterationsReached vm.state.pc vm.state.contract))+                    interpretInternal t { vm = vm', stepper = (k r) }                   -- we're in a loop and askSmtIters has been reached                   (Just True, True, _) ->                     -- ask the smt solver about the loop condition@@ -408,10 +544,10 @@                       [PBool False] -> liftIO $ stToIO $ runStateT (continue (Case False)) vm                       [] -> liftIO $ stToIO $ runStateT (continue (Case True)) vm                       _ -> liftIO $ stToIO $ runStateT (continue UnknownBranch) vm-                    interpret fetcher iterConf vm' (k r)+                    interpretInternal t { vm = vm', stepper = (k r) }           _ -> performQuery -maxIterationsReached :: VM Symbolic s -> Maybe Integer -> Maybe Bool+maxIterationsReached :: VM Symbolic -> Maybe Integer -> Maybe Bool maxIterationsReached _ Nothing = Nothing maxIterationsReached vm (Just maxIter) =   let codelocation = getCodeLocation vm@@ -420,7 +556,7 @@      then Map.lookup (codelocation, iters - 1) vm.pathsVisited      else Nothing -askSmtItersReached :: VM Symbolic s -> Integer -> Bool+askSmtItersReached :: VM Symbolic -> Integer -> Bool askSmtItersReached vm askSmtIters = let     codelocation = getCodeLocation vm     (iters, _) = view (at codelocation % non (0, [])) vm.iterations@@ -434,7 +570,7 @@   This heuristic is not perfect, and can certainly be tricked, but should generally be good enough for most compiler generated and non pathological user generated loops.  -}-isLoopHead :: LoopHeuristic -> VM Symbolic s -> Maybe Bool+isLoopHead :: LoopHeuristic -> VM Symbolic -> Maybe Bool isLoopHead Naive _ = Just True isLoopHead StackBased vm = let     loc = getCodeLocation vm@@ -445,8 +581,8 @@        Just (_, oldStack) -> Just $ filter isValid oldStack == filter isValid vm.state.stack        Nothing -> Nothing -type Precondition s = VM Symbolic s -> Prop-type Postcondition s = VM Symbolic s -> Expr End -> Prop+type Precondition = VM Symbolic -> Prop+type Postcondition = VM Symbolic -> Expr End -> Prop  -- Used only in testing checkAssert@@ -457,23 +593,9 @@   -> Maybe Sig   -> [String]   -> VeriOpts-  -> m (Expr End, [VerifyResult])+  -> m ([Expr End], [VerifyResult]) checkAssert solvers errs c signature' concreteArgs opts = do-  checkAssertWithSession solvers Nothing errs c signature' concreteArgs opts---- Used only in testing-checkAssertWithSession-  :: App m-  => SolverGroup-  -> Maybe Fetch.Session-  -> [Word256]-  -> ByteString-  -> Maybe Sig-  -> [String]-  -> VeriOpts-  -> m (Expr End, [VerifyResult])-checkAssertWithSession solvers sess errs c signature' concreteArgs opts = do-  verifyContractWithSession solvers sess c signature' concreteArgs opts Nothing (Just $ checkAssertions errs)+  verifyContract solvers c signature' concreteArgs opts Nothing (checkAssertions errs)  -- Used only in testing getExprEmptyStore@@ -483,13 +605,13 @@   -> Maybe Sig   -> [String]   -> VeriOpts-  -> m (Expr End)+  -> m [Expr End] getExprEmptyStore solvers c signature' concreteArgs opts = do   conf <- readConfig   calldata <- mkCalldata signature' concreteArgs   preState <- liftIO $ stToIO $ loadEmptySymVM (RuntimeCode (ConcreteRuntimeCode c)) (Lit 0) calldata-  exprInter <- interpret (Fetch.oracle solvers Nothing opts.rpcInfo) opts.iterConf preState runExpr-  if conf.simp then (pure $ Expr.simplify exprInter) else pure exprInter+  paths <- interpret (Fetch.oracle solvers Nothing opts.rpcInfo) opts.iterConf preState runExpr pure+  if conf.simp then (pure $ map Expr.simplify paths) else pure paths  -- Used only in testing getExpr@@ -499,13 +621,13 @@   -> Maybe Sig   -> [String]   -> VeriOpts-  -> m (Expr End)+  -> m [Expr End] getExpr solvers c signature' concreteArgs opts = do   conf <- readConfig   calldata <- mkCalldata signature' concreteArgs   preState <- liftIO $ stToIO $ abstractVM calldata c Nothing False-  exprInter <- interpret (Fetch.oracle solvers Nothing opts.rpcInfo) opts.iterConf preState runExpr-  if conf.simp then (pure $ Expr.simplify exprInter) else pure exprInter+  paths <- interpret (Fetch.oracle solvers Nothing opts.rpcInfo) opts.iterConf preState runExpr pure+  if conf.simp then (pure $ map Expr.simplify paths) else pure paths  {- | Checks if an assertion violation has been encountered @@ -527,7 +649,7 @@   see: https://docs.soliditylang.org/en/v0.8.6/control-structures.html?highlight=Panic#panic-via-assert-and-error-via-require   NOTE: does not deal with e.g. `assertEq()` -}-checkAssertions :: [Word256] -> Postcondition s+checkAssertions :: [Word256] -> Postcondition checkAssertions errs _ = \case   Failure _ _ (UnrecognizedOpcode 0xfe)  -> PBool False   Failure _ _ (Revert (ConcreteBuf msg)) -> PBool $ msg `notElem` (fmap panicMsg errs)@@ -567,31 +689,32 @@   -> Maybe Sig   -> [String]   -> VeriOpts-  -> Maybe (Precondition RealWorld)-  -> Maybe (Postcondition RealWorld)-  -> m (Expr End, [VerifyResult])-verifyContract solvers theCode signature' concreteArgs opts maybepre maybepost = do-  verifyContractWithSession solvers Nothing theCode signature' concreteArgs opts maybepre maybepost+  -> Maybe Precondition+  -> Postcondition+  -> m ([Expr End], [VerifyResult])+verifyContract solvers theCode signature' concreteArgs opts maybepre post = do+  calldata <- mkCalldata signature' concreteArgs+  preState <- liftIO $ stToIO $ abstractVM calldata theCode maybepre False+  let fetcher = Fetch.oracle solvers Nothing opts.rpcInfo+  verify solvers fetcher opts preState post Nothing  -- Used only in testing-verifyContractWithSession :: forall m . App m+exploreContract :: forall m . App m   => SolverGroup-  -> Maybe Fetch.Session   -> ByteString   -> Maybe Sig   -> [String]   -> VeriOpts-  -> Maybe (Precondition RealWorld)-  -> Maybe (Postcondition RealWorld)-  -> m (Expr End, [VerifyResult])-verifyContractWithSession solvers sess theCode signature' concreteArgs opts maybepre maybepost = do+  -> Maybe Precondition+  -> m [Expr End]+exploreContract solvers theCode signature' concreteArgs opts maybepre = do   calldata <- mkCalldata signature' concreteArgs   preState <- liftIO $ stToIO $ abstractVM calldata theCode maybepre False-  let fetcher = Fetch.oracle solvers sess opts.rpcInfo-  verify solvers fetcher opts preState maybepost+  let fetcher = Fetch.oracle solvers Nothing opts.rpcInfo+  executeVM fetcher opts.iterConf preState pure  -- | Stepper that parses the result of Stepper.runFully into an Expr End-runExpr :: Stepper.Stepper Symbolic RealWorld (Expr End)+runExpr :: Stepper.Stepper Symbolic (Expr End) runExpr = do   vm <- Stepper.runFully   let traces = TraceContext (Zipper.toForest vm.traces) vm.env.contracts vm.labels@@ -604,53 +727,12 @@ toEContract :: Contract -> Expr EContract toEContract c = C c.code c.storage c.tStorage c.balance c.nonce --- | Converts a given top level expr into a list of final states and the--- associated path conditions for each state.-flattenExpr :: Expr End -> [Expr End]-flattenExpr = go []-  where-    go :: [Prop] -> Expr End -> [Expr End]-    go pcs = \case-      ITE c t f -> go (PNeg ((PEq (Lit 0) c)) : pcs) t <> go (PEq (Lit 0) c : pcs) f-      Success ps trace msg store -> [Success (nubOrd $ ps <> pcs) trace msg store]-      Failure ps trace e -> [Failure (nubOrd $ ps <> pcs) trace e]-      Partial ps trace p -> [Partial (nubOrd $ ps <> pcs) trace p]-      GVar _ -> internalError "cannot flatten an Expr containing a GVar"---- | Strips unreachable branches from a given expr--- Returns a list of executed SMT queries alongside the reduced expression for debugging purposes--- Note that the reduced expression loses information relative to the original--- one if jump conditions are removed. This restriction can be removed once--- Expr supports attaching knowledge to AST nodes.--- Although this algorithm currently parallelizes nicely, it does not exploit--- the incremental nature of the task at hand. Introducing support for--- incremental queries might let us go even faster here.--- TODO: handle errors properly-reachable :: App m => SolverGroup -> Expr End -> m (Expr End)-reachable solvers e = do-  res <- go [] e-  pure $ fromMaybe (internalError "no reachable paths found") res+-- | Strips unreachable branches from a given list of Expr End nodes+reachable :: App m => SolverGroup -> [Expr End] -> m [Expr End]+reachable solvers e = catMaybes <$> mapM go e   where-    {--       Walk down the tree and collect pcs.-       Dispatch a reachability query at each leaf.-       If reachable return the expr wrapped in a Just. If not return Nothing.-       When walking back up the tree drop unreachable subbranches.-    -}-    go :: (App m, MonadUnliftIO m) => [Prop] -> Expr End -> m (Maybe (Expr End))-    go pcs = \case-      ITE c t f -> do-        (tres, fres) <- withRunInIO $ \env -> concurrently-          (env $ go (PEq (Lit 1) c : pcs) t)-          (env $ go (PEq (Lit 0) c : pcs) f)-        let subexpr = case (tres, fres) of-              (Just t', Just f') -> Just $ ITE c t' f'-              (Just t', Nothing) -> Just t'-              (Nothing, Just f') -> Just f'-              (Nothing, Nothing) -> Nothing-        pure subexpr-      leaf -> do-        res <- checkSatWithProps solvers pcs+    go leaf = do+        res <- checkSatWithProps solvers (extractProps leaf)         case res of           Qed -> pure Nothing           Cex _ -> pure (Just leaf)@@ -661,7 +743,6 @@ -- | Extract constraints stored in Expr End nodes extractProps :: Expr End -> [Prop] extractProps = \case-  ITE _ _ _ -> []   Success asserts _ _ _ -> asserts   Failure asserts _ _ -> asserts   Partial asserts _ _ -> asserts@@ -669,7 +750,6 @@  extractEndStates :: Expr End -> Map (Expr EAddr) (Expr EContract) extractEndStates = \case-  ITE {} -> mempty   Success _ _ _ contr -> contr   Failure {} -> mempty   Partial  {} -> mempty@@ -694,96 +774,100 @@       e@(Partial _ _ p) -> Just (p, e)       _ -> Nothing ++-- | Symbolically execute the VM and return the representention of the execution+executeVM :: forall m a . App m => Fetch.Fetcher Symbolic m -> IterConfig -> VM Symbolic -> (Expr End -> m a) -> m [a]+executeVM fetcher iterConfig preState handlePath = interpret fetcher iterConfig preState runExpr handlePath+ -- | Symbolically execute the VM and check all endstates against the -- postcondition, if available. verify :: App m   => SolverGroup-  -> Fetch.Fetcher Symbolic m RealWorld+  -> Fetch.Fetcher Symbolic m   -> VeriOpts-  -> VM Symbolic RealWorld-  -> Maybe (Postcondition RealWorld)-  -> m (Expr End, [VerifyResult])-verify solvers fetcher opts preState maybepost = do-  (expr, res, _) <- verifyInputs solvers opts fetcher preState maybepost-  pure $ verifyResults preState expr res+  -> VM Symbolic+  -> Postcondition+  -> Maybe (VM Symbolic -> SMTResult -> Expr End -> m ())+  -> m ([Expr End], [VerifyResult])+verify solvers fetcher opts preState post cexHandler = do+  (ends1, partials) <- verifyInputsWithHandler solvers opts fetcher preState post cexHandler+  let (ends2, results) = unzip $ map (verifyResult preState) ends1+  pure (ends2 <> fmap snd partials, filter (not . isQed) results) -verifyResults :: VM Symbolic RealWorld -> Expr End -> [(SMTResult, Expr End)] -> (Expr End, [VerifyResult])-verifyResults preState expr cexs = if null cexs then (expr, [Qed]) else (expr, fmap toVRes cexs)+verifyResult :: VM Symbolic-> (SMTResult, Expr End) -> (Expr End, VerifyResult)+verifyResult preState res = (snd res, toVRes res)   where     toVRes :: (SMTResult, Expr End) -> VerifyResult-    toVRes (res, leaf) = case res of+    toVRes (res2, leaf) = case res2 of       Cex model -> Cex (leaf, expandCex preState model)       Unknown reason -> Unknown (reason, leaf)       Error e -> Error e       Qed -> Qed --- | Symbolically execute the VM and find possible inputs given the--- postcondition, if available.-verifyInputs+-- | Symbolically execute the VM with optional custom handler for immediate Cex processing+verifyInputsWithHandler   :: App m   => SolverGroup   -> VeriOpts-  -> Fetch.Fetcher Symbolic m RealWorld-  -> VM Symbolic RealWorld-  -> Maybe (Postcondition RealWorld)-  -> m (Expr End, [(SMTResult, Expr End)], [(PartialExec, Expr End)])-verifyInputs solvers opts fetcher preState maybepost = do+  -> Fetch.Fetcher Symbolic m+  -> VM Symbolic+  -> Postcondition+  -> Maybe (VM Symbolic -> SMTResult -> Expr End -> m ())+  -> m ([(SMTResult, Expr End)], [(PartialExec, Expr End)])+verifyInputsWithHandler solvers opts fetcher preState post cexHandler = do   conf <- readConfig   let call = mconcat ["prefix 0x", getCallPrefix preState.state.calldata]-  when conf.debug $ liftIO $ putStrLn $ "   Exploring call " <> call--  expr <- interpret fetcher opts.iterConf preState runExpr-  when conf.dumpExprs $ liftIO $ T.writeFile "unsimplified.expr" (formatExpr expr)-  let flattened = flattenExpr expr-  when (conf.dumpExprs && conf.simp) $ liftIO $ do-    let exprSimplified = Expr.simplify expr-    T.writeFile "simplified.expr" (formatExpr exprSimplified)-    T.writeFile "simplified-conc.expr" (formatExpr $ Expr.simplify $ mapExpr Expr.concKeccakOnePass exprSimplified)--  let partials = getPartials flattened   when conf.debug $ liftIO $ do-    putStrLn "   Flattening expression"-    printPartialIssues flattened ("the call " <> call)-    putStrLn $ "   Exploration finished, " <> show (Expr.numBranches expr) <> " branch(es) to check in call " <> call     putStrLn $ "   Keccak preimages in state: " <> (show $ length preState.keccakPreImgs)-  case maybepost of-    Nothing -> pure (expr, [(Qed, expr)], partials)-    Just post -> do-      let-        -- Filter out any leaves from `flattened` that can be statically shown to be safe-        tocheck = flip map flattened $ \leaf -> (toProps leaf preState post, leaf)-        withQueries = filter canBeSat tocheck-      when conf.debug $ liftIO $ putStrLn $ "   Checking for reachability of " <> show (length withQueries)-        <> " potential property violation(s) in call " <> call+    putStrLn $ "   Exploring call " <> call -      -- Dispatch the remaining branches to the solver to check for violations-      results <- withRunInIO $ \env -> flip mapConcurrently withQueries $ \(query, leaf) -> do-        res <- env $ checkSatWithProps solvers query-        when conf.debug $ putStrLn $ "   SMT result: " <> show res+  results <- executeVM fetcher opts.iterConf preState $ \leaf -> do+    -- Extract partial if applicable+    let mPartial = case leaf of+          Partial _ _ p -> Just (p, leaf)+          _ -> Nothing++    -- Check if this leaf needs SMT checking+    let props = toProps leaf preState.keccakPreImgs post+    smtResult <- if canBeSat (props, leaf)+      then do+        res <- checkSatWithProps solvers props+        when (conf.debug && conf.verb >=2) $ liftIO $ putStrLn $ "   Checking leaf with props: " <> show props <> " SMT result: " <> show res+        -- Call custom handler if provided (for immediate Cex processing/validation/printing)+        case (cexHandler, res) of+          (Just handler, cex@(Cex _)) -> handler preState cex leaf+          _ -> pure ()         pure (res, leaf)-      let cexs = filter (\(res, _) -> not . isQed $ res) results-      when conf.debug $ liftIO $-        putStrLn $ "   Found " <> show (length cexs) <> " potential counterexample(s) in call " <> call-      pure (expr, cexs, partials)+      else pure (Qed, leaf)+    pure (smtResult, mPartial)++  let (smtResults, partials) = unzip results+  when conf.debug $ liftIO $ do+    putStrLn $ "   Exploration and solving finished, " <> show (length results) <> " branch(es) checked in call " <> call <> " of which partial: "+                <> show (length smtResults)+    let cexs = filter (\(res, _) -> not . isQed $ res) smtResults+    putStrLn $ "   Found " <> show (length cexs) <> " counterexample(s) in call " <> call++  pure (smtResults, catMaybes partials)   where     getCallPrefix :: Expr Buf -> String     getCallPrefix (WriteByte (Lit 0) (LitByte a) (WriteByte (Lit 1) (LitByte b) (WriteByte (Lit 2) (LitByte c) (WriteByte (Lit 3) (LitByte d) _)))) = mconcat $ map (printf "%02x") [a,b,c,d]     getCallPrefix _ = "unknown"-    toProps leaf vm post = let-      postCondition = post preState leaf-      keccakConstraints = map (\(bs, k)-> PEq (Keccak (ConcreteBuf bs)) (Lit k)) (Set.toList vm.keccakPreImgs)+    toProps leaf keccakPreImgs post' = let+      postCondition = post' preState leaf+      keccakConstraints = map (\(bs, k)-> PEq (Keccak (ConcreteBuf bs)) (Lit k)) (Set.toList keccakPreImgs)      in case postCondition of       PBool True -> [PBool False]-      _ -> PNeg postCondition : vm.constraints <> extractProps leaf <> keccakConstraints+      _ -> PNeg postCondition : extractProps leaf <> keccakConstraints      canBeSat (a, _) = case a of         [PBool False] -> False         _ -> True -expandCex :: VM Symbolic s -> SMTCex -> SMTCex+expandCex :: VM Symbolic -> SMTCex -> SMTCex expandCex prestate c = c { store = Map.union c.store concretePreStore }   where-    concretePreStore = Map.mapMaybe (maybeConcStoreSimp . (.storage))+    concretePreStore = Map.mapMaybe (Expr.maybeConcStoreSimp . (.storage))                      . Map.filter (\v -> Expr.containsNode isConcreteStore v.storage)                      $ (prestate.env.contracts)     isConcreteStore = \case@@ -813,13 +897,14 @@ equivalenceCheck   :: forall m . App m   => SolverGroup+  -> Maybe Fetch.Session   -> ByteString   -> ByteString   -> VeriOpts   -> (Expr Buf, [Prop])   -> Bool   -> m EqIssues-equivalenceCheck solvers bytecodeA bytecodeB opts calldata create = do+equivalenceCheck solvers sess bytecodeA bytecodeB opts calldata create = do   conf <- readConfig   case bytecodeA == bytecodeB of     True -> liftIO $ do@@ -840,24 +925,16 @@       let branchesA = rewriteFresh "A-" branchesAorig           branchesB = rewriteFresh "B-" branchesBorig       let partialIssues = EqIssues mempty (filter isPartial branchesA <> filter isPartial branchesB)-      issues <- equivalenceCheck' solvers branchesA branchesB create-      pure $ oneQedOrNoQed issues <> partialIssues+      issues <- equivalenceCheck' solvers sess branchesA branchesB create+      pure $ filterQeds (issues <> partialIssues)   where     -- decompiles the given bytecode into a list of branches     getBranches :: App m => ByteString -> m [Expr End]     getBranches bs = do-      conf <- readConfig       let bytecode = if BS.null bs then BS.pack [0] else bs       prestate <- liftIO $ stToIO $ abstractVM calldata bytecode Nothing create-      expr <- interpret (Fetch.oracle solvers Nothing mempty) opts.iterConf prestate runExpr-      let simpl = if conf.simp then Expr.simplify expr else expr-      pure $ flattenExpr simpl-    oneQedOrNoQed :: EqIssues -> EqIssues-    oneQedOrNoQed (EqIssues res partials) =-      let allQed = all (\(r, _) -> isQed r) res-      in if allQed then EqIssues [(Qed, "")] partials-          else EqIssues (filter (\(r, _) -> not $ isQed r) res) partials-+      interpret (Fetch.oracle solvers sess Fetch.noRpc) opts.iterConf prestate runExpr pure+    filterQeds (EqIssues res partials) = EqIssues (filter (\(r, _) -> not . isQed $ r) res) partials  rewriteFresh :: Text -> [Expr a] -> [Expr a] rewriteFresh prefix exprs = fmap (mapExpr mymap) exprs@@ -871,8 +948,8 @@  equivalenceCheck'   :: forall m . App m-  => SolverGroup -> [Expr End] -> [Expr End] -> Bool -> m EqIssues-equivalenceCheck' solvers branchesA branchesB create = do+  => SolverGroup -> Maybe Fetch.Session -> [Expr End] -> [Expr End] -> Bool -> m EqIssues+equivalenceCheck' solvers sess branchesA branchesB create = do       conf <- readConfig       when conf.debug $ do         liftIO $ printPartialIssues branchesA "codeA"@@ -972,8 +1049,6 @@         -- partial end states can't be compared to actual end states, so we always ignore them         (Partial {}, _) -> pure (Nothing, mempty)         (_, Partial {}) -> pure (Nothing, mempty)-        (ITE _ _ _, _) -> internalError "Expressions must be flattened"-        (_, ITE _ _ _) -> internalError "Expressions must be flattened"         (GVar _, _) -> internalError "GVar in equivalence check"         (_, GVar _) -> internalError "GVar in equivalence check" @@ -1005,7 +1080,7 @@             liftIO $ putStrLn $ "create deployed code B: " <> bsToHex codeB               <> " with constraints: " <> (T.unpack . T.unlines $ map formatProp bProps)           calldata <- mkCalldata Nothing []-          equivalenceCheck solvers codeA codeB defaultVeriOpts calldata False+          equivalenceCheck solvers sess codeA codeB defaultVeriOpts calldata False         _ -> internalError $ "Symbolic code returned from constructor." <> " A: " <> show simpA <> " B: " <> show simpB      statesDiffer :: Map (Expr EAddr) (Expr EContract) -> Map (Expr EAddr) (Expr EContract) -> Prop@@ -1035,10 +1110,9 @@ both' :: (a -> b) -> (a, a) -> (b, b) both' f (x, y) = (f x, f y) -produceModels :: App m => SolverGroup -> Expr End -> m [(Expr End, SMTResult)]-produceModels solvers expr = do-  let flattened = flattenExpr expr-      withQueries = fmap (\e -> (extractProps e, e)) flattened+produceModels :: App m => SolverGroup -> [Expr End] -> m [(Expr End, SMTResult)]+produceModels solvers exprs = do+  let withQueries = fmap (\e -> (extractProps e, e)) exprs   results <- withRunInIO $ \runInIO -> (flip mapConcurrently) withQueries $ \(query, leaf) -> do     res <- runInIO $ checkSatWithProps solvers query     pure (res, leaf)@@ -1158,7 +1232,7 @@  calldataFromCex :: App m => SMTCex -> Expr Buf -> Sig -> m (Err ByteString) calldataFromCex cex buf sig = do-  let sigKeccak = keccakSig $ encodeUtf8 (callSig sig)+  let sigKeccak = BS.take 4 $ keccakBytes $ encodeUtf8 (callSig sig)   pure $ (sigKeccak <>) <$> body   where     cd = defaultSymbolicValues $ subModel cex buf@@ -1169,8 +1243,6 @@     forceConcrete :: (Expr Buf) -> Err ByteString     forceConcrete (ConcreteBuf k) = Right k     forceConcrete _ = Left "Symbolic buffer in calldata, cannot produce concrete model"-    keccakSig :: ByteString -> ByteString-    keccakSig = keccakBytes >>> BS.take 4  prettyCalldata :: SMTCex -> Expr Buf -> Text -> [AbiType] -> Text prettyCalldata cex buf sig types = headErr errSig (T.splitOn "(" sig) <> "(" <> body <> ")" <> T.pack finalErr
src/EVM/Tracing.hs view
@@ -15,7 +15,7 @@ import Optics.State  import Control.Monad.IO.Class-import Control.Monad.ST (stToIO, RealWorld)+import Control.Monad.ST (stToIO) import Data.Aeson qualified as JSON import Data.Word (Word8, Word64) import GHC.Generics (Generic)@@ -70,14 +70,14 @@ instance JSON.ToJSON VMTraceStepResult where   toEncoding = JSON.genericToEncoding JSON.defaultOptions -type TraceState s = (VM Concrete s, [VMTraceStep])+type TraceState = (VM Concrete, [VMTraceStep]) -execWithTrace :: App m => StateT (TraceState RealWorld) m (VMResult Concrete RealWorld)+execWithTrace :: App m => StateT (TraceState) m (VMResult Concrete) execWithTrace = do   _ <- runWithTrace   fromJust <$> use (_1 % #result) -runWithTrace :: App m => StateT (TraceState RealWorld) m (VM Concrete RealWorld)+runWithTrace :: App m => StateT (TraceState) m (VM Concrete) runWithTrace = do   -- This is just like `exec` except for every instruction evaluated,   -- we also increment a counter indexed by the current code location.@@ -100,16 +100,16 @@  interpretWithTrace   :: forall m a . App m-  => Fetch.Fetcher Concrete m RealWorld-  -> Stepper Concrete RealWorld a-  -> StateT (TraceState RealWorld) m a+  => Fetch.Fetcher Concrete m+  -> Stepper Concrete a+  -> StateT TraceState m a interpretWithTrace fetcher =   eval . Operational.view   where     eval       :: App m-      => Operational.ProgramView (Action Concrete RealWorld) a-      -> StateT (TraceState RealWorld) m a+      => Operational.ProgramView (Action Concrete) a+      -> StateT TraceState m a     eval (Operational.Return x) = pure x     eval (action Operational.:>>= k) =       case action of@@ -127,7 +127,7 @@           assign _1 vm'           interpretWithTrace fetcher (k r) -vmTraceStep :: VM Concrete s -> VMTraceStep+vmTraceStep :: VM Concrete -> VMTraceStep vmTraceStep vm =   let     memsize = vm.state.memorySize@@ -143,11 +143,11 @@     , error = readoutError vm.result     }   where-    readoutError :: Maybe (VMResult t s) -> Maybe String+    readoutError :: Maybe (VMResult t) -> Maybe String     readoutError (Just (VMFailure e)) = Just $ evmErrToString e     readoutError _ = Nothing -getOpFromVM :: VM t s -> Word8+getOpFromVM :: VM t -> Word8 getOpFromVM vm =   let pcpos  = vm ^. #state % #pc       code' = vm ^. #state % #code
src/EVM/Transaction.hs view
@@ -254,7 +254,7 @@ -- | Given a valid tx loaded into the vm state, -- subtract gas payment from the origin, increment the nonce -- and pay receiving address-initTx :: VM t s -> VM t s+initTx :: VM t -> VM t initTx vm =   let     toAddr   = vm.state.contract
src/EVM/Traversals.hs view
@@ -96,7 +96,6 @@       e@(Failure a _ (Revert c)) -> f e <> (foldl' (foldProp f) mempty a) <> go c       e@(Failure a _ _) -> f e <> (foldl' (foldProp f) mempty a)       e@(Partial a _ _) -> f e <> (foldl' (foldProp f) mempty a)-      e@(ITE a b c) -> f e <> (go a) <> (go b) <> (go c)        -- integers @@ -358,11 +357,6 @@         pure (k',v')       pure $ Map.fromList x'     f (Success a' b c' d')-  ITE a b c -> do-    a' <- mapExprM f a-    b' <- mapExprM f b-    c' <- mapExprM f c-    f (ITE a' b' c')    -- integers 
src/EVM/Types.hs view
@@ -17,7 +17,7 @@ import GHC.ByteOrder (targetByteOrder, ByteOrder(..)) import Control.Arrow ((>>>)) import Control.Monad (mzero)-import Control.Monad.ST (ST)+import Control.Monad.ST (ST, RealWorld) import Control.Monad.State.Strict (StateT) import Crypto.Hash (hash, Keccak_256, Digest) import Data.Aeson qualified as JSON@@ -231,7 +231,6 @@   Partial        :: [Prop] -> TraceContext -> PartialExec -> Expr End   Failure        :: [Prop] -> TraceContext -> EvmError -> Expr End   Success        :: [Prop] -> TraceContext -> Expr Buf -> Map (Expr EAddr) (Expr EContract) -> Expr End-  ITE            :: Expr EWord -> Expr End -> Expr End -> Expr End    -- integers @@ -598,34 +597,29 @@   deriving (Show, Eq, Ord)  -- | Effect types used by the vm implementation for side effects & control flow-data Effect t s where-  Query :: Query t s -> Effect t s-  RunBoth :: RunBoth s -> Effect Symbolic s-  RunAll :: RunAll s -> Effect Symbolic s-deriving instance Show (Effect t s)+data Effect t where+  Query :: Query t -> Effect t+  Branch :: BranchContext -> Effect Symbolic+deriving instance Show (Effect t)  -- | Queries halt execution until resolved through RPC calls or SMT queries-data Query t s where-  PleaseFetchContract :: Addr -> BaseState -> (Contract -> EVM t s ()) -> Query t s-  PleaseFetchSlot     :: Addr -> W256 -> (W256 -> EVM t s ()) -> Query t s-  PleaseAskSMT        :: Expr EWord -> [Prop] -> (BranchCondition -> EVM Symbolic s ()) -> Query Symbolic s-  PleaseGetSols       :: Expr EWord -> Int -> [Prop] -> (Maybe [W256] -> EVM Symbolic s ()) -> Query Symbolic s-  PleaseDoFFI         :: [String] -> Map String String -> (ByteString -> EVM t s ()) -> Query t s-  PleaseReadEnv       :: String -> (String -> EVM t s ()) -> Query t s---- | Execution could proceed down one of two branches-data RunBoth s where-  PleaseRunBoth    :: Expr EWord -> (Bool -> EVM Symbolic s ()) -> RunBoth s+data Query t where+  PleaseFetchContract :: Addr -> BaseState -> (Contract -> EVM t ()) -> Query t+  PleaseFetchSlot     :: Addr -> W256 -> (W256 -> EVM t ()) -> Query t+  PleaseAskSMT        :: Expr EWord -> [Prop] -> (BranchCondition -> EVM Symbolic ()) -> Query Symbolic+  PleaseGetSols       :: Expr EWord -> Int -> [Prop] -> (Maybe [W256] -> EVM Symbolic ()) -> Query Symbolic+  PleaseDoFFI         :: [String] -> Map String String -> (ByteString -> EVM t ()) -> Query t+  PleaseReadEnv       :: String -> (String -> EVM t ()) -> Query t --- | Execution could proceed down one of several branches-data RunAll s where-  PleaseRunAll    :: Expr EWord -> [Expr EWord] -> (Expr EWord -> EVM Symbolic s ()) -> RunAll s+data BranchContext where+  PleaseRunBoth :: (Bool -> EVM Symbolic ()) -> BranchContext+  PleaseRunAll  :: [Expr EWord] -> (Expr EWord -> EVM Symbolic ()) -> BranchContext  -- | The possible return values of a SMT query data BranchCondition = Case Bool | UnknownBranch   deriving Show -instance Show (Query t s) where+instance Show (Query t) where   showsPrec _ = \case     PleaseFetchContract addr base _ ->       (("<EVM.Query: fetch contract " ++ show addr ++ show base ++ ">") ++)@@ -648,24 +642,22 @@     PleaseReadEnv variable _ ->       (("<EVM.Query: read env: " ++ variable) ++) -instance Show (RunBoth s) where+instance Show (BranchContext) where   showsPrec _ = \case-    PleaseRunBoth _ _ ->+    PleaseRunBoth _ ->       (("<EVM.RunBoth: system running both paths") ++) -instance Show (RunAll s) where-  showsPrec _ = \case-    PleaseRunAll _ _ _ ->+    PleaseRunAll _ _ ->       (("<EVM.RunAll: system running all paths for Expr EWord-s") ++)  -- | The possible result states of a VM-data VMResult (t :: VMType) s where-  Unfinished :: PartialExec -> VMResult Symbolic s -- ^ Execution could not continue further-  VMFailure :: EvmError -> VMResult t s            -- ^ An operation failed-  VMSuccess :: (Expr Buf) -> VMResult t s          -- ^ Reached STOP, RETURN, or end-of-code-  HandleEffect :: (Effect t s) -> VMResult t s     -- ^ An effect must be handled for execution to continue+data VMResult (t :: VMType) where+  Unfinished :: PartialExec -> VMResult Symbolic -- ^ Execution could not continue further+  VMFailure :: EvmError -> VMResult t            -- ^ An operation failed+  VMSuccess :: (Expr Buf) -> VMResult t          -- ^ Reached STOP, RETURN, or end-of-code+  HandleEffect :: (Effect t) -> VMResult t     -- ^ An effect must be handled for execution to continue -deriving instance Show (VMResult t s)+deriving instance Show (VMResult t)   -- VM State ----------------------------------------------------------------------------------------@@ -677,10 +669,10 @@   Gas Concrete = Word64  -- | The state of a stepwise EVM execution-data VM (t :: VMType) s = VM-  { result         :: Maybe (VMResult t s)-  , state          :: FrameState t s-  , frames         :: [Frame t s]+data VM (t :: VMType) = VM+  { result         :: Maybe (VMResult t)+  , state          :: FrameState t+  , frames         :: [Frame t]   , env            :: Env   , block          :: Block   , tx             :: TxState@@ -712,11 +704,11 @@   }   deriving (Show, Generic) -deriving instance Show (VM Symbolic s)-deriving instance Show (VM Concrete s)+deriving instance Show (VM Symbolic)+deriving instance Show (VM Concrete)  -- | Alias for the type of e.g. @exec1@.-type EVM (t :: VMType) s a = StateT (VM t s) (ST s) a+type EVM (t :: VMType) a = StateT (VM t) (ST RealWorld) a  -- | The VM base state (i.e. should new contracts be created with abstract balance / storage?) data BaseState@@ -732,13 +724,13 @@   deriving (Show)  -- | An entry in the VM's "call/create stack"-data Frame (t :: VMType) s = Frame+data Frame (t :: VMType) = Frame   { context :: FrameContext-  , state   :: FrameState t s+  , state   :: FrameState t   } -deriving instance Show (Frame Symbolic s)-deriving instance Show (Frame Concrete s)+deriving instance Show (Frame Symbolic)+deriving instance Show (Frame Concrete)  -- | Call/create info data FrameContext@@ -774,13 +766,13 @@   deriving (Eq, Ord, Show)  -- | The "registers" of the VM along with memory and data stack-data FrameState (t :: VMType) s = FrameState+data FrameState (t :: VMType) = FrameState   { contract     :: Expr EAddr   , codeContract :: Expr EAddr   , code         :: ContractCode   , pc           :: {-# UNPACK #-} !Int -- program counter in BYTES (not ops). PUSH ops will increment pc by more than 1   , stack        :: [Expr EWord]-  , memory       :: Memory s+  , memory       :: Memory   , memorySize   :: Word64   , calldata     :: Expr Buf   , callvalue    :: Expr EWord@@ -793,18 +785,18 @@   }   deriving (Generic) -deriving instance Show (FrameState Symbolic s)-deriving instance Show (FrameState Concrete s)+deriving instance Show (FrameState Symbolic)+deriving instance Show (FrameState Concrete) -data Memory s-  = ConcreteMemory (MutableMemory s)+data Memory+  = ConcreteMemory (MutableMemory)   | SymbolicMemory !(Expr Buf) -instance Show (Memory s) where+instance Show (Memory) where   show (ConcreteMemory _) = "<can't show mutable memory>"   show (SymbolicMemory m) = show m -type MutableMemory s = STVector s Word8+type MutableMemory = STVector RealWorld Word8  -- | The state that spans a whole transaction data TxState = TxState@@ -857,18 +849,18 @@   deriving (Show, Eq, Ord)  class VMOps (t :: VMType) where-  burn' :: Gas t -> EVM t s () -> EVM t s ()+  burn' :: Gas t -> EVM t () -> EVM t ()   -- TODO: change to EvmWord t-  burnExp :: Expr EWord -> EVM t s () -> EVM t s ()-  burnSha3 :: Expr EWord -> EVM t s () -> EVM t s ()-  burnCalldatacopy :: Expr EWord -> EVM t s () -> EVM t s ()-  burnCodecopy :: Expr EWord -> EVM t s () -> EVM t s ()-  burnExtcodecopy :: Expr EAddr -> Expr EWord -> EVM t s () -> EVM t s ()-  burnReturndatacopy :: Expr EWord -> EVM t s () -> EVM t s ()-  burnLog :: Expr EWord -> Word8 -> EVM t s () -> EVM t s ()+  burnExp :: Expr EWord -> EVM t () -> EVM t ()+  burnSha3 :: Expr EWord -> EVM t () -> EVM t ()+  burnCalldatacopy :: Expr EWord -> EVM t () -> EVM t ()+  burnCodecopy :: Expr EWord -> EVM t () -> EVM t ()+  burnExtcodecopy :: Expr EAddr -> Expr EWord -> EVM t () -> EVM t ()+  burnReturndatacopy :: Expr EWord -> EVM t () -> EVM t ()+  burnLog :: Expr EWord -> Word8 -> EVM t () -> EVM t ()    initialGas :: Gas t-  ensureGas :: Word64 -> EVM t s () -> EVM t s ()+  ensureGas :: Word64 -> EVM t () -> EVM t ()   -- TODO: change to EvmWord t   gasTryFrom :: Expr EWord -> Either () (Gas t) @@ -877,20 +869,20 @@    costOfCall     :: FeeSchedule Word64 -> Bool -> Expr EWord -> Gas t -> Gas t -> Expr EAddr-    -> (Word64 -> Word64 -> EVM t s ()) -> EVM t s ()+    -> (Word64 -> Word64 -> EVM t ()) -> EVM t () -  reclaimRemainingGasAllowance :: VM t s -> EVM t s ()-  payRefunds :: EVM t s ()-  pushGas :: EVM t s ()+  reclaimRemainingGasAllowance :: VM t -> EVM t ()+  payRefunds :: EVM t ()+  pushGas :: EVM t ()   enoughGas :: Word64 -> Gas t -> Bool   subGas :: Gas t -> Word64 -> Gas t   toGas :: Word64 -> Gas t -  whenSymbolicElse :: EVM t s a -> EVM t s a -> EVM t s a+  whenSymbolicElse :: EVM t a -> EVM t a -> EVM t a -  partial :: PartialExec -> EVM t s ()-  branch :: Maybe Int -> Expr EWord -> (Bool -> EVM t s ()) -> EVM t s ()-  manySolutions :: Maybe Int -> Expr EWord -> Int -> (Maybe W256 -> EVM t s ()) -> EVM t s ()+  partial :: PartialExec -> EVM t ()+  branch :: Maybe Int -> Expr EWord -> (Bool -> EVM t ()) -> EVM t ()+  manySolutions :: Maybe Int -> Expr EWord -> Int -> (Maybe W256 -> EVM t ()) -> EVM t ()  -- Bytecode Representations ------------------------------------------------------------------------ @@ -1237,7 +1229,9 @@         T.decodeUtf8 . toStrict . toLazyByteString . byteStringHex  instance JSON.FromJSON ByteStringS where-  parseJSON (JSON.String x) = case BS16.decodeBase16Untyped (T.encodeUtf8 x) of+  parseJSON (JSON.String x) =+    let x' = if "0x" `T.isPrefixOf` x then T.drop 2 x else x in+    case BS16.decodeBase16Untyped (T.encodeUtf8 x') of                                 Left _ -> mzero                                 Right bs -> pure (ByteStringS bs)   parseJSON _ = mzero
src/EVM/UnitTest.hs view
@@ -15,7 +15,7 @@ import EVM.Fetch qualified as Fetch import EVM.Format import EVM.Solidity-import EVM.SymExec (defaultVeriOpts, symCalldata, verify, extractCex, prettyCalldata, calldataFromCex, panicMsg, VeriOpts(..), flattenExpr, groupIssues, groupPartials, IterConfig(..), defaultIterConf, LoopHeuristic)+import EVM.SymExec (defaultVeriOpts, symCalldata, verify, verifyResult, extractCex, prettyCalldata, calldataFromCex, panicMsg, VeriOpts(..), groupIssues, groupPartials, IterConfig(..), LoopHeuristic, defaultIterConf) import EVM.Types import EVM.Transaction (initTx) import EVM.Stepper (Stepper)@@ -50,7 +50,7 @@ import Data.Vector qualified as V import Data.Char (ord) -data UnitTestOptions s = UnitTestOptions+data UnitTestOptions = UnitTestOptions   { rpcInfo       :: Fetch.RpcInfo   , solvers       :: SolverGroup   , sess          :: Fetch.Session@@ -100,18 +100,18 @@ type ABIMethod = Text  -- | Used in various places for dumping traces-writeTraceDapp :: App m => DappInfo -> VM t RealWorld -> m ()+writeTraceDapp :: App m => DappInfo -> VM t -> m () writeTraceDapp dapp vm = do   conf <- readConfig   liftIO $ when conf.dumpTrace $ Text.writeFile "VM.trace" (showTraceTree dapp vm) -writeTrace :: App m => VM t RealWorld -> m ()+writeTrace :: App m => VM t -> m () writeTrace vm = do   conf <- readConfig   liftIO $ when conf.dumpTrace $ writeFile "VM.trace" (show $ traceForest vm)  -- | Generate VeriOpts from UnitTestOptions-makeVeriOpts :: UnitTestOptions s -> VeriOpts+makeVeriOpts :: UnitTestOptions -> VeriOpts makeVeriOpts opts =    defaultVeriOpts { iterConf = defaultIterConf {maxIter = opts.maxIter, askSmtIters = opts.askSmtIters, loopHeuristic = opts.loopHeuristic}                    , rpcInfo = opts.rpcInfo@@ -119,7 +119,7 @@  -- | Top level CLI endpoint for hevm test -- | Returns tuple of (No Cex, No warnings)-unitTest :: App m => UnitTestOptions RealWorld -> BuildOutput -> m (Bool, Bool)+unitTest :: App m => UnitTestOptions -> BuildOutput -> m (Bool, Bool) unitTest opts bo@(BuildOutput (Contracts cs) _) = do   let unitTestContrs = findUnitTests opts.prefix opts.match $ Map.elems cs   conf <- readConfig@@ -134,7 +134,7 @@  -- | Assuming a constructor is loaded, this stepper will run the constructor -- to create the test contract, give it an initial balance, and run `setUp()'.-initializeUnitTest :: UnitTestOptions s -> SolcContract -> Stepper Concrete s ()+initializeUnitTest :: UnitTestOptions -> SolcContract -> Stepper Concrete () initializeUnitTest opts theContract = do   let addr = opts.testParams.address @@ -164,9 +164,9 @@     _ -> popTrace  validateCex :: forall m . App m-  => UnitTestOptions RealWorld-  -> Fetch.Fetcher Concrete m RealWorld-  -> VM Concrete RealWorld+  => UnitTestOptions+  -> Fetch.Fetcher Concrete m+  -> VM Concrete   -> ReproducibleCex   -> m Bool validateCex uTestOpts fetcher vm repCex = do@@ -203,7 +203,7 @@ -- Returns tuple of (No Cex, No warnings) runUnitTestContract   :: App m-  => UnitTestOptions RealWorld+  => UnitTestOptions   -> BuildOutput   -> (Text, [Sig])   -> m [(Bool, Bool)]@@ -216,7 +216,7 @@     Nothing -> internalError $ "Contract " ++ unpack name ++ " not found"     Just solcContr -> do       -- Construct the initial VM and begin the contract's constructor-      vm0 :: VM Concrete RealWorld <- liftIO $ stToIO $ initialUnitTestVm opts solcContr+      vm0 :: VM Concrete <- liftIO $ stToIO $ initialUnitTestVm opts solcContr       vm1 <- Stepper.interpret (Fetch.oracle solvers (Just sess) rpcInfo) vm0 $ do         Stepper.enter name         initializeUnitTest opts solcContr@@ -233,7 +233,7 @@           forM testSigs $ \s -> symRun opts vm1 s solcContr buildOut.sources         _ -> internalError "setUp() did not end with a result" -dsTestFailedSym :: Map (Expr 'EAddr) (Expr EContract) -> VM s t -> Prop+dsTestFailedSym :: Map (Expr 'EAddr) (Expr EContract) -> VM t -> Prop dsTestFailedSym store vm =   let testContract = fromMaybe (internalError "test contract not found in state") (Map.lookup vm.state.contract store)   in case Map.lookup cheatCode store of@@ -247,7 +247,7 @@  -- Define the thread spawner for symbolic tests -- Returns tuple of (No Cex, No warnings)-symRun :: App m => UnitTestOptions RealWorld -> VM Concrete RealWorld -> Sig -> SolcContract -> SourceCache -> m (Bool, Bool)+symRun :: forall m . App m => UnitTestOptions -> VM Concrete -> Sig -> SolcContract -> SourceCache -> m (Bool, Bool) symRun opts@UnitTestOptions{..} vm sig@(Sig testName types) solcContr sourceCache = do     let cs = callSig sig     liftIO $ putStrLn $ "\x1b[96m[RUNNING]\x1b[0m " <> Text.unpack cs@@ -285,33 +285,29 @@      -- check postconditions against vm     let fetcherSym = Fetch.oracle solvers (Just sess) rpcInfo-    (end, results) <- verify solvers fetcherSym (makeVeriOpts opts) (symbolify vm') (Just postcondition)-    let ends = flattenExpr end+    (ends, results) <- verify solvers fetcherSym (makeVeriOpts opts) (symbolify vm') postcondition (Just $ cexHandler cd fetcherConc)     conf <- readConfig-    when conf.debug $ liftIO $ forM_ (filter Expr.isFailure ends) $ \case-      (Failure _ _ a) ->  putStrLn $ "   -> debug of func: " <> Text.unpack testName <> " Failure at the end of expr: " <> show a;-      _ -> internalError "cannot be, filtered for failure"+    when (conf.debug) $ liftIO $ do+      putStrLn $ "   \x1b[94m[EXPLORATION COMPLETE]\x1b[0m " <> Text.unpack testName <> " -- explored " <> show (length ends) <> " paths."+      when (conf.verb >= 2) $ do+        forM_ (filter Expr.isFailure ends) $ \case+          (Failure _ _ a) ->  putStrLn $ "   -> debug of func: " <> Text.unpack testName <> " Failure at the end of expr: " <> show a;+          _ -> internalError "cannot be, filtered for failure"      -- display results+    when (conf.debug && conf.verb >=2) $ liftIO $ do+      putStrLn $ "Collected END-s:\n" <> prettyvmresults ends+      putStrLn $ "Collected verification results: " <> show results     let warnings = any Expr.isPartial ends || any isUnknown results || any isError results     let allReverts = not . (any Expr.isSuccess) $ ends     let unexpectedAllRevert = allReverts && not shouldFail-    when conf.debug $ liftIO $ putStrLn $ "symRun -- (cex,warnings,unexpectedAllRevert): " <> show (any isCex results, warnings, unexpectedAllRevert)+    when conf.debug $ liftIO $ putStrLn $ "   symRun -- (cex,warnings,unexpectedAllRevert): " <> show (any isCex results, warnings, unexpectedAllRevert)     txtResult <- case (any isCex results, warnings, unexpectedAllRevert) of       (False, False, False) -> do         -- happy case         pure $ "   \x1b[32m[PASS]\x1b[0m " <> Text.unpack testName <> "\n"       (True, _, _) -> do-        -- there are counterexamples (and maybe other things, but Cex is most important)-        let x = mapMaybe extractCex results-        failsToRepro <- getReproFailures (Sig testName types) (fst cd) (map snd x)---        validation <- mapM (traverse $ validateCex opts fetcherConc vm) failsToRepro-        when conf.debug $ liftIO $ putStrLn $ "Cex reproduction runs' results are: " <> show validation-        let toPrintData = zipWith (\(a, b) c -> (a, b, c)) x validation-        txtFails <- symFailure opts testName (fst cd) types toPrintData-        pure $ "   \x1b[31m[FAIL]\x1b[0m " <> Text.unpack testName <> "\n" <> Text.unpack txtFails+        pure $ "   \x1b[31m[FAIL]\x1b[0m " <> Text.unpack testName <> "\n"       (_, True, _) -> do         -- There are errors/unknowns/partials, we fail them         pure $ "   \x1b[31m[FAIL]\x1b[0m " <> Text.unpack testName <> "\n"@@ -327,6 +323,22 @@     liftIO $ printWarnings warnData ends results $ "the test " <> Text.unpack testName     pure (not (any isCex results), not (warnings || unexpectedAllRevert))     where+      cexHandler :: (Expr 'Buf, [Prop])+        -> Fetch.Fetcher Concrete m+        -> VM 'Symbolic+        -> SMTResult+        -> Expr 'End+        -> m ()+      cexHandler cd fetcherConc preState smtRes end = do+          let verifRes = snd $ verifyResult preState (smtRes, end)+          case extractCex verifRes of+            Nothing -> internalError "cexHandler: expected a cex"+            Just (cexEnd, smtCex) -> do+              failsToRepro <- getReproFailure (Sig testName types) (fst cd) smtCex+              validation <- traverse (validateCex opts fetcherConc vm) failsToRepro+              txtFail <- symFailure opts testName (fst cd) types (cexEnd, smtCex, validation)+              liftIO $ Text.putStr txtFail+       -- The offset of the text is: the selector (4B), the offset value (aligned to 32B), and the length of the string (aligned to 32B)       txtOffset = 4+32+32       symbolicFail :: Expr Buf -> Prop@@ -352,7 +364,7 @@               lhs = LitByte (c2w a)               rhs = Expr.readByte (Lit (fromIntegral n)) b ---printWarnings :: Maybe (WarningData s t) -> GetUnknownStr b => [Expr 'End] -> [ProofResult a b] -> String -> IO ()+printWarnings :: Maybe (WarningData t) -> GetUnknownStr b => [Expr 'End] -> [ProofResult a b] -> String -> IO () printWarnings warnData e results testName = do   when (any isUnknown results || any isError results || any Expr.isPartial e) $ do     putStrLn $ "   \x1b[33m[WARNING]\x1b[0m hevm was only able to partially explore " <> testName <> " due to: ";@@ -361,20 +373,20 @@     forM_ (groupPartials warnData e) $ \(num, str) -> putStrLn $ "      " <> show num <> "x -> " <> str   putStrLn "" -getReproFailures :: App m => Sig -> Expr Buf -> [SMTCex] -> m [Err ReproducibleCex]-getReproFailures sig@(Sig testName _) cd cexes = do-  fullCDs <- mapM (\cex -> calldataFromCex cex cd sig) cexes-  pure $ map (\case+getReproFailure :: App m => Sig -> Expr Buf -> SMTCex -> m (Err ReproducibleCex)+getReproFailure sig@(Sig testName _) cd cex = do+  bs <- calldataFromCex cex cd sig+  pure $ (\case     Left err -> Left err-    Right fullCD -> Right $ ReproducibleCex { testName = testName, callData = fullCD}) fullCDs+    Right fullCD -> Right $ ReproducibleCex { testName = testName, callData = fullCD}) bs  symFailure :: App m =>-  UnitTestOptions RealWorld -> Text -> Expr Buf -> [AbiType] ->-  [(Expr End, SMTCex, Err Bool)] ->+  UnitTestOptions -> Text -> Expr Buf -> [AbiType] ->+  (Expr End, SMTCex, Err Bool) ->   m Text-symFailure UnitTestOptions {..} testName cd types fails = do+symFailure UnitTestOptions {..} testName cd types failure = do   conf <- readConfig-  pure $ mconcat [ Text.concat $ indentLines 3 . mkMsg conf <$> fails ]+  pure $ mconcat [ indentLines 3 $ mkMsg conf failure ]   where       showRes = \case         Success _ _ _ _ -> if "proveFail" `isPrefixOf` testName@@ -403,7 +415,7 @@   let p = Text.replicate n " "   in Text.unlines (map (p <>) (Text.lines s)) -failOutput :: App m => VM t s -> UnitTestOptions s -> Text -> m Text+failOutput :: App m => VM t -> UnitTestOptions -> Text -> m Text failOutput vm UnitTestOptions { .. } testName = do   conf <- readConfig   let ?context = DappContext { info = dapp@@ -490,14 +502,14 @@                   _ -> Nothing               _ -> Just "<symbolic decimal>" -abiCall :: VMOps t => TestVMParams -> Either (Text, AbiValue) ByteString -> EVM t s ()+abiCall :: VMOps t => TestVMParams -> Either (Text, AbiValue) ByteString -> EVM t () abiCall params args =   let cd = case args of         Left (sig, args') -> abiMethod sig args'         Right b -> b   in makeTxCall params (ConcreteBuf cd, []) -makeTxCall :: VMOps t => TestVMParams -> (Expr Buf, [Prop]) -> EVM t s ()+makeTxCall :: VMOps t => TestVMParams -> (Expr Buf, [Prop]) -> EVM t () makeTxCall params (cd, cdProps) = do   resetState   assign (#tx % #isCreate) False@@ -512,7 +524,7 @@   vm <- get   put $ initTx vm -initialUnitTestVm :: VMOps t => UnitTestOptions s -> SolcContract -> ST s (VM t s)+initialUnitTestVm :: VMOps t => UnitTestOptions -> SolcContract -> ST RealWorld (VM t) initialUnitTestVm (UnitTestOptions {..}) theContract = do   vm <- makeVm $ VMOpts            { contract = initialContract (InitCode theContract.creationCode mempty)@@ -553,15 +565,7 @@   (miner,ts,blockNum,ran,limit,base) <- case rpcInfo.blockNumURL of     Nothing -> pure (SymAddr "miner", Lit 0, Lit 0, 0, 0, 0)     Just (Fetch.Latest, url) -> fetch Fetch.Latest url-    Just (Fetch.BlockNumber block, url) -> case rpcInfo.mockBlock >>= Map.lookup block of-        Nothing -> fetch (Fetch.BlockNumber block) url-        Just b ->pure (b.coinbase-                      , b.timestamp-                      , b.number-                      , b.prevRandao-                      , b.gaslimit-                      , b.baseFee-                      )+    Just (Fetch.BlockNumber block, url) -> fetch (Fetch.BlockNumber block) url   let ts' = fromMaybe (internalError "received unexpected symbolic timestamp via rpc") (maybeLitWordSimp ts)   pure $ TestVMParams     -- TODO: make this symbolic! It needs some tweaking to the way that our
test/EVM/Test/BlockchainTests.hs view
@@ -1,43 +1,36 @@-module EVM.Test.BlockchainTests where+module EVM.Test.BlockchainTests (prepareTests, problematicTests, Case, vmForCase, checkExpectation, allTestCases) where  import EVM (initialContract, makeVm, setEIP4788Storage) import EVM.Concrete qualified as EVM+import EVM.Effects+import EVM.Expr (maybeLitAddrSimp) import EVM.FeeSchedule (feeSchedule) import EVM.Fetch qualified-import EVM.Format (hexText)+import EVM.Solvers (withSolvers, Solver(..)) import EVM.Stepper qualified import EVM.Transaction-import EVM.UnitTest (writeTrace) import EVM.Types hiding (Block, Case, Env)-import EVM.Expr (maybeLitWordSimp, maybeLitAddrSimp)-import EVM.Tracing qualified as Tracing-import EVM.Test.FuzzSymExec (compareTraces, EVMToolTraceOutput(..), decodeTraceOutputHelper)+import EVM.UnitTest (writeTrace)  import Optics.Core import Control.Arrow ((***), (&&&)) import Control.Monad-import Control.Monad.ST (RealWorld, stToIO)+import Control.Monad.ST (stToIO) import Control.Monad.State.Strict import Control.Monad.IO.Unlift-import EVM.Effects import Data.Aeson ((.:), (.:?), FromJSON (..)) import Data.Aeson qualified as JSON import Data.Aeson.Types qualified as JSON import Data.ByteString qualified as BS import Data.ByteString.Lazy qualified as Lazy-import Data.ByteString.Lazy qualified as LazyByteString-import Data.List (isInfixOf, isPrefixOf) import Data.Map (Map) import Data.Map qualified as Map import Data.Maybe (fromJust, fromMaybe, isNothing, isJust) import Data.Word (Word64)-import System.Environment (lookupEnv, getEnv)+import GHC.Generics (Generic)+import System.Environment (getEnv) import System.FilePath.Find qualified as Find import System.FilePath.Posix (makeRelative, (</>))-import System.IO (hPutStr, hClose)-import System.IO.Temp (withSystemTempFile)-import System.Process (readProcessWithExitCode)-import GHC.IO.Exception (ExitCode(ExitSuccess)) import Witch (into, unsafeInto) import Witherable (Filterable, catMaybes) @@ -59,70 +52,96 @@   , beaconRoot  :: W256   } deriving Show +data BlockchainContract = BlockchainContract+  { code    :: ByteStringS+  , nonce   :: W64+  , balance :: W256+  , storage :: Map W256 W256+  } deriving (Eq, Show, Generic)++instance FromJSON BlockchainContract++asBCContract :: Contract -> BlockchainContract+asBCContract c = BlockchainContract code nonce balance storage+  where+    code = case c.code of+      (RuntimeCode (ConcreteRuntimeCode bs)) -> ByteStringS bs+      _ -> internalError "Expected concrete contract"+    nonce = fromJust c.nonce+    balance = forceLit (c.balance)+    storage = fromConcrete c.storage++makeContract :: BlockchainContract -> Contract+makeContract (BlockchainContract (ByteStringS code) nonce balance storage) =+    initialContract (RuntimeCode (ConcreteRuntimeCode code))+      & set #nonce    (Just nonce)+      & set #balance  (Lit balance)+      & set #storage (ConcreteStore storage)+      & set #origStorage (ConcreteStore storage)++type BlockchainContracts = Map Addr BlockchainContract+ data Case = Case   { vmOpts      :: VMOpts Concrete-  , checkContracts  :: Map Addr Contract-  , testExpectation :: Map Addr Contract+  , checkContracts  :: BlockchainContracts+  , testExpectation :: BlockchainContracts   } deriving Show  data BlockchainCase = BlockchainCase   { blocks  :: [Block]-  , pre     :: Map Addr Contract-  , post    :: Map Addr Contract+  , pre     :: BlockchainContracts+  , post    :: BlockchainContracts   , network :: String   } deriving Show --testEnv :: Env-testEnv = Env { config = defaultConfig }--main :: IO ()-main = do-  tests <- runEnv testEnv prepareTests-  defaultMain tests- prepareTests :: App m => m TestTree prepareTests = do-  repo <- liftIO $ getEnv "HEVM_ETHEREUM_TESTS_REPO"-  let testsDir = "BlockchainTests/GeneralStateTests"-  let dir = repo </> testsDir-  jsonFiles <- liftIO $ Find.find Find.always (Find.extension Find.==? ".json") dir-  liftIO $ putStrLn $ "Loading and parsing json files from ethereum-tests from " <> show dir-  isCI <- liftIO $ isJust <$> lookupEnv "CI"-  let problematicTests = if isCI then commonProblematicTests <> ciProblematicTests else commonProblematicTests-  let ignoredFiles = if isCI then ciIgnoredFiles else []-  groups <- mapM (\f -> testGroup (makeRelative repo f) <$> (if any (`isInfixOf` f) ignoredFiles then pure [] else testsFromFile f problematicTests)) jsonFiles+  rootDir <- liftIO rootDirectory+  liftIO $ putStrLn $ "Loading and parsing json files from ethereum-tests from " <> show rootDir+  cases <- liftIO allTestCases+  groups <- forM (Map.toList cases) (\(f, subtests) -> testGroup (makeRelative rootDir f) <$> (process subtests))   liftIO $ putStrLn "Loaded."   pure $ testGroup "ethereum-tests" groups--testsFromFile-  :: forall m . App m-  => String -> Map String (TestTree -> TestTree) -> m [TestTree]-testsFromFile fname problematicTests = do-  fContents <- liftIO $ LazyByteString.readFile fname-  let parsed = parseBCSuite fContents-  liftIO $ putStrLn $ "Parsed " <> fname-  case parsed of-    Left "No cases to check." -> pure []-    Left _err -> pure []-    Right allTests -> mapM runTest $ Map.toList allTests   where-    runTest :: (String, Case) -> m TestTree+    process :: forall m . App m => (Map String Case) -> m [TestTree]+    process tests = forM (Map.toList tests) runTest++    runTest :: App m => (String, Case) -> m TestTree     runTest (name, x) = do-      exec <- toIO $ runVMTest x+      let fetcher q = withSolvers Z3 0 1 (Just 0) $ \s -> EVM.Fetch.noRpcFetcher s q+      exec <- toIO $ runVMTest fetcher x       pure $ testCase' name exec     testCase' :: String -> Assertion -> TestTree     testCase' name assertion =       case Map.lookup name problematicTests of-        Just f -> f (testCase name (liftIO assertion))-        Nothing -> testCase name (liftIO assertion)+        Just f -> f (testCase name assertion)+        Nothing -> testCase name assertion --- CI has issues with some heaver tests, disable in bulk-ciIgnoredFiles :: [String]-ciIgnoredFiles = []+rootDirectory :: IO FilePath+rootDirectory = do+  repo <- getEnv "HEVM_ETHEREUM_TESTS_REPO"+  let testsDir = "BlockchainTests/GeneralStateTests"+  pure $ repo </> testsDir -commonProblematicTests :: Map String (TestTree -> TestTree)-commonProblematicTests = Map.fromList+collectJsonFiles :: FilePath -> IO [FilePath]+collectJsonFiles rootDir = Find.find Find.always (Find.extension Find.==? ".json") rootDir++allTestCases :: IO (Map FilePath (Map String Case))+allTestCases = do+  root <- rootDirectory+  jsons <- collectJsonFiles root+  cases <- forM jsons (\fname -> do+      fContents <- BS.readFile fname+      let parsed = case (parseBCSuite (Lazy.fromStrict fContents)) of+                    Left "No cases to check." -> mempty+                    Left _err -> mempty -- TODO: This should be an error+                    Right allTests -> allTests+      pure (fname, parsed)+    )+  pure $ Map.fromList cases++problematicTests :: Map String (TestTree -> TestTree)+problematicTests = Map.fromList   [ ("loopMul_d0g0v0_Cancun", ignoreTestBecause "hevm is too slow")   , ("loopMul_d1g0v0_Cancun", ignoreTestBecause "hevm is too slow")   , ("loopMul_d2g0v0_Cancun", ignoreTestBecause "hevm is too slow")@@ -159,71 +178,71 @@   , ("failed_tx_xcf416c53_d0g0v0_Cancun", ignoreTestBecause "EIP-4844 not implemented")   ] -ciProblematicTests :: Map String (TestTree -> TestTree)-ciProblematicTests = Map.fromList-  [ ("Return50000_d0g1v0_Cancun", ignoreTest)-  , ("Return50000_2_d0g1v0_Cancun", ignoreTest)-  , ("randomStatetest177_d0g0v0_Cancun", ignoreTest)-  , ("static_Call50000_d0g0v0_Cancun", ignoreTest)-  , ("static_Call50000_d1g0v0_Cancun", ignoreTest)-  , ("static_Call50000bytesContract50_1_d1g0v0_Cancun", ignoreTest)-  , ("static_Call50000bytesContract50_2_d1g0v0_Cancun", ignoreTest)-  , ("static_Return50000_2_d0g0v0_Cancun", ignoreTest)-  , ("loopExp_d10g0v0_Cancun", ignoreTest)-  , ("loopExp_d11g0v0_Cancun", ignoreTest)-  , ("loopExp_d12g0v0_Cancun", ignoreTest)-  , ("loopExp_d13g0v0_Cancun", ignoreTest)-  , ("loopExp_d14g0v0_Cancun", ignoreTest)-  , ("loopExp_d8g0v0_Cancun", ignoreTest)-  , ("loopExp_d9g0v0_Cancun", ignoreTest)-  ] -runVMTest :: App m => Case -> m ()-runVMTest x = do+runVMTest :: App m => EVM.Fetch.Fetcher Concrete m -> Case -> m ()+runVMTest fetcher x = do   -- traceVsGeth fname name x   vm0 <- liftIO $ vmForCase x-  result <- EVM.Stepper.interpret (EVM.Fetch.zero 0 (Just 0)) vm0 EVM.Stepper.runFully+  result <- EVM.Stepper.interpret fetcher vm0 EVM.Stepper.runFully   writeTrace result-  maybeReason <- checkExpectation x result-  liftIO $ forM_ maybeReason assertFailure+  let maybeReason = checkExpectation x result+  liftIO $ forM_ maybeReason (liftIO >=> assertFailure) +checkExpectation :: Case -> VM Concrete -> Maybe (IO String)+checkExpectation x vm = let (okState, okBal, okNonce, okStor, okCode) = checkExpectedContracts vm x.testExpectation in+  if okState then Nothing else Just $ checkStateFail x (okBal, okNonce, okStor, okCode)+  where+    checkExpectedContracts :: VM Concrete -> BlockchainContracts -> (Bool, Bool, Bool, Bool, Bool)+    checkExpectedContracts vm' expected =+      let cs = fmap (asBCContract . clearZeroStorage) $ forceConcreteAddrs vm'.env.contracts+      in ( (expected ~= cs)+        , (clearBalance <$> expected) ~= (clearBalance <$> cs)+        , (clearNonce   <$> expected) ~= (clearNonce   <$> cs)+        , (clearStorage <$> expected) ~= (clearStorage <$> cs)+        , (clearCode    <$> expected) ~= (clearCode    <$> cs)+        ) --- | Run a vm test and output a geth style per opcode trace-traceVMTest :: App m => Case -> m [Tracing.VMTraceStep]-traceVMTest x = do-  vm0 <- liftIO $ vmForCase x-  (_, (_, ts)) <- runStateT (Tracing.interpretWithTrace (EVM.Fetch.zero 0 (Just 0)) EVM.Stepper.runFully) (vm0, [])-  pure ts+    -- quotient account state by nullness+    (~=) :: BlockchainContracts -> BlockchainContracts -> Bool+    (~=) cs1 cs2 =+        let nullAccount = asBCContract $ EVM.initialContract (RuntimeCode (ConcreteRuntimeCode ""))+            padNewAccounts cs ks = Map.union cs $ Map.fromList [(k, nullAccount) | k <- ks]+            padded_cs1 = padNewAccounts cs1 (Map.keys cs2)+            padded_cs2 = padNewAccounts cs2 (Map.keys cs1)+        in and $ zipWith (==) (Map.elems padded_cs1) (Map.elems padded_cs2)+    +    checkStateFail :: Case -> (Bool, Bool, Bool, Bool) -> IO String+    checkStateFail x' (okBal, okNonce, okData, okCode) = do+      let+        printContracts :: BlockchainContracts -> IO ()+        printContracts cs = putStrLn $ Map.foldrWithKey (\k c acc ->+          acc ++ "-->" <> show k ++ " : "+                      ++ (show c.nonce) ++ " "+                      ++ (show c.balance) ++ " "+                      ++ (show c.storage)+            ++ "\n") "" cs --- | given a path to a test file, a test case from within that file, and a trace from geth from running that test, compare the traces and show where we differ--- This would need a few tweaks to geth to make this really usable (i.e. evm statetest show allow running a single test from within the test file).-traceVsGeth :: App m => String -> String -> Case -> m ()-traceVsGeth fname name x = do-  liftIO $ putStrLn "-> Running `evm --json blocktest` tool."-  (exitCode, evmtoolStdout, evmtoolStderr) <- liftIO $ readProcessWithExitCode "evm" [-                               "--json"-                               , "blocktest"-                               , "--run", name-                               , fname-                               ] ""-  when (exitCode /= ExitSuccess) $ liftIO $ do-    putStrLn $ "evmtool exited with code " <> show exitCode-    putStrLn $ "evmtool stderr output:" <> show evmtoolStderr-    putStrLn $ "evmtool stdout output:" <> show evmtoolStdout-  hevm <- traceVMTest x-  decodedContents <- liftIO $ withSystemTempFile "trace.jsonl" $ \traceFile hdl -> do-    hPutStr hdl $ filterInfoLines evmtoolStderr-    hClose hdl-    decodeTraceOutputHelper traceFile-  let EVMToolTraceOutput ts _ = fromJust decodedContents-  liftIO $ putStrLn "Comparing traces."-  _ <- liftIO $ compareTraces hevm ts-  pure ()+        reason = map fst (filter (not . snd)+            [ ("bad-state",       okBal   || okNonce || okData  || okCode)+            , ("bad-balance", not okBal   || okNonce || okData  || okCode)+            , ("bad-nonce",   not okNonce || okBal   || okData  || okCode)+            , ("bad-storage", not okData  || okBal   || okNonce || okCode)+            , ("bad-code",    not okCode  || okBal   || okNonce || okData)+            ])+        check = x'.checkContracts+        expected = x'.testExpectation+        actual = fmap (asBCContract . clearZeroStorage) $ forceConcreteAddrs vm.env.contracts -  where-    filterInfoLines :: String -> String-    filterInfoLines input = unlines $ filter (not . isPrefixOf "INFO") (lines input)+      putStrLn $ "-> Failing because of: " <> (unwords reason)+      putStrLn "-> Pre balance/state: "+      printContracts check+      putStrLn "-> Expected balance/state: "+      printContracts expected+      putStrLn "-> Actual balance/state: "+      printContracts actual+      pure (unwords reason) + splitEithers :: (Filterable f) => f (Either a b) -> (f a, f b) splitEithers =   (catMaybes *** catMaybes)@@ -234,115 +253,23 @@ fromConcrete (ConcreteStore s) = s fromConcrete s = internalError $ "unexpected abstract store: " <> show s -checkStateFail :: Case -> VM Concrete RealWorld -> (Bool, Bool, Bool, Bool) -> IO String-checkStateFail x vm (okBal, okNonce, okData, okCode) = do-  let-    printContracts :: Map Addr Contract -> IO ()-    printContracts cs = putStrLn $ Map.foldrWithKey (\k c acc ->-      acc ++ "-->" <> show k ++ " : "-                   ++ (show $ fromJust c.nonce) ++ " "-                   ++ (show $ fromJust $ maybeLitWordSimp c.balance) ++ " "-                   ++ (show $ fromConcrete c.storage)-                   ++ (show $ fromConcrete c.tStorage)-        ++ "\n") "" cs--    reason = map fst (filter (not . snd)-        [ ("bad-state",       okBal   || okNonce || okData  || okCode)-        , ("bad-balance", not okBal   || okNonce || okData  || okCode)-        , ("bad-nonce",   not okNonce || okBal   || okData  || okCode)-        , ("bad-storage", not okData  || okBal   || okNonce || okCode)-        , ("bad-code",    not okCode  || okBal   || okNonce || okData)-        ])-    check = x.checkContracts-    expected = x.testExpectation-    actual = fmap (clearZeroStorage . clearOrigStorage) $ forceConcreteAddrs vm.env.contracts--  putStrLn $ "-> Failing because of: " <> (unwords reason)-  putStrLn "-> Pre balance/state: "-  printContracts check-  putStrLn "-> Expected balance/state: "-  printContracts expected-  putStrLn "-> Actual balance/state: "-  printContracts actual-  pure (unwords reason)--checkExpectation-  :: App m-  => Case -> VM Concrete RealWorld -> m (Maybe String)-checkExpectation x vm = do-  let expectation = x.testExpectation-      (okState, okBal, okNonce, okStor, okCode) = checkExpectedContracts vm expectation-  if okState then do-    pure Nothing-  else liftIO $ Just <$> checkStateFail x vm (okBal, okNonce, okStor, okCode)---- quotient account state by nullness-(~=) :: Map Addr Contract -> Map Addr Contract -> Bool-(~=) cs1 cs2 =-    let nullAccount = EVM.initialContract (RuntimeCode (ConcreteRuntimeCode ""))-        padNewAccounts cs ks = Map.union cs $ Map.fromList [(k, nullAccount) | k <- ks]-        padded_cs1 = padNewAccounts cs1 (Map.keys cs2)-        padded_cs2 = padNewAccounts cs2 (Map.keys cs1)-    in and $ zipWith (===) (Map.elems padded_cs1) (Map.elems padded_cs2)--(===) :: Contract -> Contract -> Bool-c1 === c2 =-  codeEqual && storageEqual && c1.balance == c2.balance && c1.nonce == c2.nonce-  where-    storageEqual = c1.storage == c2.storage-    codeEqual = case (c1.code, c2.code) of-      (RuntimeCode a', RuntimeCode b') -> a' == b'-      codes -> internalError ("unexpected code: \n" <> show codes)--checkExpectedContracts :: VM Concrete RealWorld -> Map Addr Contract -> (Bool, Bool, Bool, Bool, Bool)-checkExpectedContracts vm expected =-  let cs = fmap (clearZeroStorage . clearOrigStorage) $ forceConcreteAddrs vm.env.contracts-  in ( (expected ~= cs)-     , (clearBalance <$> expected) ~= (clearBalance <$> cs)-     , (clearNonce   <$> expected) ~= (clearNonce   <$> cs)-     , (clearStorage <$> expected) ~= (clearStorage <$> cs)-     , (clearCode    <$> expected) ~= (clearCode    <$> cs)-     )--clearOrigStorage :: Contract -> Contract-clearOrigStorage = set #origStorage (ConcreteStore mempty)- clearZeroStorage :: Contract -> Contract clearZeroStorage c = case c.storage of   ConcreteStore m -> let store = Map.filter (/= 0) m                      in set #storage (ConcreteStore store) c   _ -> internalError "Internal Error: unexpected abstract store" -clearStorage :: Contract -> Contract-clearStorage c = c { storage = clear c.storage, tStorage = clear c.tStorage }-  where-    clear :: Expr Storage -> Expr Storage-    clear (ConcreteStore _) = ConcreteStore mempty-    clear _ = internalError "Internal Error: unexpected abstract store"--clearBalance :: Contract -> Contract-clearBalance c = set #balance (Lit 0) c--clearNonce :: Contract -> Contract-clearNonce c = set #nonce (Just 0) c+clearStorage :: BlockchainContract -> BlockchainContract+clearStorage c = c { storage = mempty} -clearCode :: Contract -> Contract-clearCode c = set #code (RuntimeCode (ConcreteRuntimeCode "")) c+clearBalance :: BlockchainContract -> BlockchainContract+clearBalance c = c {balance = 0} -instance FromJSON Contract where-  parseJSON (JSON.Object v) = do-    code <- (RuntimeCode . ConcreteRuntimeCode <$> (hexText <$> v .: "code"))-    storage <- v .: "storage"-    balance <- v .: "balance"-    nonce   <- v .: "nonce"-    pure $ EVM.initialContract code-             & #balance .~ (Lit balance)-             & #nonce   ?~ nonce-             & #storage .~ (ConcreteStore storage)-             & #origStorage .~ (ConcreteStore storage)+clearNonce :: BlockchainContract -> BlockchainContract+clearNonce c = c {nonce = 0} -  parseJSON invalid =-    JSON.typeMismatch "Contract" invalid+clearCode :: BlockchainContract -> BlockchainContract+clearCode c = c {code = (ByteStringS "")}  instance FromJSON BlockchainCase where   parseJSON (JSON.Object v) = BlockchainCase@@ -372,7 +299,7 @@   parseJSON invalid =     JSON.typeMismatch "Block" invalid -parseContracts :: Which -> JSON.Object -> JSON.Parser (Map Addr Contract)+parseContracts :: Which -> JSON.Object -> JSON.Parser (BlockchainContracts) parseContracts w v = v .: which >>= parseJSON   where which = case w of           Pre  -> "pre"@@ -424,7 +351,7 @@ maxCodeSize = 24576  fromBlockchainCase' :: Block -> Transaction-                       -> Map Addr Contract -> Map Addr Contract+                       -> BlockchainContracts -> BlockchainContracts                        -> Either BlockchainError Case fromBlockchainCase' block tx preState postState =   let isCreate = isNothing tx.toAddr in@@ -464,11 +391,13 @@       postState         where           toAddr = maybe (EVM.createAddress origin (fromJust senderNonce)) LitAddr (tx.toAddr)-          senderNonce = view (accountAt (LitAddr origin) % #nonce) (Map.mapKeys LitAddr preState)+          senderNonce = (.nonce) <$> Map.lookup origin preState           toCode = Map.lookup toAddr (Map.mapKeys LitAddr preState)           theCode = if isCreate                     then InitCode tx.txdata mempty-                    else maybe (RuntimeCode (ConcreteRuntimeCode "")) (.code) toCode+                    else RuntimeCode . ConcreteRuntimeCode $ case toCode of+                      Nothing ->  ""+                      Just (BlockchainContract (ByteStringS bs) _ _ _) -> bs           effectiveGasPrice = effectiveprice tx block.baseFee           cd = if isCreate                then mempty@@ -495,43 +424,41 @@      EIP1559Transaction -> fromJust tx.maxFeePerGas      _ -> fromJust tx.gasPrice -checkTx :: Transaction -> Block -> Map Addr Contract -> Maybe (Map Addr Contract)+checkTx :: Transaction -> Block -> BlockchainContracts -> Maybe (BlockchainContracts) checkTx tx block prestate = do   origin <- sender tx   validateTx tx block prestate-  let isCreate    = isNothing tx.toAddr-      cs          = Map.mapKeys LitAddr prestate-      senderNonce = view (accountAt (LitAddr origin) % #nonce) cs-      toAddr      = maybe (EVM.createAddress origin (fromJust senderNonce)) LitAddr (tx.toAddr)-      prevCode    = view (accountAt toAddr % #code) cs-      prevNonce   = view (accountAt toAddr % #nonce) cs--      nonEmptyAccount = case prevCode of-                        RuntimeCode (ConcreteRuntimeCode b) -> not (BS.null b)-                        _ -> True-      badNonce = prevNonce /= Just 0-      initCodeSizeExceeded = BS.length tx.txdata > (unsafeInto maxCodeSize * 2)-  if isCreate && (badNonce || nonEmptyAccount || initCodeSizeExceeded)-  then mzero+  if (isJust tx.toAddr) then pure prestate   else-    pure prestate+    let senderNonce = (.nonce) <$> Map.lookup origin prestate+        addr  = case EVM.createAddress origin (fromJust senderNonce) of+                  (LitAddr a) -> a+                  _ -> internalError "Cannot happen"+        freshContract = BlockchainContract (ByteStringS "") 0 0 mempty+        (BlockchainContract (ByteStringS b) prevNonce _ _) = (fromMaybe freshContract $ Map.lookup addr prestate)+        nonEmptyAccount = not (BS.null b)+        badNonce = prevNonce /= 0+        initCodeSizeExceeded = BS.length tx.txdata > (unsafeInto maxCodeSize * 2)+    in+    if (badNonce || nonEmptyAccount || initCodeSizeExceeded) then mzero+    else pure prestate -validateTx :: Transaction -> Block -> Map Addr Contract -> Maybe ()+validateTx :: Transaction -> Block -> BlockchainContracts -> Maybe () validateTx tx block cs = do   origin <- sender tx-  Lit originBalance <- (.balance) <$> Map.lookup origin cs+  originBalance <- (.balance) <$> Map.lookup origin cs   originNonce <- (.nonce) <$> Map.lookup origin cs   let gasDeposit = (effectiveprice tx block.baseFee) * (into tx.gasLimit)   if gasDeposit + tx.value <= originBalance-    && (Just (unsafeInto tx.nonce) == originNonce) && block.baseFee <= maxBaseFee tx+    && ((unsafeInto tx.nonce) == originNonce) && block.baseFee <= maxBaseFee tx   then Just ()   else Nothing -vmForCase :: Case -> IO (VM Concrete RealWorld)+vmForCase :: Case -> IO (VM Concrete) vmForCase x = do   vm <- stToIO $ makeVm x.vmOpts     -- TODO: why do we override contracts here instead of using VMOpts otherContracts?-    <&> set (#env % #contracts) (Map.mapKeys LitAddr x.checkContracts)+    <&> set (#env % #contracts) (Map.mapKeys LitAddr $ Map.map makeContract x.checkContracts)     -- TODO: we need to call this again because we override contracts in the     -- previous line     <&> setEIP4788Storage x.vmOpts
test/EVM/Test/FuzzSymExec.hs view
@@ -13,7 +13,8 @@ module EVM.Test.FuzzSymExec where  import Control.Monad (when)-import Control.Monad.ST (ST, stToIO)+import Control.Monad.IO.Unlift+import Control.Monad.ST (ST, stToIO, RealWorld) import Control.Monad.State.Strict (StateT(..)) import Control.Monad.Reader (ReaderT) import Data.Aeson ((.:), (.:?))@@ -21,7 +22,7 @@ import Data.ByteString (ByteString) import Data.ByteString qualified as BS import Data.ByteString.Char8 qualified as Char8-import Data.Maybe (fromJust, isJust, isNothing)+import Data.Maybe (fromJust, isJust, mapMaybe) import Data.Map.Strict qualified as Map import Data.Text.IO qualified as T import Data.Vector qualified as Vector@@ -29,6 +30,7 @@ import GHC.Generics (Generic) import GHC.IO.Exception (ExitCode(ExitSuccess)) import Numeric (showHex)+import Optics.Core hiding (pre) import System.Directory (removeDirectoryRecursive) import System.FilePath ((</>)) import System.IO.Temp (getCanonicalTemporaryDirectory, createTempDirectory)@@ -38,12 +40,10 @@ import Test.QuickCheck.Instances.Natural() import Test.QuickCheck.Instances.ByteString() import Test.Tasty (testGroup, after, TestTree, TestName, DependencyType(..))-import Test.Tasty.HUnit (assertEqual, testCase)+import Test.Tasty.HUnit (assertEqual, testCase, assertBool) import Test.Tasty.QuickCheck hiding (Failure, Success) import Witch (into, unsafeInto) -import Optics.Core hiding (pre)- import EVM (makeVm, initialContract, symbolify) import EVM.Assembler (assemble) import EVM.Expr qualified as Expr@@ -60,7 +60,6 @@ import EVM.Transaction qualified import EVM.Types hiding (Env) import EVM.Effects-import Control.Monad.IO.Unlift import EVM.Tracing (interpretWithTrace, VMTraceStep(..), VMTraceStepResult(..))  data EVMToolTrace =@@ -280,10 +279,10 @@  getHEVMRet   :: App m-  => OpContract -> ByteString -> Int -> m (Either (EvmError, [VMTraceStep]) (Expr 'End, [VMTraceStep], VMTraceStepResult))+  => OpContract -> ByteString -> Int -> m (Either (EvmError, [VMTraceStep]) ([Expr 'End], [VMTraceStep], VMTraceStepResult)) getHEVMRet contr txData gaslimitExec = do   let (txn, evmEnv, contrAlloc, fromAddress, toAddress, _) = evmSetup contr txData gaslimitExec-  runCodeWithTrace mempty evmEnv contrAlloc txn (LitAddr fromAddress) (LitAddr toAddress)+  runCodeWithTrace Fetch.noRpc evmEnv contrAlloc txn (LitAddr fromAddress) (LitAddr toAddress)  getEVMToolRet :: FilePath -> OpContract -> ByteString -> Int -> IO (Maybe EVMToolResult) getEVMToolRet evmDir contr txData gaslimitExec = do@@ -401,13 +400,13 @@ runCodeWithTrace   :: App m   => Fetch.RpcInfo -> EVMToolEnv -> EVMToolAlloc -> EVM.Transaction.Transaction-  -> Expr EAddr -> Expr EAddr -> m (Either (EvmError, [VMTraceStep]) ((Expr 'End, [VMTraceStep], VMTraceStepResult)))+  -> Expr EAddr -> Expr EAddr -> m (Either (EvmError, [VMTraceStep]) (([Expr 'End], [VMTraceStep], VMTraceStepResult))) runCodeWithTrace rpcinfo evmEnv alloc txn fromAddr toAddress = withSolvers Z3 0 1 Nothing $ \solvers -> do   let calldata' = ConcreteBuf txn.txdata       code' = alloc.code       iterConf = IterConfig { maxIter = Nothing, askSmtIters = 1, loopHeuristic = Naive }       fetcherSym = Fetch.oracle solvers Nothing rpcinfo-      buildExpr vm = interpret fetcherSym iterConf vm runExpr+      buildExpr vm = interpret fetcherSym iterConf vm runExpr pure   origVM <- liftIO $ stToIO $ vmForRuntimeCode code' calldata' evmEnv alloc txn fromAddr toAddress   expr <- buildExpr $ symbolify origVM @@ -417,7 +416,7 @@     Left x -> pure $ Left (x, trace)     Right _ -> pure $ Right (expr, trace, vmres vm) -vmForRuntimeCode :: ByteString -> Expr Buf -> EVMToolEnv -> EVMToolAlloc -> EVM.Transaction.Transaction -> Expr EAddr -> Expr EAddr -> ST s (VM Concrete s)+vmForRuntimeCode :: ByteString -> Expr Buf -> EVMToolEnv -> EVMToolAlloc -> EVM.Transaction.Transaction -> Expr EAddr -> Expr EAddr -> ST RealWorld (VM Concrete) vmForRuntimeCode runtimecode calldata' evmToolEnv alloc txn fromAddr toAddress =   let contract = initialContract (RuntimeCode (ConcreteRuntimeCode runtimecode))                  & set #balance (Lit alloc.balance)@@ -452,7 +451,7 @@              (Just (initialContract (RuntimeCode (ConcreteRuntimeCode BS.empty))))        <&> set (#state % #calldata) calldata' -vmres :: VM Concrete s -> VMTraceStepResult+vmres :: VM Concrete -> VMTraceStepResult vmres vm =   let     gasUsed' = vm.tx.gaslimit - vm.state.gas@@ -682,7 +681,7 @@ randItem :: [a] -> IO a randItem = generate . Test.QuickCheck.elements -getOpFromVM :: VM t s -> Word8+getOpFromVM :: VM t -> Word8 getOpFromVM vm =   let pcpos  = vm ^. #state % #pc       code' = vm ^. #state % #code@@ -760,19 +759,19 @@   case hevmRun of     (Right (expr, hevmTrace, hevmTraceResult)) -> liftIO $ do       let-        concretize :: Expr a -> Expr Buf -> Expr a-        concretize a c = mapExpr go a+        concretize :: Expr Buf -> Expr a ->  Expr a+        concretize c a = mapExpr go a           where             go :: Expr a -> Expr a             go = \case                        AbstractBuf "calldata" -> c                        y -> y-        concretizedExpr = concretize expr (ConcreteBuf txData)-        simplConcExpr = Expr.simplify concretizedExpr+        concretizedExpr = map (concretize (ConcreteBuf txData)) $ expr+        simplConcExpr = map Expr.simplify concretizedExpr         getReturnVal :: Expr End -> Maybe ByteString         getReturnVal (Success _ _ (ConcreteBuf bs) _) = Just bs         getReturnVal _ = Nothing-        simplConcrExprRetval = getReturnVal simplConcExpr+        simplConcrExprRetval = mapMaybe getReturnVal simplConcExpr       traceOK <- compareTraces hevmTrace (evmtoolTraceOutput.trace)       -- putStrLn $ "HEVM trace   : " <> show hevmTrace       -- putStrLn $ "evmtool trace: " <> show (evmtoolTraceOutput.trace)@@ -780,18 +779,19 @@       let resultOK = evmtoolTraceOutput.output.output == hevmTraceResult.out       if resultOK then liftIO $ do         putStrLn $ "HEVM & evmtool's outputs match: '" <> (bsToHex $ bssToBs evmtoolTraceOutput.output.output) <> "'"-        if isNothing simplConcrExprRetval || (fromJust simplConcrExprRetval) == (bssToBs hevmTraceResult.out)+        assertBool "Cannot have more than one success return value" (length simplConcrExprRetval <= 1)+        if null simplConcrExprRetval || (simplConcrExprRetval !! 0) == (bssToBs hevmTraceResult.out)            then do              putStr "OK, symbolic interpretation -> concrete calldata -> Expr.simplify gives the same answer."-             if isNothing simplConcrExprRetval then putStrLn ", but it was a Nothing, so not strong equivalence"-                                               else putStrLn ""+             if null simplConcrExprRetval then putStrLn ", but it was a Nothing, so not strong equivalence"+                                          else putStrLn ""            else do              putStrLn $ "original expr                    : " <> (show expr)              putStrLn $ "concretized expr                 : " <> (show concretizedExpr)              putStrLn $ "simplified concretized expr      : " <> (show simplConcExpr)              putStrLn $ "evmtoolTraceOutput.output.output : " <> (show (evmtoolTraceOutput.output.output))              putStrLn $ "HEVM trace result output         : " <> (bsToHex (bssToBs hevmTraceResult.out))-             putStrLn $ "ret value computed via symb+conc : " <> (bsToHex (fromJust simplConcrExprRetval))+             putStrLn $ "ret value computed via symb+conc : " <> (bsToHex (simplConcrExprRetval !! 0))              assertEqual "Simplified, concretized expression must match evmtool's output." True False       else do         putStrLn $ "Name of trace file: " <> (getTraceFileName evmDir $ fromJust evmtoolResult)
test/EVM/Test/Utils.hs view
@@ -17,14 +17,13 @@ import EVM.Solvers import EVM.UnitTest import EVM.SymExec qualified as SymExec-import Control.Monad.ST (RealWorld) import Control.Monad.IO.Unlift import Control.Monad.Catch (MonadMask) import EVM.Effects import Data.Maybe (fromMaybe) import EVM.Types (internalError) import System.Environment (lookupEnv)-import EVM.Fetch (RpcInfo)+import EVM.Fetch (RpcInfo, noRpc) import EVM.Fetch qualified as Fetch  -- Returns tuple of (No cex, No warnings)@@ -47,12 +46,12 @@ runForgeTest   :: (MonadMask m, App m)   => FilePath -> Text -> m (Bool, Bool)-runForgeTest testFile match = runForgeTestCustom testFile match Nothing Nothing True mempty+runForgeTest testFile match = runForgeTestCustom testFile match Nothing Nothing True noRpc -testOpts :: forall m . App m => SolverGroup -> FilePath -> Maybe BuildOutput -> Text -> Maybe Integer -> Bool -> RpcInfo -> m (UnitTestOptions RealWorld)+testOpts :: forall m . App m => SolverGroup -> FilePath -> Maybe BuildOutput -> Text -> Maybe Integer -> Bool -> RpcInfo -> m (UnitTestOptions) testOpts solvers root buildOutput match maxIter allowFFI rpcinfo = do   let srcInfo = maybe emptyDapp (dappInfo root) buildOutput-  sess <- Fetch.mkSession+  sess <- Fetch.mkSessionWithoutCache   params <- paramsFromRpc rpcinfo sess    pure UnitTestOptions
test/clitest.hs view
@@ -136,50 +136,6 @@         let hexStr = Types.bsToHex c         (_, stdout, _) <- readProcessWithExitCode "cabal" ["run", "exe:hevm", "--", "symbolic", "--solver", "empty", "--code", hexStr] ""         stdout `shouldContain` "SMT solver says: Result unknown by SMT solver"--      -- file "devcon_example.yul" from "eq-all-yul-optimization-tests" in test.hs-      -- we check that at least one UNSAT cache hit happens, i.e. the unsat cache is not-      -- completely broken-      it "unsat-cache" $ do-        let a = [i| {-          calldatacopy(0,0,1024)-              sstore(0, array_sum(calldataload(0)))-              function array_sum(x) -> sum {-                  let length := calldataload(x)-                  for { let i := 0 } lt(i, length) { i := add(i, 1) } {-                      sum := add(sum, array_load(x, i))-                  }-              }-              function array_load(x, i) -> v {-                  let len := calldataload(x)-                  if iszero(lt(i, len)) { revert(0, 0) }-                  let data := add(x, 0x20)-                  v := calldataload(add(data, mul(i, 0x20)))-              }-          } |]-        let b = [i| {-          calldatacopy(0,0,1024)-               {-                   let _1 := calldataload(0)-                   let sum := 0-                   let length := calldataload(_1)-                   let i := 0-                   for { } true { i := add(i, 1) }-                   {-                       let _2 := iszero(lt(i, length))-                       if _2 { break }-                       _2 := 0-                       sum := add(sum, calldataload(add(add(_1, shl(5, i)), 0x20)))-                   }-                   sstore(0, sum)-               }-           } |]-        Right aPrgm <- yul (T.pack "") $ T.pack a-        Right bPrgm <- yul (T.pack "") $ T.pack b-        let hexStrA = Types.bsToHex aPrgm-            hexStrB = Types.bsToHex bPrgm-        (_, stdout, _) <- readProcessWithExitCode "cabal" ["run", "exe:hevm", "--", "equivalence", "--num-solvers", "1", "--debug", "--code-a", hexStrA, "--code-b", hexStrB] ""-        stdout `shouldContain` "Qed found via cache"       it "crash-of-hevm" $ do         let hexStrA = "608060405234801561001057600080fd5b506004361061002b5760003560e01c8063efa2978514610030575b600080fd5b61004361003e3660046102ad565b610045565b005b60006100508561007a565b9050600061005d866100a8565b905080821461006e5761006e61034c565b50505050505050505050565b600061008761032e6103aa565b8261009457610197610098565b61013e5b6100a291906103e2565b92915050565b60006100b561032e6103aa565b6100be906103aa565b6100c7906103aa565b82806100d1575060005b806100da575060005b61013157605a6100ea60006103aa565b6100f3906103aa565b6100ff6001605a610404565b61010b6001605a610404565b61011891166101976103e2565b6101229190610493565b61012c9190610493565b610149565b604061013f8161013e6103e2565b6101499190610493565b61015391906103e2565b61016061032e60006103e2565b83801561016b575060015b15801590610177575060015b80156101a05750831515801561018b575060015b15158015610197575060015b806101a0575060005b610251576101976101b3605a602d610493565b602d60006101c2600182610493565b6101cd906001610404565b6101d8906001610404565b6101e1906103aa565b6101ea906103aa565b6101f491906103e2565b6101ff90605a610404565b604e61020c8160016103e2565b6102169190610493565b61022490600116605a610404565b1661022e906103aa565b61023891906103e2565b6102429190610493565b61024c9190610493565b610283565b604561025f8161013e6103e2565b6102699190610493565b60456102778161013e6103e2565b6102819190610493565b165b61028d91906103e2565b1692915050565b80358015155b81146100a257600080fd5b80358061029a565b600080600080600080600080610100898b0312156102ca57600080fd5b6102d48a8a610294565b97506102e38a60208b01610294565b96506102f28a60408b016102a5565b95506103018a60608b016102a5565b94506103108a60808b01610294565b935061031f8a60a08b016102a5565b925061032e8a60c08b01610294565b915061033d8a60e08b016102a5565b90509295985092959890939650565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007f800000000000000000000000000000000000000000000000000000000000000082036103db576103db61037b565b5060000390565b818103600083128015838313168383129190911617156100a2576100a261037b565b60008261043a577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f800000000000000000000000000000000000000000000000000000000000000082147fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8414161561048e5761048e61037b565b500590565b80820160008212801584831290811690159190911617156100a2576100a261037b56fea26469706673582212200a37769e5bf4b8b890caac8ab643126d55feb821a0201d2f674203f23fa666ad64736f6c634300081e0033" @@ -241,9 +197,9 @@         fileExists <- doesFileExist filename         shouldBe fileExists True         removeFile filename-      it "rpc-mock" $ do+      it "rpc-cache" $ do         (_, stdout, stderr) <- runForge "test/contracts/fail/rpc-test.sol"           ["--rpc", "http://mock.mock", "--prefix", "test_attack_symbolic"-          , "--number", "10307563", "--mock-file", "test/contracts/fail/rpc-test-mock.json"]+          , "--number", "10307563", "--cache-dir", "test/contracts/fail/"]         stdout `shouldContain` "[FAIL]"         stderr `shouldNotContain` "CallStack"
test/rpc.hs view
@@ -19,7 +19,7 @@ import EVM.SymExec import EVM.Test.Utils import EVM.Types hiding (BlockNumber, Env)-import Control.Monad.ST (stToIO, RealWorld)+import Control.Monad.ST (stToIO) import Control.Monad.Reader (ReaderT) import Control.Monad.IO.Unlift import EVM.Effects@@ -39,7 +39,7 @@     [ test "pre-merge-block" $ do         let block = BlockNumber 15537392         conf <- readConfig-        sess <- mkSession+        sess <- mkSessionWithoutCache         liftIO $ do           (cb, numb, basefee, prevRan) <- fetchBlockWithSession conf sess block testRpc >>= \case                         Nothing -> internalError "Could not fetch block"@@ -55,7 +55,7 @@           assertEqual "prevRan" 11049842297455506 prevRan     , test "post-merge-block" $ do         conf <- readConfig-        sess <- mkSession+        sess <- mkSessionWithoutCache         liftIO $ do           let block = BlockNumber 16184420           (cb, numb, basefee, prevRan) <- fetchBlockWithSession conf sess block testRpc >>= \case@@ -82,15 +82,12 @@     -- https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2#code     , test "weth-conc" $ do         let-          blockNum = 16198552           wad = 0x999999999999999999           calldata' = ConcreteBuf $ abiMethod "transfer(address,uint256)" (AbiTuple (V.fromList [AbiAddress (Addr 0xdead), AbiUInt 256 wad]))-          rpcDat = Just (BlockNumber blockNum, testRpc)-          rpcInfo :: RpcInfo = mempty { blockNumURL = rpcDat }-        sess <- mkSession-        vm <- weth9VM sess blockNum (calldata', [])+        sess <- mkSessionWithoutCache+        vm <- weth9VM sess testBlockNumber (calldata', [])         postVm <- withSolvers Z3 1 1 Nothing $ \solvers ->-          Stepper.interpret (oracle solvers (Just sess) rpcInfo) vm Stepper.runFully+          Stepper.interpret (oracle solvers (Just sess) testRpcInfo) vm Stepper.runFully         let           wethStore = (fromJust $ Map.lookup (LitAddr 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) postVm.env.contracts).storage           wethStore' = case wethStore of@@ -109,20 +106,18 @@     , test "weth-sym" $ do         calldata' <- symCalldata "transfer(address,uint256)" [AbiAddressType, AbiUIntType 256] ["0xdead"] (AbstractBuf "txdata")         let-          blockNum = 16198552           postc _ (Failure _ _ (Revert _)) = PBool False           postc _ _ = PBool True-        sess <- mkSession-        vm <- weth9VM sess blockNum calldata'+        sess <- mkSession Nothing Nothing+        vm <- weth9VM sess testBlockNumber calldata'         (_, [Cex (_, model)]) <- withSolvers Z3 1 1 Nothing $ \s ->-          let rpcInfo ::RpcInfo =  mempty { blockNumURL = Just (BlockNumber blockNum, testRpc) }-          in verify s (oracle s (Just sess) rpcInfo) (rpcVeriOpts (fromJust rpcInfo.blockNumURL)) (symbolify vm) (Just postc)+          verify s (oracle s (Just sess) testRpcInfo) (defaultVeriOpts {rpcInfo = testRpcInfo}) (symbolify vm) postc Nothing         liftIO $ assertBool "model should exceed caller balance" (getVar model "arg2" >= 695836005599316055372648)     ]   ]  -- call into WETH9 from 0xf04a... (a large holder)-weth9VM :: App m => Session -> W256 -> (Expr Buf, [Prop]) -> m (VM Concrete RealWorld)+weth9VM :: App m => Session -> BlockNumber -> (Expr Buf, [Prop]) -> m (VM Concrete) weth9VM sess blockNum calldata' = do   let     caller' = LitAddr 0xf04a5cc80b1e94c69b48f5ee68a08cd2f09a7c3e@@ -130,20 +125,21 @@     callvalue' = Lit 0   vmFromRpc sess blockNum calldata' callvalue' caller' weth9 -vmFromRpc :: App m => Session -> W256 -> (Expr Buf, [Prop]) -> Expr EWord -> Expr EAddr -> Addr -> m (VM Concrete RealWorld)+vmFromRpc :: App m => Session -> BlockNumber -> (Expr Buf, [Prop]) -> Expr EWord -> Expr EAddr -> Addr -> m (VM Concrete) vmFromRpc sess blockNum calldata callvalue caller address = do   conf <- readConfig-  ctrct <- liftIO $ fetchContractWithSession conf sess (BlockNumber blockNum) testRpc address >>= \case-        Nothing -> internalError $ "contract not found: " <> show address-        Just contract' -> pure contract'+  ctrct <- liftIO $ fetchContractWithSession conf sess blockNum testRpc address >>= \case+        FetchFailure _ -> internalError $ "contract not found: " <> show address+        FetchError e -> internalError $ "rpc error: " <> show e+        FetchSuccess contract' _ -> pure contract'    liftIO $ addFetchCache sess address ctrct-  blk <- liftIO $ fetchBlockWithSession conf sess (BlockNumber blockNum) testRpc >>= \case+  blk <- liftIO $ fetchBlockWithSession conf sess blockNum testRpc >>= \case     Nothing -> internalError "could not fetch block"     Just b -> pure b    liftIO $ stToIO (makeVm $ VMOpts-    { contract       = ctrct+    { contract       = makeContractFromRPC ctrct     , otherContracts = []     , calldata       = calldata     , value          = callvalue@@ -174,6 +170,8 @@ testRpc :: Text testRpc = "https://eth-mainnet.alchemyapi.io/v2/vpeKFsEF6PHifHzdtcwXSDbhV3ym5Ro4" +testBlockNumber :: BlockNumber+testBlockNumber = BlockNumber 16198552+ testRpcInfo :: RpcInfo-testRpcInfo = let rpcDat = Just (BlockNumber 16198552, testRpc)-  in mempty { blockNumURL = rpcDat }+testRpcInfo = RpcInfo $ Just (testBlockNumber, testRpc)
test/test.hs view
@@ -10,7 +10,7 @@ import GHC.TypeLits import Data.Proxy import Control.Monad-import Control.Monad.ST (RealWorld, stToIO)+import Control.Monad.ST (stToIO) import Control.Monad.State.Strict import Control.Monad.IO.Unlift import Control.Monad.Reader (ReaderT)@@ -150,8 +150,8 @@           }         }         |]-       expr <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "transfer(uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts-       assertEqualM "Expression is not clean." (badStoresInExpr expr) False+       paths <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "transfer(uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts+       assertEqualM "Expression is not clean." (badStoresInExpr paths) False     -- This case is somewhat artificial. We can't simplify this using only     -- static rewrite rules, because acct is totally abstract and acct + 1     -- could overflow back to zero. we may be able to do better if we have some@@ -170,9 +170,9 @@           }         }         |]-       expr <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "transfer(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts-       -- T.writeFile "symbolic-index.expr" $ formatExpr expr-       assertEqualM "Expression is not clean." (badStoresInExpr expr) False+       paths <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "transfer(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts+       -- T.writeFile "symbolic-index.expr" $ formatExpr paths+       assertEqualM "Expression is not clean." (badStoresInExpr paths) False     , expectFail $ test "simplify-storage-array-of-struct-symbolic-index" $ do        Just c <- solcRuntime "MyContract"         [i|@@ -191,8 +191,8 @@           }         }         |]-       expr <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "transfer(uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts-       assertEqualM "Expression is not clean." (badStoresInExpr expr) False+       paths <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "transfer(uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts+       assertEqualM "Expression is not clean." (badStoresInExpr paths) False     , test "simplify-storage-array-loop-nonstruct" $ do        Just c <- solcRuntime "MyContract"         [i|@@ -206,9 +206,9 @@           }         }         |]-       let veriOpts = defaultVeriOpts { iterConf = defaultIterConf { maxIter = Just 5 }}-       expr <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "transfer(uint256)" [AbiUIntType 256])) [] veriOpts-       assertEqualM "Expression is not clean." (badStoresInExpr expr) False+       let veriOpts = (defaultVeriOpts :: VeriOpts) { iterConf = defaultIterConf { maxIter = Just 5 }}+       paths <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "transfer(uint256)" [AbiUIntType 256])) [] veriOpts+       assertEqualM "Expression is not clean." (badStoresInExpr paths) False     , test "simplify-storage-map-newtest1" $ do        Just c <- solcRuntime "MyContract"         [i|@@ -226,9 +226,9 @@           }         }         |]-       expr <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "fun(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts-       assertEqualM "Expression is not clean." (badStoresInExpr expr) False-       (_, [(Qed)]) <- withDefaultSolver $ \s -> checkAssert s [0x11] c (Just (Sig "fun(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts+       paths <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "fun(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts+       assertEqualM "Expression is not clean." (badStoresInExpr paths) False+       (_, []) <- withDefaultSolver $ \s -> checkAssert s [0x11] c (Just (Sig "fun(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts        liftIO $ putStrLn "OK"     , ignoreTest $ test "simplify-storage-map-todo" $ do        Just c <- solcRuntime "MyContract"@@ -250,8 +250,8 @@        -- TODO: expression below contains (load idx1 (store idx1 (store idx1 (store idx0)))), and the idx0        --       is not stripped. This is due to us not doing all we can in this case, see        --       note above readStorage. Decompose remedies this (when it can be decomposed)-       -- expr <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "fun(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts-       -- putStrLnM $ T.unpack $ formatExpr expr+       -- paths <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "fun(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts+       -- putStrLnM $ T.unpack $ formatExpr paths        (_, [Cex _]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts        liftIO $ putStrLn "OK"     , test "simplify-storage-array-loop-struct" $ do@@ -272,9 +272,9 @@           }         }         |]-       let veriOpts = defaultVeriOpts { iterConf = defaultIterConf { maxIter = Just 5 }}-       expr <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "transfer(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] veriOpts-       assertEqualM "Expression is not clean." (badStoresInExpr expr) False+       let veriOpts = (defaultVeriOpts :: VeriOpts) { iterConf = defaultIterConf { maxIter = Just 5 }}+       paths <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "transfer(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] veriOpts+       assertEqualM "Expression is not clean." (badStoresInExpr paths) False     , test "decompose-1" $ do       Just c <- solcRuntime "MyContract"         [i|@@ -288,9 +288,9 @@           }         }         |]-      expr <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "prove_mapping_access(address,address)" [AbiAddressType, AbiAddressType])) [] defaultVeriOpts-      let simpExpr = mapExprM Expr.decomposeStorage expr-      assertEqualM "Decompose did not succeed." (isJust simpExpr) True+      paths <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "prove_mapping_access(address,address)" [AbiAddressType, AbiAddressType])) [] defaultVeriOpts+      let simpExpr = map (mapExprM Expr.decomposeStorage) paths+      assertEqualM "Decompose did not succeed." (all isJust simpExpr) True     , test "decompose-2" $ do       Just c <- solcRuntime "MyContract"         [i|@@ -303,10 +303,10 @@           }         }         |]-      expr <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "prove_mixed_symoblic_concrete_writes(address,uint256)" [AbiAddressType, AbiUIntType 256])) [] defaultVeriOpts-      let simpExpr = mapExprM Expr.decomposeStorage expr-      -- putStrLnM $ T.unpack $ formatExpr (fromJust simpExpr)-      assertEqualM "Decompose did not succeed." (isJust simpExpr) True+      paths <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "prove_mixed_symoblic_concrete_writes(address,uint256)" [AbiAddressType, AbiUIntType 256])) [] defaultVeriOpts+      let pathsSimp = map (mapExprM (Expr.decomposeStorage . Expr.concKeccakSimpExpr . Expr.simplify)) paths+      -- putStrLnM $ T.unpack $ formatExpr (fromJust pathsSimp)+      assertEqualM "Decompose did not succeed." (all isJust pathsSimp) True     , test "decompose-3" $ do       Just c <- solcRuntime "MyContract"         [i|@@ -320,9 +320,9 @@           }         }         |]-      expr <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "prove_array(uint256,uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts-      let simpExpr = mapExprM Expr.decomposeStorage expr-      assertEqualM "Decompose did not succeed." (isJust simpExpr) True+      paths <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "prove_array(uint256,uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts+      let simpExpr = map (mapExprM Expr.decomposeStorage) paths+      assertEqualM "Decompose did not succeed." (all isJust simpExpr) True     , test "decompose-4-mixed" $ do       Just c <- solcRuntime "MyContract"         [i|@@ -338,10 +338,10 @@           }         }         |]-      expr <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "prove_array(uint256,uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts-      let simpExpr = mapExprM Expr.decomposeStorage expr+      paths <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "prove_array(uint256,uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts+      let simpExpr = map (mapExprM Expr.decomposeStorage) paths       -- putStrLnM $ T.unpack $ formatExpr (fromJust simpExpr)-      assertEqualM "Decompose did not succeed." (isJust simpExpr) True+      assertEqualM "Decompose did not succeed." (all isJust simpExpr) True     , test "decompose-5-mixed" $ do       Just c <- solcRuntime "MyContract"         [i|@@ -365,10 +365,10 @@           }         }         |]-      expr <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "prove_mixed(address,address,uint256)" [AbiAddressType, AbiAddressType, AbiUIntType 256])) [] defaultVeriOpts-      let simpExpr = mapExprM Expr.decomposeStorage expr+      paths <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "prove_mixed(address,address,uint256)" [AbiAddressType, AbiAddressType, AbiUIntType 256])) [] defaultVeriOpts+      let simpExpr = map (mapExprM Expr.decomposeStorage) paths       -- putStrLnM $ T.unpack $ formatExpr (fromJust simpExpr)-      assertEqualM "Decompose did not succeed." (isJust simpExpr) True+      assertEqualM "Decompose did not succeed." (all isJust simpExpr) True     , test "decompose-6" $ do       Just c <- solcRuntime "MyContract"         [i|@@ -381,10 +381,10 @@           }         }         |]-      expr <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "prove_mixed(uint256)" [AbiUIntType 256])) [] defaultVeriOpts-      let simpExpr = mapExprM Expr.decomposeStorage expr+      paths <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "prove_mixed(uint256)" [AbiUIntType 256])) [] defaultVeriOpts+      let simpExpr = map (mapExprM Expr.decomposeStorage) paths       -- putStrLnM $ T.unpack $ formatExpr (fromJust simpExpr)-      assertEqualM "Decompose did not succeed." (isJust simpExpr) True+      assertEqualM "Decompose did not succeed." (all isJust simpExpr) True     -- This test uses array.length, which is is concrete 0 only in case we start with an empty storage     -- otherwise (i.e. with getExpr) it's symbolic, and the exploration loops forever     , test "decompose-7-emtpy-storage" $ do@@ -408,8 +408,8 @@           }        } |]        let sig = Just $ Sig "nested_append(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256]-       expr <- withDefaultSolver $ \s -> getExprEmptyStore s c sig [] defaultVeriOpts-       assertEqualM "Expression must be clean." (badStoresInExpr expr) False+       paths <- withDefaultSolver $ \s -> getExprEmptyStore s c sig [] defaultVeriOpts+       assertEqualM "Expression must be clean." (badStoresInExpr paths) False     , test "simplify-storage-map-only-static" $ do        Just c <- solcRuntime "MyContract"         [i|@@ -425,8 +425,9 @@         }         |]        let sig = (Just (Sig "transfer(uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256]))-       expr <- withDefaultSolver $ \s -> getExpr s c sig [] defaultVeriOpts-       assertEqualM "Expression is not clean." (badStoresInExpr expr) False+       paths <- withDefaultSolver $ \s -> getExpr s c sig [] defaultVeriOpts+       let pathsSimp = map (mapExpr (Expr.concKeccakSimpExpr . Expr.simplify)) paths+       assertEqualM "Expression is not clean." (badStoresInExpr pathsSimp) False     , test "simplify-storage-map-only-2" $ do        Just c <- solcRuntime "MyContract"         [i|@@ -441,9 +442,9 @@           }         }         |]-       expr <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "transfer(uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts-       -- putStrLnM $ T.unpack $ formatExpr expr-       assertEqualM "Expression is not clean." (badStoresInExpr expr) False+       paths <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "transfer(uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts+       -- putStrLnM $ T.unpack $ formatExpr paths+       assertEqualM "Expression is not clean." (badStoresInExpr paths) False     , test "simplify-storage-map-with-struct" $ do        Just c <- solcRuntime "MyContract"         [i|@@ -462,8 +463,8 @@           }         }         |]-       expr <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "transfer(uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts-       assertEqualM "Expression is not clean." (badStoresInExpr expr) False+       paths <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "transfer(uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts+       assertEqualM "Expression is not clean." (badStoresInExpr paths) False     , test "simplify-storage-map-and-array" $ do        Just c <- solcRuntime "MyContract"         [i|@@ -484,9 +485,9 @@           }         }        |]-       expr <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "transfer(uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts-       -- putStrLnM $ T.unpack $ formatExpr expr-       assertEqualM "Expression is not clean." (badStoresInExpr expr) False+       paths <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "transfer(uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts+       -- putStrLnM $ T.unpack $ formatExpr paths+       assertEqualM "Expression is not clean." (badStoresInExpr paths) False     , test "simplify-storage-wordToAddr" $ do        let a = "000000000000000000000000d95322745865822719164b1fc167930754c248de000000000000000000000000000000000000000000000000000000000000004a"            store = ConcreteStore (Map.fromList[(W256 0xebd33f63ba5dda53a45af725baed5628cdad261db5319da5f5d921521fe1161d,W256 0x5842cf)])@@ -520,7 +521,7 @@         let dummyContract =               (initialContract (RuntimeCode (ConcreteRuntimeCode mempty)))                 { external = True }-        vm :: VM Concrete RealWorld <- liftIO $ stToIO $ vmForEthrunCreation ""+        vm :: VM Concrete <- liftIO $ stToIO $ vmForEthrunCreation ""         -- perform the initial access         let ?conf = testEnv.config         vm1 <- liftIO $ stToIO $ execStateT (EVM.accessStorage (LitAddr 0) (Lit 0) (pure . pure ())) vm@@ -662,6 +663,19 @@         e2 = ConcreteBuf "Definitely not the same!"       equal <- checkEquiv e1 e2       assertBoolM "Should not be equivalent!" $ not equal+    , testNoSimplify "simplify-comparison-GEq" $ do+      let+        expr = PEq (Lit 0x1) (GEq (Var "v") (Lit 0x2))+        simp = Expr.simplifyProp expr+      ret <- checkEquivPropAndLHS expr simp+      assertEqualM "Must be equivalent" True ret+    , test "buffer-length-zero" $ do+        let+          p = PEq (BufLength (AbstractBuf "b")) (Lit 0x0)+          simp = Expr.simplifyProp p+        liftIO $ print simp+        ret <-  checkEquivProp p simp+        assertEqualM "Must be equivalent" True ret     ]   -- These tests fuzz the simplifier by generating a random expression,   -- applying some simplification rules, and then using the smt encoding to@@ -691,7 +705,7 @@     , testProperty "byte-simplification" $ \(expr :: Expr Byte) -> propNoSimp $ do         let simplified = Expr.simplify expr         checkEquivAndLHS expr simplified-    , testProperty "word-simplification" $ \(ZeroDepthWord expr) -> propNoSimp $ do+    , askOption $ \(QuickCheckTests n) -> testProperty "word-simplification" $ withMaxSuccess (min n 20) $ \(ZeroDepthWord expr) -> propNoSimp $ do         let simplified = Expr.simplify expr         checkEquivAndLHS expr simplified     , testProperty "readStorage-equivalance" $ \(store, slot) -> propNoSimp $ do@@ -733,6 +747,16 @@         let simplified = Expr.indexWord idx src             full = IndexWord idx src         checkEquiv full simplified+    , testProperty "pow-base2-simp" $ \(_ :: Int) -> propNoSimp $ do+        expo <- liftIO $ generate . sized $ genWordArith 15+        let full = Exp (Lit 2) expo+            simplified = Expr.simplify full+        checkEquiv full simplified+    , testProperty "pow-low-exponent-simp" $ \(LitWord @100 expo) -> propNoSimp $ do+        base <- liftIO $ generate . sized $ genWordArith 15+        let full = Exp base expo+            simplified = Expr.simplify full+        checkEquiv full simplified     , testProperty "indexWord-mask-equivalence" $ \(src :: Expr EWord, LitWord @35 idx) -> propNoSimp $ do         mask <- liftIO $ generate $ do           pow <- arbitrary :: Gen Int@@ -881,6 +905,68 @@           propagated = Expr.constPropagate t         assertEqualM "Must contain PBool False" True ((PBool False) `elem` propagated)   ]+  , testGroup "inequality-propagation-tests" [+      test "PLT-detects-impossible-constraint" $ do+        let+          -- x < 0 is impossible for unsigned integers+          t = [PLT (Var "x") (Lit 0)]+          propagated = Expr.constPropagate t+        assertEqualM "Must contain PBool False" True ((PBool False) `elem` propagated)+    , test "PLT-overflow-check" $ do+        let+          -- maxLit < y is impossible+          t = [PLT (Lit 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (Var "y")]+          propagated = Expr.constPropagate t+        assertEqualM "Must contain PBool False" True ((PBool False) `elem` propagated)+    , test "PGT-detects-impossible-constraint" $ do+        let+          -- x > maxLit is impossible+          t = [PGT (Var "x") (Lit 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)]+          propagated = Expr.constPropagate t+        assertEqualM "Must contain PBool False" True ((PBool False) `elem` propagated)+    , test "PGT-overflow-check" $ do+        let+          -- 0 > y is impossible+          t = [PGT (Lit 0) (Var "y")]+          propagated = Expr.constPropagate t+        assertEqualM "Must contain PBool False" True ((PBool False) `elem` propagated)+    , test "inequality-conflict-detection-narrow" $ do+        let+          -- x < 2 && x > 5 is impossible+          t = [PLT (Var "x") (Lit 2), PGT (Var "x") (Lit 5)]+          propagated = Expr.constPropagate t+        assertEqualM "Must contain PBool False" True ((PBool False) `elem` propagated)+    , test "inequality-conflict-detection-wide" $ do+        let+          -- x < 5 && x > 10 is impossible+          t = [PLT (Var "x") (Lit 5), PGT (Var "x") (Lit 10)]+          propagated = Expr.constPropagate t+        assertEqualM "Must contain PBool False" True ((PBool False) `elem` propagated)+    , test "inequality-tight-bounds-satisfied" $ do+        let+          -- x >= 5 && x <= 5 and x == 5 should be consistent+          t = [PGEq (Var "x") (Lit 5), PLEq (Var "x") (Lit 5), PEq (Var "x") (Lit 5)]+          propagated = Expr.constPropagate t+        assertEqualM "Must not contain PBool False" False ((PBool False) `elem` propagated)+    , test "inequality-tight-bounds-violated" $ do+        let+          -- x >= 5 && x <= 5 and x != 5 should be inconsistent+          t = [PGEq (Var "x") (Lit 5), PLEq (Var "x") (Lit 5), PNeg (PEq (Var "x") (Lit 5))]+          propagated = Expr.constPropagate t+        assertEqualM "Must contain PBool False" True ((PBool False) `elem` propagated)+    , test "inequality-with-existing-equality-consistent" $ do+        let+          -- x == 5 && x < 10 is consistent+          t = [PEq (Var "x") (Lit 5), PLT (Var "x") (Lit 10)]+          propagated = Expr.constPropagate t+        assertEqualM "Must not contain PBool False" False ((PBool False) `elem` propagated)+    , test "inequality-with-existing-equality-inconsistent" $ do+        let+          -- x == 5 && x < 5 is inconsistent+          t = [PEq (Var "x") (Lit 5), PLT (Var "x") (Lit 5)]+          propagated = Expr.constPropagate t+        assertEqualM "Must contain PBool False" True ((PBool False) `elem` propagated)+  ]   , testGroup "simpProp-concrete-tests" [       test "simpProp-concrete-trues" $ do         let@@ -1082,13 +1168,11 @@             } |]         let sig = Just $ Sig "fun(int256)" [AbiIntType 256]         (e, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-        assertBoolM "The expression must not be partial" $ not (Expr.containsNode isPartial e)+        assertBoolM "The expression must not be partial" $ not (any isPartial e)         let numCexes = sum $ map (fromEnum . isCex) ret         let numErrs = sum $ map (fromEnum . isError) ret-        let numQeds = sum $ map (fromEnum . isQed) ret         assertEqualM "number of counterexamples" 1 numCexes         assertEqualM "number of errors" 0 numErrs-        assertEqualM "number of qed-s" 0 numQeds     , test "negative-numbers-nonzero-comp-2" $ do         Just c <- solcRuntime "C" [i|             contract C {@@ -1102,13 +1186,11 @@             } |]         let sig = Just $ Sig "fun(int256)" [AbiIntType 256]         (e, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-        assertBoolM "The expression must not be partial" $ not (Expr.containsNode isPartial e)+        assertBoolM "The expression must not be partial" $ not (any isPartial e)         let numCexes = sum $ map (fromEnum . isCex) ret         let numErrs = sum $ map (fromEnum . isError) ret-        let numQeds = sum $ map (fromEnum . isQed) ret         assertEqualM "number of counterexamples" 1 numCexes         assertEqualM "number of errors" 0 numErrs-        assertEqualM "number of qed-s" 0 numQeds     , test "negative-numbers-min" $ do         Just c <- solcRuntime "C" [i|             contract C {@@ -1122,13 +1204,11 @@             } |]         let sig = Just $ Sig "fun(int256)" [AbiIntType 256]         (e, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-        assertBoolM "The expression must not be partial" $ not (Expr.containsNode isPartial e)+        assertBoolM "The expression must not be partial" $ not (any isPartial e)         let numCexes = sum $ map (fromEnum . isCex) ret         let numErrs = sum $ map (fromEnum . isError) ret-        let numQeds = sum $ map (fromEnum . isQed) ret         assertEqualM "number of counterexamples" 1 numCexes         assertEqualM "number of errors" 0 numErrs-        assertEqualM "number of qed-s" 0 numQeds     , test "negative-numbers-int128-1" $ do         Just c <- solcRuntime "C" [i|             contract C {@@ -1143,13 +1223,11 @@             } |]         let sig = Just $ Sig "fun(int128)" [AbiIntType 128]         (e, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-        assertBoolM "The expression must not be partial" $ not (Expr.containsNode isPartial e)+        assertBoolM "The expression must not be partial" $ not (any isPartial e)         let numCexes = sum $ map (fromEnum . isCex) ret         let numErrs = sum $ map (fromEnum . isError) ret-        let numQeds = sum $ map (fromEnum . isQed) ret         assertEqualM "number of counterexamples" 1 numCexes         assertEqualM "number of errors" 0 numErrs-        assertEqualM "number of qed-s" 0 numQeds     , test "negative-numbers-zero-comp-simpleassert" $ do         Just c <- solcRuntime "C" [i|             contract C {@@ -1159,13 +1237,11 @@             } |]         let sig = Just $ Sig "fun(int256)" [AbiIntType 256]         (e, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-        assertBoolM "The expression must not be partial" $ not (Expr.containsNode isPartial e)+        assertBoolM "The expression must not be partial" $ not (any isPartial e)         let numCexes = sum $ map (fromEnum . isCex) ret         let numErrs = sum $ map (fromEnum . isError) ret-        let numQeds = sum $ map (fromEnum . isQed) ret         assertEqualM "number of counterexamples" 1 numCexes         assertEqualM "number of errors" 0 numErrs-        assertEqualM "number of qed-s" 0 numQeds     , test "signed-int8-range" $ do         Just c <- solcRuntime "C" [i|           contract C {@@ -1176,13 +1252,66 @@           } |]         let sig = Just $ Sig "fun(int8)" [AbiIntType 8]         (e, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-        assertBoolM "The expression must not be partial" $ not (Expr.containsNode isPartial e)+        assertBoolM "The expression must not be partial" $ not (any isPartial e)         let numCexes = sum $ map (fromEnum . isCex) ret         let numErrs = sum $ map (fromEnum . isError) ret-        let numQeds = sum $ map (fromEnum . isQed) ret         assertEqualM "number of counterexamples" 0 numCexes         assertEqualM "number of errors" 0 numErrs-        assertEqualM "number of qed-s" 1 numQeds+    , test "base-2-exp-uint8" $ do+        Just c <- solcRuntime "C" [i|+          contract C {+            function fun(uint8 x) public {+              unchecked {+                require(x < 10);+                uint256 y = 2**x;+                assert (y <= 512);+              }+            }+          } |]+        let sig = Just $ Sig "fun(uint8)" [AbiUIntType 8]+        (e, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts+        assertBoolM "The expression must not be partial" $ not (any isPartial e)+        let numCexes = sum $ map (fromEnum . isCex) ret+        let numErrs = sum $ map (fromEnum . isError) ret+        assertEqualM "number of counterexamples" 0 numCexes+        assertEqualM "number of errors" 0 numErrs+    , test "base-2-exp-no-rollaround" $ do+        Just c <- solcRuntime "C" [i|+          contract C {+            function fun(uint256 x) public {+              unchecked {+                require(x > 10);+                require(x < 256);+                uint256 y = 2**x;+                assert (y > 512);+              }+            }+          } |]+        let sig = Just $ Sig "fun(uint256)" [AbiUIntType 256]+        (e, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts+        assertBoolM "The expression must not be partial" $ not (any isPartial e)+        let numCexes = sum $ map (fromEnum . isCex) ret+        let numErrs = sum $ map (fromEnum . isError) ret+        assertEqualM "number of counterexamples" 0 numCexes+        assertEqualM "number of errors" 0 numErrs+    , test "base-2-exp-rollaround" $ do+        Just c <- solcRuntime "C" [i|+          contract C {+            function fun(uint256 x) public {+              unchecked {+                require(x == 256);+                uint256 y = 2**x;+                assert (y > 512);+              }+            }+          } |]+        let sig = Just $ Sig "fun(uint256)" [AbiUIntType 256]+        (e, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts+        assertBoolM "The expression must not be partial" $ not (any isPartial e)+        let numCexes = sum $ map (fromEnum . isCex) ret+        let numErrs = sum $ map (fromEnum . isError) ret+        assertEqualM "number of counterexamples" 1 numCexes+        assertEqualM "number of errors" 0 numErrs     , test "unsigned-int8-range" $ do         Just c <- solcRuntime "C" [i|           contract C {@@ -1193,13 +1322,11 @@           } |]         let sig = Just $ Sig "fun(uint8)" [AbiUIntType 8]         (e, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-        assertBoolM "The expression must not be partial" $ not (Expr.containsNode isPartial e)+        assertBoolM "The expression must not be partial" $ not (any isPartial e)         let numCexes = sum $ map (fromEnum . isCex) ret         let numErrs = sum $ map (fromEnum . isError) ret-        let numQeds = sum $ map (fromEnum . isQed) ret         assertEqualM "number of counterexamples" 0 numCexes         assertEqualM "number of errors" 0 numErrs-        assertEqualM "number of qed-s" 1 numQeds     , test "negative-numbers-zero-comp" $ do         Just c <- solcRuntime "C" [i|             contract C {@@ -1213,13 +1340,11 @@             } |]         let sig = Just $ Sig "fun(int256)" [AbiIntType 256]         (e, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-        assertBoolM "The expression must not be partial" $ not (Expr.containsNode isPartial e)+        assertBoolM "The expression must not be partial" $ not (any isPartial e)         let numCexes = sum $ map (fromEnum . isCex) ret         let numErrs = sum $ map (fromEnum . isError) ret-        let numQeds = sum $ map (fromEnum . isQed) ret         assertEqualM "number of counterexamples" 1 numCexes         assertEqualM "number of errors" 0 numErrs-        assertEqualM "number of qed-s" 0 numQeds     , test "positive-numbers-cex" $ do         Just c <- solcRuntime "C" [i|             contract C {@@ -1233,13 +1358,11 @@             } |]         let sig = Just $ Sig "fun(uint256)" [AbiUIntType 256]         (e, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-        assertBoolM "The expression must not be partial" $ not (Expr.containsNode isPartial e)+        assertBoolM "The expression must not be partial" $ not (any isPartial e)         let numCexes = sum $ map (fromEnum . isCex) ret         let numErrs = sum $ map (fromEnum . isError) ret-        let numQeds = sum $ map (fromEnum . isQed) ret         assertEqualM "number of counterexamples" 1 numCexes         assertEqualM "number of errors" 0 numErrs-        assertEqualM "number of qed-s" 0 numQeds     , test "positive-numbers-qed" $ do         Just c <- solcRuntime "C" [i|             contract C {@@ -1253,13 +1376,11 @@             } |]         let sig = Just $ Sig "fun(uint256)" [AbiUIntType 256]         (e, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-        assertBoolM "The expression must not be partial" $ not (Expr.containsNode isPartial e)+        assertBoolM "The expression must not be partial" $ not (any isPartial e)         let numCexes = sum $ map (fromEnum . isCex) ret         let numErrs = sum $ map (fromEnum . isError) ret-        let numQeds = sum $ map (fromEnum . isQed) ret         assertEqualM "number of counterexamples" 0 numCexes         assertEqualM "number of errors" 0 numErrs-        assertEqualM "number of qed-s" 1 numQeds      , test "keccak256()" $         SolidityCall "x = uint(keccak256(abi.encodePacked(a)));"@@ -1492,7 +1613,7 @@              }             |]         let sig = (Just (Sig "fun(uint8)" [AbiUIntType 8]))-        (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts+        (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts         putStrLnM "expected Qed found"      , test "enum-conversion-fail" $ do         Just c <- solcRuntime "MyContract"@@ -1577,7 +1698,7 @@             }           |]         Right e <- reachableUserAsserts c (Just $ Sig "f(address,uint256)" [AbiAddressType, AbiUIntType 256])-        assertBoolM "The expression is not partial" $ Expr.containsNode isPartial e+        assertBoolM "The expression is not partial" $ any isPartial e       ,       test "vm.prank-create" $ do         Just c <- solcRuntime "C"@@ -1651,8 +1772,8 @@             }             |]         let sig = Just (Sig "fun(uint256)" [AbiUIntType 256])-        (e, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-        assertBoolM "The expression must contain Partial." $ Expr.containsNode isPartial e+        (e, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts+        assertBoolM "The expression must contain Partial." $ any isPartial e       , test "cheatcode-with-selector" $ do         Just c <- solcRuntime "C"             [i|@@ -1667,7 +1788,7 @@             }             |]         Right e <- reachableUserAsserts c Nothing-        assertBoolM "The expression should not contain Partial." $ Prelude.not $ Expr.containsNode isPartial e+        assertBoolM "The expression should not contain Partial." $ Prelude.not $ any isPartial e       ,       test "call ffi when disabled" $ do         Just c <- solcRuntime "C"@@ -1789,14 +1910,12 @@             }             |]           let sig = Just (Sig "checkval(uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])-          (expr, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts+          (paths, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts           let numCexes = sum $ map (fromEnum . isCex) ret           let numErrs = sum $ map (fromEnum . isError) ret-          let numQeds = sum $ map (fromEnum . isQed) ret-          assertBoolM "The expression MUST be partial" (Expr.containsNode isPartial expr)+          assertBoolM "The expression MUST be partial" (any isPartial paths)           assertEqualM "number of errors" 0 numErrs           assertEqualM "number of counterexamples" 0 numCexes-          assertEqualM "number of qed-s" 1 numQeds       -- below we don't hit the limit of the depth of the symbolic execution tree       , testCase "limit-num-explore-no-hit-limit" $ do         let conf = testEnv.config {maxDepth = Just 7}@@ -1815,14 +1934,12 @@             }             |]           let sig = Just (Sig "checkval(uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])-          (expr, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts+          (paths, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts           let numCexes = sum $ map (fromEnum . isCex) ret           let numErrs = sum $ map (fromEnum . isError) ret-          let numQeds = sum $ map (fromEnum . isQed) ret-          assertBoolM "The expression MUST NOT be partial" $ Prelude.not (Expr.containsNode isPartial expr)+          assertBoolM "The expression MUST NOT be partial" $ Prelude.not (any isPartial paths)           assertEqualM "number of errors" 0 numErrs           assertEqualM "number of counterexamples" 1 numCexes-          assertEqualM "number of qed-s" 0 numQeds       , test "symbolic-copyslice" $ do         Just c <- solcRuntime "MyContract"             [i|@@ -1878,8 +1995,9 @@           let calldata = (WriteWord (Lit 0x0) (Var "u") (ConcreteBuf ""), [])           initVM <- liftIO $ stToIO $ abstractVM calldata initCode Nothing True           let iterConf = IterConfig {maxIter=Nothing, askSmtIters=1, loopHeuristic=StackBased }-          expr <- Expr.simplify <$> interpret (Fetch.oracle s Nothing mempty) iterConf initVM runExpr-          assertBoolM "unexptected partial execution" (not $ Expr.containsNode isPartial expr)+          paths <- interpret (Fetch.noRpcFetcher s) iterConf initVM runExpr pure+          let exprSimp = map Expr.simplify paths+          assertBoolM "unexptected partial execution" (not $ any isPartial exprSimp)     , test "mixed-concrete-symbolic-args" $ do         Just c <- solcRuntime "C"           [i|@@ -1901,8 +2019,8 @@                 }             }           |]-        Right expr <- reachableUserAsserts c (Just $ Sig "foo(uint256)" [AbiUIntType 256])-        assertBoolM "unexptected partial execution" (not $ Expr.containsNode isPartial expr)+        Right paths <- reachableUserAsserts c (Just $ Sig "foo(uint256)" [AbiUIntType 256])+        assertBoolM "unexptected partial execution" $ Prelude.not (any isPartial paths)     , test "extcodesize-symbolic" $ do         Just c <- solcRuntime "C"           [i|@@ -1920,8 +2038,8 @@         let sig = (Just $ Sig "foo(address,uint256)" [AbiAddressType, AbiUIntType 256])         (e, res) <- withDefaultSolver $           \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-        liftIO $ printWarnings Nothing [e] res "the contracts under test"-        assertEqualM "Must be QED" res [Qed]+        liftIO $ printWarnings Nothing e res "the contracts under test"+        assertEqualM "Must be QED" res []     , test "extcodesize-symbolic2" $ do         Just c <- solcRuntime "C"           [i|@@ -1938,7 +2056,7 @@         let sig = (Just $ Sig "foo(address,uint256)" [AbiAddressType, AbiUIntType 256])         (e, res@[Cex _]) <- withDefaultSolver $           \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-        liftIO $ printWarnings Nothing [e] res "the contracts under test"+        liftIO $ printWarnings Nothing e res "the contracts under test"     , test "jump-into-symbolic-region" $ do         let           -- our initCode just jumps directly to the end@@ -1969,10 +2087,9 @@         withDefaultSolver $ \s -> do           vm <- liftIO $ stToIO $ loadSymVM runtimecode (Lit 0) initCode False           let iterConf = IterConfig {maxIter=Nothing, askSmtIters=1, loopHeuristic=StackBased }-          expr <- Expr.simplify <$> interpret (Fetch.oracle s Nothing mempty) iterConf vm runExpr-          case expr of-            Partial _ _ (JumpIntoSymbolicCode _ _ _) -> assertBoolM "" True-            _ -> assertBoolM "did not encounter expected partial node" False+          paths <- interpret (Fetch.noRpcFetcher s) iterConf vm runExpr pure+          let exprSimp = map Expr.simplify paths+          assertBoolM "expected partial execution" (any isPartial exprSimp)     ]   , testGroup "Dapp-Tests"     [ test "Trivial-Pass" $ do@@ -2009,7 +2126,7 @@               , ("test/contracts/fail/symbolicFail.sol",      "prove_symb_fail_allrev_selector.*", (False, False))               , ("test/contracts/fail/symbolicFail.sol",      "prove_symb_fail_somerev_selector.*", (False, True))]         forM_ cases $ \(testFile, match, expected) -> do-          actual <- runForgeTestCustom testFile match Nothing Nothing False mempty+          actual <- runForgeTestCustom testFile match Nothing Nothing False Fetch.noRpc           putStrLnM $ "Test result for " <> testFile <> " match: " <> T.unpack match <> ": " <> show actual           assertEqualM "Must match" expected actual     , test "Trivial-Fail" $ do@@ -2042,14 +2159,14 @@         runForgeTest testFile "prove_trivial" >>= assertEqualM "prove_trivial" (False, False)         runForgeTest testFile "prove_trivial_dstest" >>= assertEqualM "prove_trivial_dstest" (False, False)         runForgeTest testFile "prove_add" >>= assertEqualM "prove_add" (False, True)-        runForgeTestCustom testFile "prove_smtTimeout" (Just 1) Nothing False mempty+        runForgeTestCustom testFile "prove_smtTimeout" (Just 1) Nothing False Fetch.noRpc           >>= assertEqualM "prove_smtTimeout" (True, False)         runForgeTest testFile "prove_multi" >>= assertEqualM "prove_multi" (False, True)         runForgeTest testFile "prove_distributivity" >>= assertEqualM "prove_distributivity" (False, True)     , test "Loop-Tests" $ do         let testFile = "test/contracts/pass/loops.sol"-        runForgeTestCustom testFile "prove_loop" Nothing (Just 10) False mempty  >>= assertEqualM "test result" (True, False)-        runForgeTestCustom testFile "prove_loop" Nothing (Just 100) False mempty >>= assertEqualM "test result" (False, False)+        runForgeTestCustom testFile "prove_loop" Nothing (Just 10) False Fetch.noRpc  >>= assertEqualM "test result" (True, False)+        runForgeTestCustom testFile "prove_loop" Nothing (Just 100) False Fetch.noRpc >>= assertEqualM "test result" (False, False)     , test "Cheat-Codes-Pass" $ do         let testFile = "test/contracts/pass/cheatCodes.sol"         runForgeTest testFile ".*" >>= assertEqualM "test result" (True, False)@@ -2076,10 +2193,10 @@             }             |]         let sig = Just $ Sig "fun()" []-            opts = defaultVeriOpts { iterConf = defaultIterConf {maxIter = Just 3 }}-        (e, [Qed]) <- withDefaultSolver $+            opts = (defaultVeriOpts :: VeriOpts) { iterConf = defaultIterConf {maxIter = Just 3 }}+        (e, []) <- withDefaultSolver $           \s -> checkAssert s defaultPanicCodes c sig [] opts-        assertBoolM "The expression is not partial" $ isPartial e+        assertBoolM "The expression is not partial" $ any isPartial e     , test "concrete-loops-not-reached" $ do         Just c <- solcRuntime "C"             [i|@@ -2093,10 +2210,10 @@             |]          let sig = Just $ Sig "fun()" []-            opts = defaultVeriOpts{ iterConf = defaultIterConf {maxIter = Just 6 }}-        (e, [Qed]) <- withDefaultSolver $+            opts = (defaultVeriOpts :: VeriOpts) { iterConf = defaultIterConf {maxIter = Just 6 }}+        (e, []) <- withDefaultSolver $           \s -> checkAssert s defaultPanicCodes c sig [] opts-        assertBoolM "The expression is partial" $ not $ isPartial e+        assertBoolM "The expression is partial" $ not $ any isPartial e     , test "symbolic-loops-reached" $ do         Just c <- solcRuntime "C"             [i|@@ -2108,10 +2225,10 @@               }             }             |]-        let veriOpts = defaultVeriOpts { iterConf = defaultIterConf { maxIter = Just 5 }}-        (e, [Qed]) <- withDefaultSolver $+        let veriOpts = (defaultVeriOpts :: VeriOpts) { iterConf = defaultIterConf { maxIter = Just 5 }}+        (e, []) <- withDefaultSolver $           \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint256)" [AbiUIntType 256])) [] veriOpts-        assertBoolM "The expression MUST be partial" $ Expr.containsNode isPartial e+        assertBoolM "The expression MUST be partial" $ any (Expr.containsNode isPartial) e     , test "inconsistent-paths" $ do         Just c <- solcRuntime "C"             [i|@@ -2128,10 +2245,10 @@             -- we don't ask the solver about the loop condition until we're             -- already in an inconsistent path (i == 5, j <= 3, i < j), so we             -- will continue looping here until we hit max iterations-            opts = defaultVeriOpts{ iterConf = defaultIterConf { maxIter = Just 10, askSmtIters = 5 }}-        (e, [Qed]) <- withDefaultSolver $+            opts = (defaultVeriOpts :: VeriOpts) { iterConf = defaultIterConf { maxIter = Just 10, askSmtIters = 5 }}+        (e, []) <- withDefaultSolver $           \s -> checkAssert s defaultPanicCodes c sig [] opts-        assertBoolM "The expression is not partial" $ Expr.containsNode isPartial e+        assertBoolM "The expression MUST be partial" $ any (Expr.containsNode isPartial) e     , test "mem-tuple" $ do         Just c <- solcRuntime "C"           [i|@@ -2152,7 +2269,7 @@           |]         let opts = defaultVeriOpts         let sig = Just $ Sig "prove_tuple_pass((uint256,uint256))" [AbiTupleType (V.fromList [AbiUIntType 256, AbiUIntType 256])]-        (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] opts+        (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] opts         putStrLnM "Qed, memory tuple is good"     , test "symbolic-loops-not-reached" $ do         Just c <- solcRuntime "C"@@ -2169,11 +2286,12 @@         let sig = Just $ Sig "fun(uint256)" [AbiUIntType 256]             -- askSmtIters is low enough here to avoid the inconsistent path             -- conditions, so we never hit maxIters-            opts = defaultVeriOpts{ iterConf = defaultIterConf {maxIter = Just 5, askSmtIters = 1 }}-        (e, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] opts-        assertBoolM "The expression MUST NOT be partial" $ not (Expr.containsNode isPartial e)+            opts = (defaultVeriOpts :: VeriOpts) { iterConf = defaultIterConf {maxIter = Just 5, askSmtIters = 1 }}+        (e, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] opts+        assertBoolM "The expression MUST NOT be partial" $ not (any (Expr.containsNode isPartial) e)     ]   , testGroup "Symbolic Addresses"+    -- TODO ignore only because Martin has a fix for this-- it should not be using `verify`     [ test "symbolic-address-create" $ do         let src = [i|                   contract A {@@ -2189,11 +2307,10 @@         Just a <- solcRuntime "A" src         Just c <- solcRuntime "C" src         let sig = Sig "fun(uint256)" [AbiUIntType 256]-        (expr, [Qed]) <- withDefaultSolver $ \s ->-          verifyContract s c (Just sig) [] defaultVeriOpts Nothing Nothing+        paths <- withDefaultSolver $ \s -> exploreContract s c (Just sig) [] defaultVeriOpts Nothing         let isSuc (Success {}) = True             isSuc _ = False-        case filter isSuc (flattenExpr expr) of+        case filter isSuc paths of           [Success _ _ _ store] -> do             let ca = fromJust (Map.lookup (SymAddr "freshSymAddr1") store)             let code = case ca.code of@@ -2202,7 +2319,7 @@             assertEqualM "balance mismatch" (Var "arg1") (Expr.simplify ca.balance)             assertEqualM "code mismatch" (stripBytecodeMetadata a) (stripBytecodeMetadata code)             assertEqualM "nonce mismatch" (Just 1) ca.nonce-          _ -> assertBoolM "too many success nodes!" False+          _ -> assertBoolM "too many/too few success nodes!" False     , test "symbolic-balance-call" $ do         let src = [i|                   contract A {@@ -2388,7 +2505,7 @@           |]         -- NOTE: we have a postcondition here, not just a regular verification         (_, [Cex _]) <- withDefaultSolver $ \s ->-          verifyContract s c Nothing [] defaultVeriOpts Nothing (Just $ checkBadCheatCode "load(address,bytes32)")+          verifyContract s c Nothing [] defaultVeriOpts Nothing (checkBadCheatCode "load(address,bytes32)")         pure ()     , test "vm.store fails for a potentially aliased address" $ do         Just c <- solcRuntime "C"@@ -2405,7 +2522,7 @@           |]         -- NOTE: we have a postcondition here, not just a regular verification         (_, [Cex _]) <- withDefaultSolver $ \s ->-          verifyContract s c Nothing [] defaultVeriOpts Nothing (Just $ checkBadCheatCode "store(address,bytes32,bytes32)")+          verifyContract s c Nothing [] defaultVeriOpts Nothing (checkBadCheatCode "store(address,bytes32,bytes32)")         pure ()     -- TODO: make this work properly     , test "transfering-eth-does-not-dealias" $ do@@ -2438,7 +2555,7 @@           |]         Right e <- reachableUserAsserts c Nothing         -- TODO: this should work one day-        assertBoolM "should be partial" (Expr.containsNode isPartial e)+        assertBoolM "should be partial" (any isPartial e)     , test "symbolic-addresses-cannot-be-zero-or-precompiles" $ do         let addrs = [T.pack . show . Addr $ a | a <- [0x0..0x09]]             mkC a = fromJust <$> solcRuntime "A"@@ -2509,7 +2626,7 @@               }              }             |]-        (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(int256)" [AbiIntType 256])) [] defaultVeriOpts+        (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(int256)" [AbiIntType 256])) [] defaultVeriOpts         putStrLnM "Require works as expected"      , test "symbolic-block-number" $ do        Just c <- solcRuntime "C" [i|@@ -2524,7 +2641,7 @@              }            } |]        (e, [Cex _]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c Nothing [] defaultVeriOpts-       assertBoolM "The expression MUST NOT be partial" $ Prelude.not (Expr.containsNode isPartial e)+       assertBoolM "The expression MUST NOT be partial" $ Prelude.not (any isPartial e)      , test "symbolic-to-concrete-multi" $ do         Just c <- solcRuntime "MyContract"             [i|@@ -2541,8 +2658,8 @@              }             |]         let sig = Just (Sig "fun(uint160)" [AbiUIntType 160])-        (e, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-        assertBoolM "The expression is not partial" $ Prelude.not (Expr.containsNode isPartial e)+        (e, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts+        assertBoolM "The expression is not partial" $ Prelude.not (any isPartial e)      ,      -- here test      test "ITE-with-bitwise-AND" $ do@@ -2580,7 +2697,7 @@            }          }          |]-       (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "f(uint256)" [AbiUIntType 256])) [] defaultVeriOpts+       (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "f(uint256)" [AbiUIntType 256])) [] defaultVeriOpts        putStrLnM "this should always be true, due to bitwise OR with positive value"      ,      test "abstract-returndata-size" $ do@@ -2594,8 +2711,8 @@            }          }          |]-       expr <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "f(uint256)" [])) [] defaultVeriOpts-       assertBoolM "The expression is partial" $ not $ Expr.containsNode isPartial expr+       paths <- withDefaultSolver $ \s -> getExpr s c (Just (Sig "f(uint256)" [])) [] defaultVeriOpts+       assertBoolM "The expression is partial" $ Prelude.not (any isPartial paths)     ,     -- CopySlice check     -- uses identity precompiled contract (0x4) to copy memory@@ -2621,9 +2738,9 @@         }         |]       let sig = Just (Sig "checkval(uint8)" [AbiUIntType 8])-      (res, [Qed]) <- withDefaultSolver $ \s ->+      (res, []) <- withDefaultSolver $ \s ->         checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-      putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+      putStrLnM $ "successfully explored " <> show (length res) <> " paths"     , test "staticcall-check-orig" $ do       Just c <- solcRuntime "C"         [i|@@ -2654,13 +2771,11 @@         |]       let sig = Just (Sig "checkval(uint256,uint256)" [AbiAddressType, AbiUIntType 256, AbiUIntType 256])       (res, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-      putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+      putStrLnM $ "successfully explored: " <> show (length res) <> " paths"       let numCexes = sum $ map (fromEnum . isCex) ret       let numErrs = sum $ map (fromEnum . isError) ret-      let numQeds = sum $ map (fromEnum . isQed) ret       assertEqualM "number of counterexamples" 0 numCexes       assertEqualM "number of errors" 0 numErrs-      assertEqualM "number of qed-s" 1 numQeds     , test "staticcall-check-orig2" $ do       Just c <- solcRuntime "C"         [i|@@ -2681,14 +2796,12 @@         |]       let sig = Just (Sig "checkval(uint256,uint256)" [AbiAddressType, AbiUIntType 256, AbiUIntType 256])       (res, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-      putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"-      assertBoolM "The expression is NOT partial" $ not $ Expr.containsNode isPartial res+      putStrLnM $ "successfully explored: " <> show (length res) <> " paths"+      assertBoolM "The expression is NOT partial" $ Prelude.not (any isPartial res)       let numCexes = sum $ map (fromEnum . isCex) ret       let numErrs = sum $ map (fromEnum . isError) ret-      let numQeds = sum $ map (fromEnum . isQed) ret       assertEqualM "number of counterexamples" 1 numCexes       assertEqualM "number of errors" 0 numErrs-      assertEqualM "number of qed-s" 0 numQeds     , test "copyslice-symbolic-ok" $ do       Just c <- solcRuntime "C"         [i|@@ -2707,10 +2820,10 @@          }         |]       let sig2 = Just (Sig "retFor(address)" [AbiAddressType])-      (expr, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig2 [] defaultVeriOpts-      putStrLnM $ "successfully explored: " <> show (Expr.numBranches expr) <> " paths"+      (paths, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig2 [] defaultVeriOpts+      putStrLnM $ "successfully explored: " <> show (length paths) <> " paths"       assertBoolM "The expression is NOT error" $ not $ any isError ret-      assertBoolM "The expression is NOT partial" $ not $ Expr.containsNode isPartial expr+      assertBoolM "The expression is NOT partial" $ not (any isPartial paths)     , test "no-overapprox-when-present" $ do       Just c <- solcRuntime "C" [i|         contract ERC20 {@@ -2727,11 +2840,11 @@           }         } |]       let sig2 = Just (Sig "no_overapp()" [])-      (expr, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig2 [] defaultVeriOpts-      -- putStrLnM $ "expr: " <> show expr-      putStrLnM $ "successfully explored: " <> show (Expr.numBranches expr) <> " paths"+      (paths, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig2 [] defaultVeriOpts+      -- putStrLnM $ "paths: " <> show paths+      putStrLnM $ "successfully explored: " <> show (length paths) <> " paths"       assertBoolM "The expression is NOT error" $ not $ any isError ret-      assertBoolM "The expression is NOT partial" $ not $ Expr.containsNode isPartial expr+      assertBoolM "The expression is NOT partial" $ not (any isPartial paths)       let numCexes = sum $ map (fromEnum . isCex) ret       assertEqualM "number of counterexamples" 0 numCexes     -- NOTE: below used to be symbolic copyslice copy error before new copyslice@@ -2758,10 +2871,10 @@          }         |]       let sig2 = Just (Sig "retFor(address)" [AbiAddressType])-      (expr, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig2 [] defaultVeriOpts-      putStrLnM $ "successfully explored: " <> show (Expr.numBranches expr) <> " paths"+      (paths, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig2 [] defaultVeriOpts+      putStrLnM $ "successfully explored: " <> show (length paths) <> " paths"       assertBoolM "The expression is NOT error" $ not $ any isError ret-      assertBoolM "The expression is NOT partial" $ not $ Expr.containsNode isPartial expr+      assertBoolM "The expression is NOT partial" $ not (any isPartial paths)       let numCexes = sum $ map (fromEnum . isCex) ret       -- There are 2 CEX-es       -- This is because with one CEX, the return DATA@@ -2786,11 +2899,11 @@          }         |]       let sig2 = Just (Sig "retFor(address)" [AbiAddressType])-      (expr, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig2 [] defaultVeriOpts-      putStrLnM $ "successfully explored: " <> show (Expr.numBranches expr) <> " paths"+      (paths, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig2 [] defaultVeriOpts+      putStrLnM $ "successfully explored: " <> show (length paths) <> " paths"       assertBoolM "The expression is NOT error" $ not $ any isError ret       let numCexes = sum $ map (fromEnum . isCex) ret-      assertBoolM "The expression is NOT partial" $ not $ Expr.containsNode isPartial expr+      assertBoolM "The expression is NOT partial" $ not (any isPartial paths)       -- There are 2 CEX-es       -- This is because with one CEX, the return DATA       -- is empty, and in the other, the return data is non-empty (but symbolic)@@ -2814,11 +2927,11 @@          }         |]       let sig2 = Just (Sig "retFor()" [])-      (expr, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig2 [] defaultVeriOpts-      putStrLnM $ "successfully explored: " <> show (Expr.numBranches expr) <> " paths"+      (paths, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig2 [] defaultVeriOpts+      putStrLnM $ "successfully explored: " <> show (length paths) <> " paths"       assertBoolM "The expression is NOT error" $ not $ any isError ret       let numCexes = sum $ map (fromEnum . isCex) ret-      assertBoolM "The expression is NOT partial" $ not $ Expr.containsNode isPartial expr+      assertBoolM "The expression is NOT partial" $ not (any isPartial paths)       -- There are 2 CEX-es       -- This is because with one CEX, the return DATA       -- is empty, and in the other, the return data is non-empty (but symbolic)@@ -2842,10 +2955,10 @@          }         |]       let sig2 = Just (Sig "retFor()" [])-      (expr, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig2 [] defaultVeriOpts-      putStrLnM $ "successfully explored: " <> show (Expr.numBranches expr) <> " paths"+      (paths, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig2 [] defaultVeriOpts+      putStrLnM $ "successfully explored: " <> show (length paths) <> " paths"       assertBoolM "The expression is NOT error" $ not $ any isError ret-      assertBoolM "The expression is NOT partial" $ not $ Expr.containsNode isPartial expr+      assertBoolM "The expression is NOT partial" $ not (any isPartial paths)       let numCexes = sum $ map (fromEnum . isCex) ret       -- There are 2 CEX-es       -- This is because with one CEX, the return DATA@@ -2882,16 +2995,14 @@         |]       let sig = Just (Sig "checkval(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])       (res, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-      putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"-      assertBoolM "The expression is NOT partial" $ not $ Expr.containsNode isPartial res+      putStrLnM $ "successfully explored: " <> show (length res) <> " paths"+      assertBoolM "The expression is NOT partial" $ not (any isPartial res)       assertBoolM "The expression is NOT unknown" $ not $ any isUnknown ret       assertBoolM "The expression is NOT error" $ not $ any isError ret       let numCexes = sum $ map (fromEnum . isCex) ret       let numErrs = sum $ map (fromEnum . isError) ret-      let numQeds = sum $ map (fromEnum . isQed) ret       assertEqualM "number of counterexamples" 0 numCexes       assertEqualM "number of errors" 0 numErrs-      assertEqualM "number of qed-s" 1 numQeds     , test "staticcall-check-symbolic1" $ do       Just c <- solcRuntime "C"         [i|@@ -2905,16 +3016,14 @@         |]       let sig = Just (Sig "checkval(address,uint256,uint256)" [AbiAddressType, AbiUIntType 256, AbiUIntType 256])       (res, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-      putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+      putStrLnM $ "successfully explored: " <> show (length res) <> " paths"       let numCexes = sum $ map (fromEnum . isCex) ret       let numErrs = sum $ map (fromEnum . isError) ret-      let numQeds = sum $ map (fromEnum . isQed) ret       -- There are 2 CEX-es, in contrast to the above (staticcall-check-orig2).       -- This is because with one CEX, the return DATA       -- is empty, and in the other, the return data is non-empty (but symbolic)       assertEqualM "number of counterexamples" 2 numCexes       assertEqualM "number of errors" 0 numErrs-      assertEqualM "number of qed-s" 0 numQeds     -- This checks that calling a symbolic address with staticcall will ALWAYS return 0/1     -- which is the semantic of the EVM. We insert a  constraint over the return value     -- even when overapproximation is used, as below.@@ -2951,13 +3060,11 @@         |]       let sig = Just (Sig "checkval(address,uint256,uint256)" [AbiAddressType, AbiUIntType 256, AbiUIntType 256])       (res, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-      putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+      putStrLnM $ "successfully explored: " <> show (length res) <> " paths"       let numCexes = sum $ map (fromEnum . isCex) ret       let numErrs = sum $ map (fromEnum . isError) ret-      let numQeds = sum $ map (fromEnum . isQed) ret       assertEqualM "number of counterexamples" 0 numCexes -- no counterexamples, because it is always  0/1       assertEqualM "number of errors" 0 numErrs-      assertEqualM "number of qed-s" 1 numQeds     , test "staticcall-check-symbolic2" $ do       Just c <- solcRuntime "C"         [i|@@ -2978,13 +3085,11 @@         |]       let sig = Just (Sig "checkval(address,uint256,uint256)" [AbiAddressType, AbiUIntType 256, AbiUIntType 256])       (res, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-      putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+      putStrLnM $ "successfully explored: " <> show (length res) <> " paths"       let numCexes = sum $ map (fromEnum . isCex) ret       let numErrs = sum $ map (fromEnum . isError) ret-      let numQeds = sum $ map (fromEnum . isQed) ret       assertEqualM "number of counterexamples" 2 numCexes       assertEqualM "number of errors" 1 numErrs-      assertEqualM "number of qed-s" 0 numQeds     , testCase "call-symbolic-noreent" $ do       let conf = testEnv.config {promiseNoReent = True}       let myTestEnv :: Env = (testEnv :: Env) {config = conf :: Config}@@ -3000,17 +3105,15 @@           }           |]         let sig = Just (Sig "checkval(address,uint256,uint256)" [AbiAddressType, AbiUIntType 256, AbiUIntType 256])-        (expr, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts+        (paths, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts         let numCexes = sum $ map (fromEnum . isCex) ret         let numErrs = sum $ map (fromEnum . isError) ret-        let numQeds = sum $ map (fromEnum . isQed) ret-        assertBoolM "The expression MUST NOT be partial" $ Prelude.not (Expr.containsNode isPartial expr)+        assertBoolM "The expression MUST NOT be partial" $ Prelude.not (any isPartial paths)       -- There are 2 CEX-es       -- This is because with one CEX, the return DATA       -- is empty, and in the other, the return data is non-empty and success is false         assertEqualM "number of errors" 0 numErrs         assertEqualM "number of counterexamples" 2 numCexes-        assertEqualM "number of qed-s" 0 numQeds     , test "call-symbolic-reent" $ do       Just c <- solcRuntime "C"         [i|@@ -3023,14 +3126,12 @@         }         |]       let sig = Just (Sig "checkval(address,uint256,uint256)" [AbiAddressType, AbiUIntType 256, AbiUIntType 256])-      (expr, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-      assertBoolM "The expression MUST be partial due to CALL to unknown code and no promise" $ (Expr.containsNode isPartial expr)+      (paths, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts+      assertBoolM "The expression MUST be partial due to CALL to unknown code and no promise" (any isPartial paths)       let numCexes = sum $ map (fromEnum . isCex) ret       let numErrs = sum $ map (fromEnum . isError) ret-      let numQeds = sum $ map (fromEnum . isQed) ret       assertEqualM "number of errors" 0 numErrs       assertEqualM "number of counterexamples" 0 numCexes-      assertEqualM "number of qed-s" 1 numQeds     , testCase "call-symbolic-noreent-maxbufsize16" $ do       let conf = testEnv.config {promiseNoReent = True, maxBufSize = 4}       let myTestEnv :: Env = (testEnv :: Env) {config = conf :: Config}@@ -3046,14 +3147,12 @@           }           |]         let sig = Just (Sig "checkval(address,uint256,uint256)" [AbiAddressType, AbiUIntType 256, AbiUIntType 256])-        (expr, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts+        (paths, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts         let numCexes = sum $ map (fromEnum . isCex) ret         let numErrs = sum $ map (fromEnum . isError) ret-        let numQeds = sum $ map (fromEnum . isQed) ret-        assertBoolM "The expression MUST NOT be partial" $ Prelude.not (Expr.containsNode isPartial expr)+        assertBoolM "The expression MUST NOT be partial" $ Prelude.not (any isPartial paths)         assertEqualM "number of errors" 0 numErrs         assertEqualM "number of counterexamples" 0 numCexes-        assertEqualM "number of qed-s" 1 numQeds     , testCase "call-symbolic-noreent-maxbufsize16-fail" $ do       let conf = testEnv.config {promiseNoReent = True, maxBufSize = 20}       let myTestEnv :: Env = (testEnv :: Env) {config = conf :: Config}@@ -3069,14 +3168,12 @@           }           |]         let sig = Just (Sig "checkval(address,uint256,uint256)" [AbiAddressType, AbiUIntType 256, AbiUIntType 256])-        (expr, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts+        (paths, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts         let numCexes = sum $ map (fromEnum . isCex) ret         let numErrs = sum $ map (fromEnum . isError) ret-        let numQeds = sum $ map (fromEnum . isQed) ret-        assertBoolM "The expression MUST NOT be partial" $ Prelude.not (Expr.containsNode isPartial expr)+        assertBoolM "The expression MUST NOT be partial" $ Prelude.not (any isPartial paths)         assertEqualM "number of errors" 0 numErrs         assertEqualM "number of counterexamples" 1 numCexes-        assertEqualM "number of qed-s" 0 numQeds     , test "call-balance-symb" $ do       Just c <- solcRuntime "C"         [i|@@ -3088,10 +3185,10 @@         }         |]       let sig = Just (Sig "checkval(address)" [AbiAddressType])-      (expr, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts+      (paths, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts       let numCexes = sum $ map (fromEnum . isCex) ret       let numErrs = sum $ map (fromEnum . isError) ret-      assertBoolM "The expression MUST NOT be partial" $ Prelude.not (Expr.containsNode isPartial expr)+      assertBoolM "The expression MUST NOT be partial" $ Prelude.not (any isPartial paths)       assertEqualM "number of errors" 0 numErrs       assertEqualM "number of counterexamples" 1 numCexes     , test "call-balance-symb2" $ do@@ -3105,10 +3202,10 @@         }         |]       let sig = Just (Sig "checkval()" [])-      (expr, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts+      (paths, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts       let numCexes = sum $ map (fromEnum . isCex) ret       let numErrs = sum $ map (fromEnum . isError) ret-      assertBoolM "The expression MUST NOT be partial" $ Prelude.not (Expr.containsNode isPartial expr)+      assertBoolM "The expression MUST NOT be partial" $ Prelude.not (any isPartial paths)       assertEqualM "number of errors" 0 numErrs       assertEqualM "number of counterexamples" 1 numCexes     , test "call-balance-concrete-pass" $ do@@ -3130,12 +3227,10 @@         }         |]       let sig = Just (Sig "checkval()" [])-      (expr, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts+      (paths, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts       let numErrs = sum $ map (fromEnum . isError) ret-      let numQeds = sum $ map (fromEnum . isQed) ret-      assertBoolM "The expression MUST NOT be partial" $ Prelude.not (Expr.containsNode isPartial expr)+      assertBoolM "The expression MUST NOT be partial" $ Prelude.not (any isPartial paths)       assertEqualM "number of errors" 0 numErrs-      assertEqualM "number of qed-s" 1 numQeds     , test "call-balance-concrete-fail" $ do       Just c <- solcRuntime "C"         [i|@@ -3155,10 +3250,10 @@         }         |]       let sig = Just (Sig "checkval()" [])-      (expr, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts+      (paths, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts       let numErrs = sum $ map (fromEnum . isError) ret       let numCexes = sum $ map (fromEnum . isCex) ret-      assertBoolM "The expression MUST NOT be partial" $ Prelude.not (Expr.containsNode isPartial expr)+      assertBoolM "The expression MUST NOT be partial" $ Prelude.not (any isPartial paths)       assertEqualM "number of errors" 0 numErrs       assertEqualM "number of counterexamples" 1 numCexes     , test "call-extcodehash-symb1" $ do@@ -3172,10 +3267,10 @@         }         |]       let sig = Just (Sig "checkval(address)" [AbiAddressType])-      (expr, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts+      (paths, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts       let numCexes = sum $ map (fromEnum . isCex) ret       let numErrs = sum $ map (fromEnum . isError) ret-      assertBoolM "The expression MUST NOT be partial" $ Prelude.not (Expr.containsNode isPartial expr)+      assertBoolM "The expression MUST NOT be partial" $ Prelude.not (any isPartial paths)       assertEqualM "number of errors" 0 numErrs       assertEqualM "number of counterexamples" 1 numCexes     , test "call-extcodehash-symb2" $ do@@ -3189,10 +3284,10 @@         }         |]       let sig = Just (Sig "checkval()" [])-      (expr, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts+      (paths, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts       let numCexes = sum $ map (fromEnum . isCex) ret       let numErrs = sum $ map (fromEnum . isError) ret-      assertBoolM "The expression MUST NOT be partial" $ Prelude.not (Expr.containsNode isPartial expr)+      assertBoolM "The expression MUST NOT be partial" $ Prelude.not (any isPartial paths)       assertEqualM "number of errors" 0 numErrs       assertEqualM "number of counterexamples" 1 numCexes     , test "call-extcodehash-concrete-fail" $ do@@ -3209,10 +3304,10 @@         }         |]       let sig = Just (Sig "checkval()" [])-      (expr, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts+      (paths, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts       let numErrs = sum $ map (fromEnum . isError) ret       let numCexes = sum $ map (fromEnum . isCex) ret-      assertBoolM "The expression MUST NOT be partial" $ Prelude.not (Expr.containsNode isPartial expr)+      assertBoolM "The expression MUST NOT be partial" $ Prelude.not (any isPartial paths)       assertEqualM "number of errors" 0 numErrs       assertEqualM "number of counterexamples" 1 numCexes     , test "jump-symbolic" $ do@@ -3236,13 +3331,11 @@         |]       let sig = Just (Sig "checkval(address,uint256,uint256)" [AbiAddressType, AbiUIntType 256, AbiUIntType 256])       (res, ret) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts-      putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+      putStrLnM $ "successfully explored: " <> show (length res) <> " paths"       let numCexes = sum $ map (fromEnum . isCex) ret       let numErrs = sum $ map (fromEnum . isError) ret-      let numQeds = sum $ map (fromEnum . isQed) ret       assertEqualM "number of counterexamples" numCexes 2       assertEqualM "number of symbolic copy errors" numErrs 0-      assertEqualM "number of qed-s" numQeds 0      ,      test "opcode-mul-assoc" $ do         Just c <- solcRuntime "MyContract"@@ -3263,7 +3356,7 @@               }              }             |]-        (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(int256,int256,int256)" [AbiIntType 256, AbiIntType 256, AbiIntType 256])) [] defaultVeriOpts+        (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(int256,int256,int256)" [AbiIntType 256, AbiIntType 256, AbiIntType 256])) [] defaultVeriOpts         putStrLnM "MUL is associative"      ,      -- TODO look at tests here for SAR: https://github.com/dapphub/dapptools/blob/01ef8ea418c3fe49089a44d56013d8fcc34a1ec2/src/dapp-tests/pass/constantinople.sol#L250@@ -3281,7 +3374,7 @@               }              }             |]-        (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(int256,int256)" [AbiIntType 256, AbiIntType 256])) [] defaultVeriOpts+        (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(int256,int256)" [AbiIntType 256, AbiIntType 256])) [] defaultVeriOpts         putStrLnM "SAR works as expected"      ,      test "opcode-sar-pos" $ do@@ -3298,7 +3391,7 @@               }              }             |]-        (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(int256,int256)" [AbiIntType 256, AbiIntType 256])) [] defaultVeriOpts+        (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(int256,int256)" [AbiIntType 256, AbiIntType 256])) [] defaultVeriOpts         putStrLnM "SAR works as expected"      ,      test "opcode-sar-fixedval-pos" $ do@@ -3315,7 +3408,7 @@               }              }             |]-        (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(int256,int256)" [AbiIntType 256, AbiIntType 256])) [] defaultVeriOpts+        (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(int256,int256)" [AbiIntType 256, AbiIntType 256])) [] defaultVeriOpts         putStrLnM "SAR works as expected"      ,      test "opcode-sar-fixedval-neg" $ do@@ -3332,7 +3425,7 @@               }              }             |]-        (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(int256,int256)" [AbiIntType 256, AbiIntType 256])) [] defaultVeriOpts+        (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(int256,int256)" [AbiIntType 256, AbiIntType 256])) [] defaultVeriOpts         putStrLnM "SAR works as expected"      ,      test "opcode-div-zero-1" $ do@@ -3349,7 +3442,7 @@               }             }             |]-        (_, [Qed])  <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint256)" [AbiUIntType 256])) [] defaultVeriOpts+        (_, [])  <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint256)" [AbiUIntType 256])) [] defaultVeriOpts         putStrLnM "sdiv works as expected"       ,      test "opcode-sdiv-zero-1" $ do@@ -3366,7 +3459,7 @@               }             }             |]-        (_, [Qed])  <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint256)" [AbiUIntType 256])) [] defaultVeriOpts+        (_, [])  <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint256)" [AbiUIntType 256])) [] defaultVeriOpts         putStrLnM "sdiv works as expected"       ,      test "opcode-sdiv-zero-2" $ do@@ -3383,7 +3476,7 @@               }             }             |]-        (_, [Qed])  <- withCVC5Solver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint256)" [AbiUIntType 256])) [] defaultVeriOpts+        (_, [])  <- withCVC5Solver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint256)" [AbiUIntType 256])) [] defaultVeriOpts         putStrLnM "sdiv works as expected"       ,      test "signed-overflow-checks" $ do@@ -3417,7 +3510,7 @@               }             }             |]-        (_, [Qed])  <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "foo(uint256)" [AbiUIntType 256])) [] defaultVeriOpts+        (_, [])  <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "foo(uint256)" [AbiUIntType 256])) [] defaultVeriOpts         putStrLnM "signextend works as expected"       ,      test "opcode-signextend-pos-nochop" $ do@@ -3435,7 +3528,7 @@               }             }             |]-        (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint256,uint8)" [AbiUIntType 256, AbiUIntType 8])) [] defaultVeriOpts+        (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint256,uint8)" [AbiUIntType 256, AbiUIntType 8])) [] defaultVeriOpts         putStrLnM "signextend works as expected"       ,       test "opcode-signextend-pos-chopped" $ do@@ -3453,7 +3546,7 @@               }             }             |]-        (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint256,uint8)" [AbiUIntType 256, AbiUIntType 8])) [] defaultVeriOpts+        (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint256,uint8)" [AbiUIntType 256, AbiUIntType 8])) [] defaultVeriOpts         putStrLnM "signextend works as expected"       ,       -- when b is too large, value is unchanged@@ -3471,7 +3564,7 @@               }             }             |]-        (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint256,uint8)" [AbiUIntType 256, AbiUIntType 8])) [] defaultVeriOpts+        (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint256,uint8)" [AbiUIntType 256, AbiUIntType 8])) [] defaultVeriOpts         putStrLnM "signextend works as expected"      ,      test "opcode-shl" $ do@@ -3489,7 +3582,7 @@               }              }             |]-        (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts+        (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts         putStrLnM "SAR works as expected"      ,      test "opcode-xor-cancel" $ do@@ -3506,7 +3599,7 @@               }              }             |]-        (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts+        (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts         putStrLnM "XOR works as expected"       ,       test "opcode-xor-reimplement" $ do@@ -3522,7 +3615,7 @@               }              }             |]-        (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts+        (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts         putStrLnM "XOR works as expected"       ,       test "opcode-add-commutative" $ do@@ -3548,7 +3641,7 @@             putStrLnM $ "y:" <> show y             putStrLnM $ "x:" <> show x             assertEqualM "Addition is not commutative... that's wrong" False True-          (_, [Qed]) -> do+          (_, []) -> do             putStrLnM "adding is commutative"           _ -> internalError "Unexpected"       ,@@ -3566,7 +3659,7 @@               }             }             |]-        (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint16)" [AbiUIntType 16])) [] defaultVeriOpts+        (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "fun(uint16)" [AbiUIntType 16])) [] defaultVeriOpts         putStrLnM "DIV by zero is zero"       ,       -- Somewhat tautological since we are asserting the precondition@@ -3594,9 +3687,9 @@                    Success _ _ b _ -> (ReadWord (Lit 0) b) .== (Add x y)                    _ -> PBool True             sig = Just (Sig "add(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])-        (res, [Qed]) <- withDefaultSolver $ \s ->-          verifyContract s safeAdd sig [] defaultVeriOpts (Just pre) (Just post)-        putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+        (res, []) <- withDefaultSolver $ \s ->+          verifyContract s safeAdd sig [] defaultVeriOpts (Just pre) post+        putStrLnM $ "successfully explored: " <> show (length res) <> " paths"      ,        test "x == y => x + y == 2 * y" $ do@@ -3621,9 +3714,9 @@               in case leaf of                    Success _ _ b _ -> (ReadWord (Lit 0) b) .== (Mul (Lit 2) y)                    _ -> PBool True-        (res, [Qed]) <- withDefaultSolver $ \s ->-          verifyContract s safeAdd (Just (Sig "add(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts (Just pre) (Just post)-        putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+        (res, []) <- withDefaultSolver $ \s ->+          verifyContract s safeAdd (Just (Sig "add(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts (Just pre) post+        putStrLnM $ "successfully explored: " <> show (length res) <> " paths"       ,       test "summary storage writes" $ do         Just c <- solcRuntime "A"@@ -3652,9 +3745,9 @@                   in Expr.add prex (Expr.mul (Lit 2) y) .== (Expr.readStorage' (Lit 0) poststore)                 _ -> PBool True             sig = Just (Sig "f(uint256)" [AbiUIntType 256])-        (res, [Qed]) <- withDefaultSolver $ \s ->-          verifyContract s c sig [] defaultVeriOpts (Just pre) (Just post)-        putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+        (res, []) <- withDefaultSolver $ \s ->+          verifyContract s c sig [] defaultVeriOpts (Just pre) post+        putStrLnM $ "successfully explored: " <> show (length res) <> " paths"         ,         -- tests how whiffValue handles Neg via application of the triple IsZero simplification rule         -- regression test for: https://github.com/dapphub/dapptools/pull/698@@ -3678,8 +3771,8 @@                     }                     |]             Right c <- liftIO $ yulRuntime "Neg" src-            (res, [Qed]) <- withSolvers Z3 4 1 Nothing $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "hello(address)" [AbiAddressType])) [] defaultVeriOpts-            putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+            (res, []) <- withSolvers Z3 4 1 Nothing $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "hello(address)" [AbiAddressType])) [] defaultVeriOpts+            putStrLnM $ "successfully explored: " <> show (length res) <> " paths"         ,         test "catch-storage-collisions-noproblem" $ do           Just c <- solcRuntime "A"@@ -3714,8 +3807,8 @@                        in Expr.add prex prey .== Expr.add postx posty                      _ -> PBool True               sig = Just (Sig "f(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])-          (_, [Qed]) <- withDefaultSolver $ \s ->-            verifyContract s c sig [] defaultVeriOpts (Just pre) (Just post)+          (_, []) <- withDefaultSolver $ \s ->+            verifyContract s c sig [] defaultVeriOpts (Just pre) post           putStrLnM "Correct, this can never fail"         ,         -- Inspired by these `msg.sender == to` token bugs@@ -3752,7 +3845,7 @@                      _ -> PBool True               sig = Just (Sig "f(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])           (_, [Cex (_, ctr)]) <- withDefaultSolver $ \s ->-            verifyContract s c sig [] defaultVeriOpts (Just pre) (Just post)+            verifyContract s c sig [] defaultVeriOpts (Just pre) post           let x = getVar ctr "arg1"           let y = getVar ctr "arg2"           putStrLnM $ "y:" <> show y@@ -3855,8 +3948,8 @@               }             }             |]-          (res, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "foo(uint256)" [AbiUIntType 256])) [] defaultVeriOpts-          putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+          (res, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "foo(uint256)" [AbiUIntType 256])) [] defaultVeriOpts+          putStrLnM $ "successfully explored: " <> show (length res) <> " paths"         ,         -- We zero out everything but the LSB byte. However, byte(31,x) takes the LSB byte         -- so there is a counterexamle, where LSB of x is not zero@@ -3909,8 +4002,8 @@               }             }             |]-          (res, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "foo(uint256)" [AbiUIntType 256])) [] defaultVeriOpts-          putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+          (res, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "foo(uint256)" [AbiUIntType 256])) [] defaultVeriOpts+          putStrLnM $ "successfully explored: " <> show (length res) <> " paths"         ,         -- Bitwise OR operation test         test "opcode-bitwise-or-full-1s" $ do@@ -3925,7 +4018,7 @@               }             }             |]-          (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "foo(uint256)" [AbiUIntType 256])) [] defaultVeriOpts+          (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "foo(uint256)" [AbiUIntType 256])) [] defaultVeriOpts           putStrLnM "When OR-ing with full 1's we should get back full 1's"         ,         -- Bitwise OR operation test@@ -3942,7 +4035,7 @@               }             }             |]-          (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "foo(uint256)" [AbiUIntType 256])) [] defaultVeriOpts+          (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "foo(uint256)" [AbiUIntType 256])) [] defaultVeriOpts           putStrLnM "When OR-ing with a byte of 1's, we should get 1's back there"         ,         test "Deposit contract loop (z3)" $ do@@ -3964,8 +4057,8 @@               }              }             |]-          (res, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "deposit(uint256)" [AbiUIntType 256])) [] defaultVeriOpts-          putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+          (res, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "deposit(uint256)" [AbiUIntType 256])) [] defaultVeriOpts+          putStrLnM $ "successfully explored: " <> show (length res) <> " paths"         ,         test "Deposit-contract-loop-error-version" $ do           Just c <- solcRuntime "Deposit"@@ -3999,8 +4092,8 @@               }             }             |]-          (res, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c Nothing [] defaultVeriOpts-          putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+          (res, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c Nothing [] defaultVeriOpts+          putStrLnM $ "successfully explored: " <> show (length res) <> " paths"         ,         test "check-asm-byte-in-bounds" $ do           Just c <- solcRuntime "C"@@ -4018,7 +4111,7 @@               }             }             |]-          (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c Nothing [] defaultVeriOpts+          (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c Nothing [] defaultVeriOpts           putStrLnM "in bounds byte reads return the expected value"         ,         test "check-div-mod-sdiv-smod-by-zero-constant-prop" $ do@@ -4048,7 +4141,7 @@               }             }             |]-          (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "foo(uint256)" [AbiUIntType 256])) [] defaultVeriOpts+          (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "foo(uint256)" [AbiUIntType 256])) [] defaultVeriOpts           putStrLnM "div/mod/sdiv/smod by zero works as expected during constant propagation"         ,         test "check-asm-byte-oob" $ do@@ -4063,7 +4156,7 @@               }             }             |]-          (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c Nothing [] defaultVeriOpts+          (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c Nothing [] defaultVeriOpts           putStrLnM "oob byte reads always return 0"         ,         test "injectivity of keccak (diff sizes)" $ do@@ -4090,8 +4183,8 @@               }             }             |]-          (res, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "f(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts-          putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+          (res, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "f(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts+          putStrLnM $ "successfully explored: " <> show (length res) <> " paths"         ,         test "injectivity of keccak contrapositive (32 bytes)" $ do           Just c <- solcRuntime "A"@@ -4103,8 +4196,8 @@               }             }             |]-          (res, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "f(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts-          putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+          (res, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "f(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts+          putStrLnM $ "successfully explored: " <> show (length res) <> " paths"         ,         test "injectivity of keccak (64 bytes)" $ do           Just c <- solcRuntime "A"@@ -4138,8 +4231,8 @@               }             }             |]-          (res, [Qed]) <- withBitwuzlaSolver $ \s -> checkAssert s defaultPanicCodes c Nothing [] defaultVeriOpts-          putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+          (res, []) <- withBitwuzlaSolver $ \s -> checkAssert s defaultPanicCodes c Nothing [] defaultVeriOpts+          putStrLnM $ "successfully explored: " <> show (length res) <> " paths"         ,         test "calldata beyond calldatasize is 0 (concrete dalldata prefix)" $ do           Just c <- solcRuntime "A"@@ -4155,8 +4248,8 @@               }             }             |]-          (res, [Qed]) <- withBitwuzlaSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "f(uint256)" [AbiUIntType 256])) [] defaultVeriOpts-          putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+          (res, []) <- withBitwuzlaSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "f(uint256)" [AbiUIntType 256])) [] defaultVeriOpts+          putStrLnM $ "successfully explored: " <> show (length res) <> " paths"         ,         test "calldata symbolic access" $ do           Just c <- solcRuntime "A"@@ -4176,8 +4269,8 @@               }             }             |]-          (res, [Qed]) <- withBitwuzlaSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "f(uint256)" [AbiUIntType 256])) [] defaultVeriOpts-          putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+          (res, []) <- withBitwuzlaSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "f(uint256)" [AbiUIntType 256])) [] defaultVeriOpts+          putStrLnM $ "successfully explored: " <> show (length res) <> " paths"         ,         test "multiple-contracts" $ do           let code =@@ -4205,7 +4298,7 @@                     <&> set (#state % #callvalue) (Lit 0)                     <&> over (#env % #contracts)                        (Map.insert aAddr (initialContract (RuntimeCode (ConcreteRuntimeCode a))))-            verify s (Fetch.oracle s Nothing mempty) defaultVeriOpts vm (Just $ checkAssertions defaultPanicCodes)+            verify s (Fetch.noRpcFetcher s) defaultVeriOpts vm (checkAssertions defaultPanicCodes) Nothing            let storeCex = cex.store               testCex = case (Map.lookup cAddr storeCex, Map.lookup aAddr storeCex) of@@ -4247,8 +4340,8 @@                 }               }             |]-          (res, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "kecc(uint256)" [AbiUIntType 256])) [] defaultVeriOpts-          putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+          (res, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "kecc(uint256)" [AbiUIntType 256])) [] defaultVeriOpts+          putStrLnM $ "successfully explored: " <> show (length res) <> " paths"         ,         test "keccak-concrete-and-sym-agree-nonzero" $ do           Just c <- solcRuntime "C"@@ -4262,8 +4355,8 @@                 }               }             |]-          (res, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "kecc(uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts-          putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+          (res, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "kecc(uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts+          putStrLnM $ "successfully explored: " <> show (length res) <> " paths"         ,         test "keccak concrete and sym injectivity" $ do           Just c <- solcRuntime "A"@@ -4274,14 +4367,14 @@                 }               }             |]-          (res, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "f(uint256)" [AbiUIntType 256])) [] defaultVeriOpts-          putStrLnM $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"+          (res, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "f(uint256)" [AbiUIntType 256])) [] defaultVeriOpts+          putStrLnM $ "successfully explored: " <> show (length res) <> " paths"         ,         test "safemath-distributivity-yul" $ do           let yulsafeDistributivity = hex "6355a79a6260003560e01c14156016576015601f565b5b60006000fd60a1565b603d602d604435600435607c565b6039602435600435607c565b605d565b6052604b604435602435605d565b600435607c565b141515605a57fe5b5b565b6000828201821115151560705760006000fd5b82820190505b92915050565b6000818384048302146000841417151560955760006000fd5b82820290505b92915050565b"           calldata <- mkCalldata (Just (Sig "distributivity(uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) []           vm <- liftIO $ stToIO $ abstractVM calldata yulsafeDistributivity Nothing False-          (_, [Qed]) <-  withDefaultSolver $ \s -> verify s (Fetch.oracle s Nothing mempty) defaultVeriOpts vm (Just $ checkAssertions defaultPanicCodes)+          (_, []) <-  withDefaultSolver $ \s -> verify s (Fetch.noRpcFetcher s) defaultVeriOpts vm (checkAssertions defaultPanicCodes) Nothing           putStrLnM "Proven"         ,         test "safemath-distributivity-sol" $ do@@ -4306,7 +4399,7 @@               }             |] -          (_, [Qed]) <- withSolvers Bitwuzla 1 1 (Just 99999999) $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "distributivity(uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts+          (_, []) <- withSolvers Bitwuzla 1 1 (Just 99999999) $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "distributivity(uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts           putStrLnM "Proven"         ,         test "storage-cex-1" $ do@@ -4372,7 +4465,7 @@             |]           let sig = Just (Sig "fun(uint256)" [AbiUIntType 256])           (_, [Cex (_, cex)]) <- withDefaultSolver $-            \s -> verifyContract s c sig [] defaultVeriOpts Nothing (Just $ checkAssertions [0x01])+            \s -> verifyContract s c sig [] defaultVeriOpts Nothing (checkAssertions [0x01])           let addr = SymAddr "entrypoint"               testCex = Map.size cex.store == 1 &&                         case Map.lookup addr cex.store of@@ -4404,7 +4497,7 @@             }             |]           let sig = (Just (Sig "stuff(address)" [AbiAddressType]))-          (_, [Qed]) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts+          (_, []) <- withDefaultSolver $ \s -> checkAssert s defaultPanicCodes c sig [] defaultVeriOpts           putStrLnM $ "Basic tstore check passed"   ]   , testGroup "simple-checks"@@ -4789,7 +4882,7 @@           |]         withSolvers Bitwuzla 3 1 Nothing $ \s -> do           calldata <- mkCalldata Nothing []-          eq <- equivalenceCheck s a b defaultVeriOpts calldata False+          eq <- equivalenceCheck s Nothing a b defaultVeriOpts calldata False           assertBoolM "Must have a difference" (any (isCex . fst) eq.res)           let cexs = mapMaybe (getCex . fst) eq.res           assertEqualM "Must have exactly one cex" (length cexs) 1@@ -4818,7 +4911,7 @@           |]         withSolvers Bitwuzla 3 1 Nothing $ \s -> do           calldata <- mkCalldata Nothing []-          eq <- equivalenceCheck s a b defaultVeriOpts calldata False+          eq <- equivalenceCheck s Nothing a b defaultVeriOpts calldata False           assertBoolM "Must have a difference" (any (isCex . fst) eq.res)           let cexs = mapMaybe (getCex . fst) eq.res           assertEqualM "Must have exactly one cex" (length cexs) 1@@ -4847,7 +4940,7 @@           |]         withSolvers Bitwuzla 3 1 Nothing $ \s -> do           calldata <- mkCalldata Nothing []-          eq <- equivalenceCheck s a b defaultVeriOpts calldata False+          eq <- equivalenceCheck s Nothing a b defaultVeriOpts calldata False           assertBoolM "Must have a difference" (any (isCex . fst) eq.res)           let cexs = mapMaybe (getCex . fst) eq.res           assertEqualM "Must have exactly one cex" (length cexs) 1@@ -4857,7 +4950,7 @@             b = fromJust (hexByteString "5f356101f40115610100526020610100f3")         withSolvers Z3 3 1 Nothing $ \s -> do           calldata <- mkCalldata Nothing []-          eq <- equivalenceCheck s a b defaultVeriOpts calldata False+          eq <- equivalenceCheck s Nothing a b defaultVeriOpts calldata False           assertBoolM "Must have a difference" (any (isCex . fst) eq.res)           let cexs :: [SMTCex] = mapMaybe (getCex . fst) eq.res           cex <- case cexs of@@ -4889,7 +4982,7 @@           |]         withSolvers Z3 3 1 Nothing $ \s -> do           calldata <- mkCalldata Nothing []-          eq <- equivalenceCheck s aPrgm bPrgm defaultVeriOpts calldata False+          eq <- equivalenceCheck s Nothing aPrgm bPrgm defaultVeriOpts calldata False           assertBoolM "Must have a difference" (any (isCex . fst) eq.res)       , test "constructor-same-deployed-diff" $ do         Just initA <- solidity "C"@@ -4918,7 +5011,7 @@           |]         withSolvers Z3 3 1 Nothing $ \s -> do           calldata <- mkCalldata Nothing []-          eq <- equivalenceCheck s initA initB defaultVeriOpts calldata True+          eq <- equivalenceCheck s Nothing initA initB defaultVeriOpts calldata True           assertBoolM "Must have difference, we return different values" (all (isCex . fst) eq.res)       , test "constructor-same-deployed-diff2" $ do         Just initA <- solidity "C"@@ -4950,7 +5043,7 @@           |]         withSolvers Z3 3 1 Nothing $ \s -> do           calldata <- mkCalldata Nothing []-          eq <- equivalenceCheck s initA initB defaultVeriOpts calldata True+          eq <- equivalenceCheck s Nothing initA initB defaultVeriOpts calldata True           assertBoolM "Must have difference, we return different values" (all (isCex . fst) eq.res)       , test "constructor-same-deployed-diff3" $ do         Just initA <- solidity "C"@@ -4976,7 +5069,7 @@           |]         withSolvers Z3 3 1 Nothing $ \s -> do           calldata <- mkCalldata Nothing []-          eq <- equivalenceCheck s initA initB defaultVeriOpts calldata True+          eq <- equivalenceCheck s Nothing initA initB defaultVeriOpts calldata True           assertBoolM "Must have difference, we return different values" (all (isCex . fst) eq.res)       -- We set x to be 0 on deployment. Default value is also 0. So they are equivalent       -- We cannot deal with symbolic code. However, the below will generate symbolic code,@@ -5009,7 +5102,7 @@           |]         withSolvers Z3 3 1 Nothing $ \s -> do           calldata <- mkCalldata Nothing []-          eq <- equivalenceCheck s initA initB defaultVeriOpts calldata True+          eq <- equivalenceCheck s Nothing initA initB defaultVeriOpts calldata True           assertBoolM "Must have difference" (all (isCex . fst) eq.res)       -- We set x to be 0 on deployment. Default value is also 0. So they are equivalent       , test "constructor-implicit" $ do@@ -5036,8 +5129,9 @@           |]         withSolvers Z3 3 1 Nothing $ \s -> do           calldata <- mkCalldata Nothing []-          eq <- equivalenceCheck s initA initB defaultVeriOpts calldata True-          assertEqualM "Must have no difference" [Qed] (map fst eq.res)+          eq <- equivalenceCheck s Nothing initA initB defaultVeriOpts calldata True+          putStrLnM $ "Equivalence result: " <> show eq+          assertEqualM "Must have no difference" [] (map fst eq.res)       -- We set x to be 3 vs 0 (default) on deployment.       , test "constructor-differing" $ do         Just initA <- solidity "C"@@ -5063,7 +5157,7 @@           |]         withSolvers Z3 3 1 Nothing $ \s -> do           calldata <- mkCalldata Nothing []-          eq <- equivalenceCheck s initA initB defaultVeriOpts calldata True+          eq <- equivalenceCheck s Nothing initA initB defaultVeriOpts calldata True           let cexes = filter (isCex . fst) eq.res           assertBoolM "Must have a difference" (not $ null cexes)       , test "eq-sol-exp-qed" $ do@@ -5089,8 +5183,8 @@           |]         withSolvers Z3 3 1 Nothing $ \s -> do           calldata <- mkCalldata Nothing []-          eq <- equivalenceCheck s aPrgm bPrgm defaultVeriOpts calldata False-          assertEqualM "Must have no difference" [Qed] (map fst eq.res)+          eq <- equivalenceCheck s Nothing aPrgm bPrgm defaultVeriOpts calldata False+          assertEqualM "Must have no difference" [] (map fst eq.res)       ,       test "eq-balance-differs" $ do         Just aPrgm <- solcRuntime "C"@@ -5121,7 +5215,7 @@           |]         withSolvers Z3 3 1 Nothing $ \s -> do           calldata <- mkCalldata Nothing []-          eq <- equivalenceCheck s aPrgm bPrgm defaultVeriOpts calldata False+          eq <- equivalenceCheck s Nothing aPrgm bPrgm defaultVeriOpts calldata False           assertBoolM "Must differ" (all (isCex . fst) eq.res)       ,       -- TODO: this fails because we don't check equivalence of deployed contracts@@ -5183,8 +5277,8 @@           |]         withSolvers Z3 3 1 Nothing $ \s -> do           calldata <- mkCalldata Nothing []-          eq <- equivalenceCheck s aPrgm bPrgm defaultVeriOpts calldata False-          assertBoolM "Must differ" (all (isCex . fst) eq.res)+          eq <- equivalenceCheck s Nothing aPrgm bPrgm defaultVeriOpts calldata False+          assertBoolM "Must differ" (any (isCex . fst) eq.res)       ,       test "eq-unknown-addr" $ do         Just aPrgm <- solcRuntime "C"@@ -5207,7 +5301,7 @@           |]         withSolvers Z3 3 1 Nothing $ \s -> do           cd <- mkCalldata (Just (Sig "a(address,address)" [AbiAddressType, AbiAddressType])) []-          eq <- equivalenceCheck s aPrgm bPrgm defaultVeriOpts cd False+          eq <- equivalenceCheck s Nothing aPrgm bPrgm defaultVeriOpts cd False           assertEqualM "Must be different" (any (isCex . fst) eq.res) True       ,       test "eq-sol-exp-cex" $ do@@ -5233,7 +5327,7 @@           |]         withSolvers Bitwuzla 3 1 Nothing $ \s -> do           calldata <- mkCalldata Nothing []-          eq <- equivalenceCheck s aPrgm bPrgm defaultVeriOpts calldata False+          eq <- equivalenceCheck s Nothing aPrgm bPrgm defaultVeriOpts calldata False           assertEqualM "Must be different" (any (isCex . fst) eq.res) True       ,       test "eq-storage-write-to-static-array-uint128" $ do@@ -5260,8 +5354,8 @@           |]         withSolvers Bitwuzla 1 1 Nothing $ \s -> do           calldata <- mkCalldata (Just (Sig "set(uint256,uint128)" [AbiUIntType 256, AbiUIntType 128])) []-          eq <- equivalenceCheck s aPrgm bPrgm defaultVeriOpts calldata False-          assertEqualM "Must have no difference" [Qed] (map fst eq.res)+          eq <- equivalenceCheck s Nothing aPrgm bPrgm defaultVeriOpts calldata False+          assertEqualM "Must have no difference" [] (map fst eq.res)       ,       test "eq-storage-write-to-static-array-uint8" $ do         Just aPrgm <- solcRuntime "C"@@ -5287,8 +5381,8 @@           |]         withSolvers Bitwuzla 1 1 Nothing $ \s -> do           calldata <- mkCalldata (Just (Sig "set(uint256,uint8)" [AbiUIntType 256, AbiUIntType 8])) []-          eq <- equivalenceCheck s aPrgm bPrgm defaultVeriOpts calldata False-          assertEqualM "Must have no difference" [Qed] (map fst eq.res)+          eq <- equivalenceCheck s Nothing aPrgm bPrgm defaultVeriOpts calldata False+          assertEqualM "Must have no difference" [] (map fst eq.res)       ,       test "eq-storage-write-to-static-array-uint32" $ do         Just aPrgm <- solcRuntime "C"@@ -5314,10 +5408,10 @@           |]         withSolvers Bitwuzla 1 1 Nothing $ \s -> do           calldata <- mkCalldata (Just (Sig "set(uint256,uint32)" [AbiUIntType 256, AbiUIntType 32])) []-          eq <- equivalenceCheck s aPrgm bPrgm defaultVeriOpts calldata False-          assertEqualM "Must have no difference" [Qed] (map fst eq.res)+          eq <- equivalenceCheck s Nothing aPrgm bPrgm defaultVeriOpts calldata False+          assertEqualM "Must have no difference" [] (map fst eq.res)       , test "eq-all-yul-optimization-tests" $ do-        let opts = defaultVeriOpts{ iterConf = defaultIterConf {maxIter = Just 5, askSmtIters = 20, loopHeuristic = Naive }}+        let opts = (defaultVeriOpts :: VeriOpts) { iterConf = defaultIterConf {maxIter = Just 5, askSmtIters = 20, loopHeuristic = Naive }}             ignoredTests =                     -- unbounded loop --                     [ "commonSubexpressionEliminator/branches_for.yul"@@ -5528,7 +5622,7 @@           procs <- liftIO $ getNumProcessors           withSolvers CVC5 (unsafeInto procs) 1 (Just 100) $ \s -> do             calldata <- mkCalldata Nothing []-            eq <- equivalenceCheck s aPrgm bPrgm opts calldata False+            eq <- equivalenceCheck s Nothing aPrgm bPrgm opts calldata False             let res = map fst eq.res             end <- liftIO $ getCurrentTime             case any isCex res of@@ -5578,15 +5672,18 @@  checkEquivBase :: (Eq a, App m) => (a -> a -> Prop) -> a -> a -> Bool -> m (Maybe Bool) checkEquivBase mkprop l r expect = do-  withSolvers Z3 1 1 (Just 1) $ \solvers -> do-     res <- checkSatWithProps solvers [mkprop l r]-     let ret = case res of-           Qed -> Just True-           Cex {} -> Just False-           Error _ -> Just (not expect)-           Unknown _ -> Nothing-     when (ret == Just (not expect)) $ liftIO $ print res-     pure ret+  config <- readConfig+  let noSimplifyEnv = Env {config = config {simp = False}}+  liftIO $ runEnv noSimplifyEnv $ do+    withSolvers Z3 1 1 (Just 1) $ \solvers -> do+      res <- checkSatWithProps solvers [mkprop l r]+      let ret = case res of+            Qed -> Just True+            Cex {} -> Just False+            Error _ -> Just (not expect)+            Unknown _ -> Nothing+      when (ret == Just (not expect)) $ liftIO $ print res+      pure ret  -- | Takes a runtime code and calls it with the provided calldata @@ -5604,7 +5701,7 @@        s -> internalError $ show s  -- | Takes a creation code and returns a vm with the result of executing the creation code-loadVM :: App m => ByteString -> m (Maybe (VM Concrete RealWorld))+loadVM :: App m => ByteString -> m (Maybe (VM Concrete)) loadVM x = do   vm <- liftIO $ stToIO $ vmForEthrunCreation x   vm1 <- Stepper.interpret (Fetch.zero 0 Nothing) vm Stepper.runFully@@ -5670,7 +5767,7 @@     }   |] (abiMethod s (AbiTuple $ V.fromList args)) -getStaticAbiArgs :: Int -> VM Symbolic s -> [Expr EWord]+getStaticAbiArgs :: Int -> VM Symbolic -> [Expr EWord] getStaticAbiArgs n vm =   let cd = vm.state.calldata   in decodeStaticArgs 4 n cd@@ -6031,13 +6128,10 @@ genEnd sz = oneof   [ liftM3 Failure subProp (pure mempty) (fmap Revert subBuf)   , liftM4 Success subProp (pure mempty) subBuf arbitrary-  , liftM3 ITE subWord subEnd subEnd   -- TODO Partial   ]   where     subBuf = defaultBuf (sz `div` 2)-    subWord = defaultWord (sz `div` 2)-    subEnd = genEnd (sz `div` 2)     subProp = genProps False (sz `div` 2)  genWord :: Int -> Int -> Gen (Expr EWord)@@ -6209,8 +6303,8 @@  -- Finds SLoad -> SStore. This should not occur in most scenarios -- as we can simplify them away-badStoresInExpr :: Expr a -> Bool-badStoresInExpr = getAny . foldExpr match mempty+badStoresInExpr :: [Expr a] -> Bool+badStoresInExpr exprs = any (getAny . foldExpr match mempty) exprs   where       match (SLoad _ (SStore _ _ _)) = Any True       match _ = Any False@@ -6260,7 +6354,7 @@ genStorage :: Int -> Gen (Expr Storage) genStorage 0 = oneof   [ liftM2 AbstractStore arbitrary (pure Nothing)-  , fmap ConcreteStore arbitrary+  , fmap ConcreteStore $ resize 5 arbitrary   ] genStorage sz = liftM3 SStore key val subStore   where@@ -6322,7 +6416,7 @@ applyPattern :: String -> TestTree  -> TestTree applyPattern p = localOption (TestPattern (parseExpr p)) -checkBadCheatCode :: Text -> Postcondition s+checkBadCheatCode :: Text -> Postcondition checkBadCheatCode sig _ = \case   (Failure _ c (Revert _)) -> case mapMaybe findBadCheatCode (concatMap flatten c.traces) of     (s:_) -> (ConcreteBuf $ into s.unFunctionSelector) ./= (ConcreteBuf $ selector sig)@@ -6334,20 +6428,19 @@       ErrorTrace (BadCheatCode _ s) -> Just s       _ -> Nothing -allBranchesFail :: App m => ByteString -> Maybe Sig -> m (Either [SMTCex] (Expr End))-allBranchesFail = checkPost (Just p)+allBranchesFail :: App m => ByteString -> Maybe Sig -> m (Either [SMTCex] [Expr End])+allBranchesFail = checkPost p   where     p _ = \case       Success _ _ _ _ -> PBool False       _ -> PBool True -reachableUserAsserts :: App m => ByteString -> Maybe Sig -> m (Either [SMTCex] (Expr End))-reachableUserAsserts = checkPost (Just $ checkAssertions [0x01])+reachableUserAsserts :: App m => ByteString -> Maybe Sig -> m (Either [SMTCex] [Expr End])+reachableUserAsserts = checkPost (checkAssertions [0x01]) -checkPost :: App m => Maybe (Postcondition RealWorld) -> ByteString -> Maybe Sig -> m (Either [SMTCex] (Expr End))+checkPost :: App m => Postcondition -> ByteString -> Maybe Sig -> m (Either [SMTCex] [Expr End]) checkPost post c sig = do-  (e, res) <- withDefaultSolver $ \s ->-    verifyContract s c sig [] defaultVeriOpts Nothing post+  (e, res) <- withDefaultSolver $ \s -> verifyContract s c sig [] defaultVeriOpts Nothing post   let cexs = snd <$> mapMaybe getCex res   case cexs of     [] -> pure $ Right e