packages feed

hevm 0.50.4 → 0.50.5

raw patch · 37 files changed

+5506/−5417 lines, 37 filesdep +aeson-opticsdep +optics-coredep +optics-extradep −lensdep −lens-aesondep ~containersdep ~filepathdep ~mtlPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: aeson-optics, optics-core, optics-extra, optics-th

Dependencies removed: lens, lens-aeson

Dependency ranges changed: containers, filepath, mtl

API changes (from Hackage documentation)

- EVM: Concrete :: StorageBase
- EVM: ConcreteS :: StorageModel
- EVM: InitialS :: StorageModel
- EVM: Symbolic :: StorageBase
- EVM: SymbolicS :: StorageModel
- EVM: [$sel:_accessedAddresses:SubState] :: SubState -> Set Addr
- EVM: [$sel:_accessedStorageKeys:SubState] :: SubState -> Set (Addr, W256)
- EVM: [$sel:_allowFFI:VM] :: VM -> Bool
- EVM: [$sel:_balance:Contract] :: Contract -> W256
- EVM: [$sel:_baseFee:Block] :: Block -> W256
- EVM: [$sel:_block:VM] :: VM -> Block
- EVM: [$sel:_burned:VM] :: VM -> {-# UNPACK #-} !Word64
- EVM: [$sel:_cache:VM] :: VM -> Cache
- EVM: [$sel:_calldata:FrameState] :: FrameState -> Expr Buf
- EVM: [$sel:_caller:FrameState] :: FrameState -> Expr EWord
- EVM: [$sel:_callvalue:FrameState] :: FrameState -> Expr EWord
- EVM: [$sel:_chainId:Env] :: Env -> W256
- EVM: [$sel:_code:FrameState] :: FrameState -> ContractCode
- EVM: [$sel:_codeContract:FrameState] :: FrameState -> Addr
- EVM: [$sel:_codeOps:Contract] :: Contract -> Vector (Int, Op)
- EVM: [$sel:_codehash:Contract] :: Contract -> Expr EWord
- EVM: [$sel:_coinbase:Block] :: Block -> Addr
- EVM: [$sel:_constraints:VM] :: VM -> [Prop]
- EVM: [$sel:_contract:FrameState] :: FrameState -> Addr
- EVM: [$sel:_contractcode:Contract] :: Contract -> ContractCode
- EVM: [$sel:_contracts:Env] :: Env -> Map Addr Contract
- EVM: [$sel:_env:VM] :: VM -> Env
- EVM: [$sel:_external:Contract] :: Contract -> Bool
- EVM: [$sel:_fetchedContracts:Cache] :: Cache -> Map Addr Contract
- EVM: [$sel:_fetchedStorage:Cache] :: Cache -> Map W256 (Map W256 W256)
- EVM: [$sel:_frameContext:Frame] :: Frame -> FrameContext
- EVM: [$sel:_frameState:Frame] :: Frame -> FrameState
- EVM: [$sel:_frames:VM] :: VM -> [Frame]
- EVM: [$sel:_gas:FrameState] :: FrameState -> {-# UNPACK #-} !Word64
- EVM: [$sel:_gaslimit:Block] :: Block -> Word64
- EVM: [$sel:_gasprice:TxState] :: TxState -> W256
- EVM: [$sel:_isCreate:TxState] :: TxState -> Bool
- EVM: [$sel:_iterations:VM] :: VM -> Map CodeLocation Int
- EVM: [$sel:_keccakEqs:VM] :: VM -> [Prop]
- EVM: [$sel:_logs:VM] :: VM -> [Expr Log]
- EVM: [$sel:_maxCodeSize:Block] :: Block -> W256
- EVM: [$sel:_memory:FrameState] :: FrameState -> Expr Buf
- EVM: [$sel:_memorySize:FrameState] :: FrameState -> Word64
- EVM: [$sel:_nonce:Contract] :: Contract -> W256
- EVM: [$sel:_number:Block] :: Block -> W256
- EVM: [$sel:_opIxMap:Contract] :: Contract -> Vector Int
- EVM: [$sel:_origStorage:Env] :: Env -> Map W256 (Map W256 W256)
- EVM: [$sel:_origin:TxState] :: TxState -> Addr
- EVM: [$sel:_overrideCaller:VM] :: VM -> Maybe (Expr EWord)
- EVM: [$sel:_path:Cache] :: Cache -> Map (CodeLocation, Int) Bool
- EVM: [$sel:_pc:FrameState] :: FrameState -> {-# UNPACK #-} !Int
- EVM: [$sel:_prevRandao:Block] :: Block -> W256
- EVM: [$sel:_refunds:SubState] :: SubState -> [(Addr, Word64)]
- EVM: [$sel:_result:VM] :: VM -> Maybe VMResult
- EVM: [$sel:_returndata:FrameState] :: FrameState -> Expr Buf
- EVM: [$sel:_schedule:Block] :: Block -> FeeSchedule Word64
- EVM: [$sel:_selfdestructs:SubState] :: SubState -> [Addr]
- EVM: [$sel:_sha3Crack:Env] :: Env -> Map W256 ByteString
- EVM: [$sel:_stack:FrameState] :: FrameState -> [Expr EWord]
- EVM: [$sel:_state:VM] :: VM -> FrameState
- EVM: [$sel:_static:FrameState] :: FrameState -> Bool
- EVM: [$sel:_storage:Env] :: Env -> Expr Storage
- EVM: [$sel:_substate:TxState] :: TxState -> SubState
- EVM: [$sel:_timestamp:Block] :: Block -> Expr EWord
- EVM: [$sel:_toAddr:TxState] :: TxState -> Addr
- EVM: [$sel:_touchedAccounts:SubState] :: SubState -> [Addr]
- EVM: [$sel:_traceContract:Trace] :: Trace -> Contract
- EVM: [$sel:_traceData:Trace] :: Trace -> TraceData
- EVM: [$sel:_traceOpIx:Trace] :: Trace -> Int
- EVM: [$sel:_traces:VM] :: VM -> TreePos Empty Trace
- EVM: [$sel:_tx:VM] :: VM -> TxState
- EVM: [$sel:_txPriorityFee:TxState] :: TxState -> W256
- EVM: [$sel:_txReversion:TxState] :: TxState -> Map Addr Contract
- EVM: [$sel:_txgaslimit:TxState] :: TxState -> Word64
- EVM: [$sel:_value:TxState] :: TxState -> Expr EWord
- EVM: [$sel:callContextAbi:CreationContext] :: FrameContext -> Maybe W256
- EVM: [$sel:callContextCodehash:CreationContext] :: FrameContext -> Expr EWord
- EVM: [$sel:callContextContext:CreationContext] :: FrameContext -> Addr
- EVM: [$sel:callContextData:CreationContext] :: FrameContext -> Expr Buf
- EVM: [$sel:callContextOffset:CreationContext] :: FrameContext -> W256
- EVM: [$sel:callContextReversion:CreationContext] :: FrameContext -> (Map Addr Contract, Expr Storage)
- EVM: [$sel:callContextSize:CreationContext] :: FrameContext -> W256
- EVM: [$sel:callContextSubState:CreationContext] :: FrameContext -> SubState
- EVM: [$sel:callContextTarget:CreationContext] :: FrameContext -> Addr
- EVM: [$sel:creationContextAddress:CreationContext] :: FrameContext -> Addr
- EVM: [$sel:creationContextCodehash:CreationContext] :: FrameContext -> Expr EWord
- EVM: [$sel:creationContextReversion:CreationContext] :: FrameContext -> Map Addr Contract
- EVM: [$sel:creationContextSubstate:CreationContext] :: FrameContext -> SubState
- EVM: [$sel:vmoptAddress:VMOpts] :: VMOpts -> Addr
- EVM: [$sel:vmoptAllowFFI:VMOpts] :: VMOpts -> Bool
- EVM: [$sel:vmoptBaseFee:VMOpts] :: VMOpts -> W256
- EVM: [$sel:vmoptBlockGaslimit:VMOpts] :: VMOpts -> Word64
- EVM: [$sel:vmoptCalldata:VMOpts] :: VMOpts -> (Expr Buf, [Prop])
- EVM: [$sel:vmoptCaller:VMOpts] :: VMOpts -> Expr EWord
- EVM: [$sel:vmoptChainId:VMOpts] :: VMOpts -> W256
- EVM: [$sel:vmoptCoinbase:VMOpts] :: VMOpts -> Addr
- EVM: [$sel:vmoptContract:VMOpts] :: VMOpts -> Contract
- EVM: [$sel:vmoptCreate:VMOpts] :: VMOpts -> Bool
- EVM: [$sel:vmoptGas:VMOpts] :: VMOpts -> Word64
- EVM: [$sel:vmoptGaslimit:VMOpts] :: VMOpts -> Word64
- EVM: [$sel:vmoptGasprice:VMOpts] :: VMOpts -> W256
- EVM: [$sel:vmoptMaxCodeSize:VMOpts] :: VMOpts -> W256
- EVM: [$sel:vmoptNumber:VMOpts] :: VMOpts -> W256
- EVM: [$sel:vmoptOrigin:VMOpts] :: VMOpts -> Addr
- EVM: [$sel:vmoptPrevRandao:VMOpts] :: VMOpts -> W256
- EVM: [$sel:vmoptPriorityFee:VMOpts] :: VMOpts -> W256
- EVM: [$sel:vmoptSchedule:VMOpts] :: VMOpts -> FeeSchedule Word64
- EVM: [$sel:vmoptStorageBase:VMOpts] :: VMOpts -> StorageBase
- EVM: [$sel:vmoptTimestamp:VMOpts] :: VMOpts -> Expr EWord
- EVM: [$sel:vmoptTxAccessList:VMOpts] :: VMOpts -> Map Addr [W256]
- EVM: [$sel:vmoptValue:VMOpts] :: VMOpts -> Expr EWord
- EVM: accessedAddresses :: Lens' SubState (Set Addr)
- EVM: accessedStorageKeys :: Lens' SubState (Set (Addr, W256))
- EVM: allowFFI :: Lens' VM Bool
- EVM: balance :: Lens' Contract W256
- EVM: baseFee :: Lens' Block W256
- EVM: block :: Lens' VM Block
- EVM: burned :: Lens' VM Word64
- EVM: cache :: Lens' VM Cache
- EVM: calldata :: Lens' FrameState (Expr 'Buf)
- EVM: caller :: Lens' FrameState (Expr 'EWord)
- EVM: callvalue :: Lens' FrameState (Expr 'EWord)
- EVM: chainId :: Lens' Env W256
- EVM: code :: Lens' FrameState ContractCode
- EVM: codeContract :: Lens' FrameState Addr
- EVM: codeOps :: Lens' Contract (Vector (Int, Op))
- EVM: codehash :: Lens' Contract (Expr 'EWord)
- EVM: coinbase :: Lens' Block Addr
- EVM: constraints :: Lens' VM [Prop]
- EVM: contract :: Lens' FrameState Addr
- EVM: contractcode :: Lens' Contract ContractCode
- EVM: contracts :: Lens' Env (Map Addr Contract)
- EVM: data StorageBase
- EVM: data StorageModel
- EVM: env :: Lens' VM Env
- EVM: ethsign :: PrivateKey -> Digest Keccak_256 -> Signature
- EVM: external :: Lens' Contract Bool
- EVM: fetchedContracts :: Lens' Cache (Map Addr Contract)
- EVM: fetchedStorage :: Lens' Cache (Map W256 (Map W256 W256))
- EVM: frameContext :: Lens' Frame FrameContext
- EVM: frameState :: Lens' Frame FrameState
- EVM: frames :: Lens' VM [Frame]
- EVM: gas :: Lens' FrameState Word64
- EVM: gaslimit :: Lens' Block Word64
- EVM: gasprice :: Lens' TxState W256
- EVM: instance GHC.Classes.Eq EVM.StorageBase
- EVM: instance GHC.Read.Read EVM.StorageModel
- EVM: instance GHC.Show.Show EVM.StorageBase
- EVM: instance GHC.Show.Show EVM.StorageModel
- EVM: instance Options.Generic.ParseField EVM.StorageModel
- EVM: isCreate :: Lens' TxState Bool
- EVM: iterations :: Lens' VM (Map CodeLocation Int)
- EVM: keccakEqs :: Lens' VM [Prop]
- EVM: logs :: Lens' VM [Expr 'Log]
- EVM: maxCodeSize :: Lens' Block W256
- EVM: memory :: Lens' FrameState (Expr 'Buf)
- EVM: memorySize :: Lens' FrameState Word64
- EVM: nonce :: Lens' Contract W256
- EVM: number :: Lens' Block W256
- EVM: opIxMap :: Lens' Contract (Vector Int)
- EVM: opParams :: VM -> Map String (Expr EWord)
- EVM: origStorage :: Lens' Env (Map W256 (Map W256 W256))
- EVM: origin :: Lens' TxState Addr
- EVM: overrideCaller :: Lens' VM (Maybe (Expr 'EWord))
- EVM: path :: Lens' Cache (Map (CodeLocation, Int) Bool)
- EVM: pc :: Lens' FrameState Int
- EVM: prevRandao :: Lens' Block W256
- EVM: refunds :: Lens' SubState [(Addr, Word64)]
- EVM: result :: Lens' VM (Maybe VMResult)
- EVM: returndata :: Lens' FrameState (Expr 'Buf)
- EVM: schedule :: Lens' Block (FeeSchedule Word64)
- EVM: selfdestructs :: Lens' SubState [Addr]
- EVM: sha3Crack :: Lens' Env (Map W256 ByteString)
- EVM: stack :: Lens' FrameState [Expr 'EWord]
- EVM: state :: Lens' VM FrameState
- EVM: static :: Lens' FrameState Bool
- EVM: storage :: Lens' Env (Expr 'Storage)
- EVM: substate :: Lens' TxState SubState
- EVM: timestamp :: Lens' Block (Expr 'EWord)
- EVM: toAddr :: Lens' TxState Addr
- EVM: touchedAccounts :: Lens' SubState [Addr]
- EVM: traceContract :: Lens' Trace Contract
- EVM: traceData :: Lens' Trace TraceData
- EVM: traceOpIx :: Lens' Trace Int
- EVM: traces :: Lens' VM (TreePos Empty Trace)
- EVM: tx :: Lens' VM TxState
- EVM: txPriorityFee :: Lens' TxState W256
- EVM: txReversion :: Lens' TxState (Map Addr Contract)
- EVM: txgaslimit :: Lens' TxState Word64
- EVM: value :: Lens' TxState (Expr 'EWord)
- EVM.Demand: demand :: (MonadIO m, NFData a) => a -> m ()
- EVM.Facts: instance EVM.Facts.AsASCII Data.ByteString.Internal.ByteString
- EVM.SMT: [$sel:blockContextV:CexVars] :: CexVars -> [Text]
- EVM.SMT: [$sel:buffersV:CexVars] :: CexVars -> Map Text (Expr EWord)
- EVM.SMT: [$sel:calldataV:CexVars] :: CexVars -> [Text]
- EVM.SMT: [$sel:txContextV:CexVars] :: CexVars -> [Text]
- EVM.Solidity: [$sel:srcMapFile:SM] :: SrcMap -> {-# UNPACK #-} !Int
- EVM.Solidity: [$sel:srcMapJump:SM] :: SrcMap -> JumpType
- EVM.Solidity: [$sel:srcMapLength:SM] :: SrcMap -> {-# UNPACK #-} !Int
- EVM.Solidity: [$sel:srcMapModifierDepth:SM] :: SrcMap -> {-# UNPACK #-} !Int
- EVM.Solidity: [$sel:srcMapOffset:SM] :: SrcMap -> {-# UNPACK #-} !Int
- EVM.Solvers: [$sel:_process:SolverInstance] :: SolverInstance -> ProcessHandle
- EVM.Solvers: [$sel:_stderr:SolverInstance] :: SolverInstance -> Handle
- EVM.Solvers: [$sel:_stdin:SolverInstance] :: SolverInstance -> Handle
- EVM.Solvers: [$sel:_stdout:SolverInstance] :: SolverInstance -> Handle
- EVM.Solvers: [$sel:_type:SolverInstance] :: SolverInstance -> Solver
- EVM.TTY: [$sel:_browserContractList:UiBrowserState] :: UiBrowserState -> List Name (Addr, Contract)
- EVM.TTY: [$sel:_browserVm:UiBrowserState] :: UiBrowserState -> UiVmState
- EVM.TTY: [$sel:_testOpts:UiTestPickerState] :: UiTestPickerState -> UnitTestOptions
- EVM.TTY: [$sel:_testPickerDapp:UiTestPickerState] :: UiTestPickerState -> DappInfo
- EVM.TTY: [$sel:_testPickerList:UiTestPickerState] :: UiTestPickerState -> List Name (Text, Text)
- EVM.TTY: [$sel:_uiShowMemory:UiVmState] :: UiVmState -> Bool
- EVM.TTY: [$sel:_uiSnapshots:UiVmState] :: UiVmState -> Map Int (VM, Stepper ())
- EVM.TTY: [$sel:_uiStep:UiVmState] :: UiVmState -> Int
- EVM.TTY: [$sel:_uiStepper:UiVmState] :: UiVmState -> Stepper ()
- EVM.TTY: [$sel:_uiTestOpts:UiVmState] :: UiVmState -> UnitTestOptions
- EVM.TTY: [$sel:_uiVm:UiVmState] :: UiVmState -> VM
- EVM.TTY: browserContractList :: Lens' UiBrowserState (List Name (Addr, Contract))
- EVM.TTY: browserVm :: Lens' UiBrowserState UiVmState
- EVM.TTY: testOpts :: Lens' UiTestPickerState UnitTestOptions
- EVM.TTY: testPickerDapp :: Lens' UiTestPickerState DappInfo
- EVM.TTY: testPickerList :: Lens' UiTestPickerState (List Name (Text, Text))
- EVM.TTY: uiShowMemory :: Lens' UiVmState Bool
- EVM.TTY: uiSnapshots :: Lens' UiVmState (Map Int (VM, Stepper ()))
- EVM.TTY: uiStep :: Lens' UiVmState Int
- EVM.TTY: uiStepper :: Lens' UiVmState (Stepper ())
- EVM.TTY: uiTestOpts :: Lens' UiVmState UnitTestOptions
- EVM.TTY: uiVm :: Lens' UiVmState VM
- EVM.Transaction: [$sel:accessAddress:AccessListEntry] :: AccessListEntry -> Addr
- EVM.Transaction: [$sel:accessStorageKeys:AccessListEntry] :: AccessListEntry -> [W256]
- EVM.Transaction: [$sel:txAccessList:Transaction] :: Transaction -> [AccessListEntry]
- EVM.Transaction: [$sel:txChainId:Transaction] :: Transaction -> W256
- EVM.Transaction: [$sel:txData:Transaction] :: Transaction -> ByteString
- EVM.Transaction: [$sel:txGasLimit:Transaction] :: Transaction -> Word64
- EVM.Transaction: [$sel:txGasPrice:Transaction] :: Transaction -> Maybe W256
- EVM.Transaction: [$sel:txMaxFeePerGas:Transaction] :: Transaction -> Maybe W256
- EVM.Transaction: [$sel:txMaxPriorityFeeGas:Transaction] :: Transaction -> Maybe W256
- EVM.Transaction: [$sel:txNonce:Transaction] :: Transaction -> W256
- EVM.Transaction: [$sel:txR:Transaction] :: Transaction -> W256
- EVM.Transaction: [$sel:txS:Transaction] :: Transaction -> W256
- EVM.Transaction: [$sel:txToAddr:Transaction] :: Transaction -> Maybe Addr
- EVM.Transaction: [$sel:txType:Transaction] :: Transaction -> TxType
- EVM.Transaction: [$sel:txV:Transaction] :: Transaction -> W256
- EVM.Transaction: [$sel:txValue:Transaction] :: Transaction -> W256
- EVM.UnitTest: [$sel:testAddress:TestVMParams] :: TestVMParams -> Addr
- EVM.UnitTest: [$sel:testBalanceCreate:TestVMParams] :: TestVMParams -> W256
- EVM.UnitTest: [$sel:testBaseFee:TestVMParams] :: TestVMParams -> W256
- EVM.UnitTest: [$sel:testCaller:TestVMParams] :: TestVMParams -> Addr
- EVM.UnitTest: [$sel:testChainId:TestVMParams] :: TestVMParams -> W256
- EVM.UnitTest: [$sel:testCoinbase:TestVMParams] :: TestVMParams -> Addr
- EVM.UnitTest: [$sel:testGasCall:TestVMParams] :: TestVMParams -> Word64
- EVM.UnitTest: [$sel:testGasCreate:TestVMParams] :: TestVMParams -> Word64
- EVM.UnitTest: [$sel:testGaslimit:TestVMParams] :: TestVMParams -> Word64
- EVM.UnitTest: [$sel:testGasprice:TestVMParams] :: TestVMParams -> W256
- EVM.UnitTest: [$sel:testMaxCodeSize:TestVMParams] :: TestVMParams -> W256
- EVM.UnitTest: [$sel:testNumber:TestVMParams] :: TestVMParams -> W256
- EVM.UnitTest: [$sel:testOrigin:TestVMParams] :: TestVMParams -> Addr
- EVM.UnitTest: [$sel:testPrevrandao:TestVMParams] :: TestVMParams -> W256
- EVM.UnitTest: [$sel:testPriorityFee:TestVMParams] :: TestVMParams -> W256
- EVM.UnitTest: [$sel:testTimestamp:TestVMParams] :: TestVMParams -> W256
+ EVM: [$sel:abi:CreationContext] :: FrameContext -> Maybe W256
+ EVM: [$sel:accessedAddresses:SubState] :: SubState -> Set Addr
+ EVM: [$sel:accessedStorageKeys:SubState] :: SubState -> Set (Addr, W256)
+ EVM: [$sel:address:CreationContext] :: FrameContext -> Addr
+ EVM: [$sel:address:VMOpts] :: VMOpts -> Addr
+ EVM: [$sel:allowFFI:VMOpts] :: VMOpts -> Bool
+ EVM: [$sel:allowFFI:VM] :: VM -> Bool
+ EVM: [$sel:balance:Contract] :: Contract -> W256
+ EVM: [$sel:baseFee:Block] :: Block -> W256
+ EVM: [$sel:baseFee:VMOpts] :: VMOpts -> W256
+ EVM: [$sel:block:VM] :: VM -> Block
+ EVM: [$sel:blockGaslimit:VMOpts] :: VMOpts -> Word64
+ EVM: [$sel:burned:VM] :: VM -> {-# UNPACK #-} !Word64
+ EVM: [$sel:cache:VM] :: VM -> Cache
+ EVM: [$sel:calldata:CreationContext] :: FrameContext -> Expr Buf
+ EVM: [$sel:calldata:FrameState] :: FrameState -> Expr Buf
+ EVM: [$sel:calldata:VMOpts] :: VMOpts -> (Expr Buf, [Prop])
+ EVM: [$sel:caller:FrameState] :: FrameState -> Expr EWord
+ EVM: [$sel:caller:VMOpts] :: VMOpts -> Expr EWord
+ EVM: [$sel:callreversion:CreationContext] :: FrameContext -> (Map Addr Contract, Expr Storage)
+ EVM: [$sel:callvalue:FrameState] :: FrameState -> Expr EWord
+ EVM: [$sel:chainId:Env] :: Env -> W256
+ EVM: [$sel:chainId:VMOpts] :: VMOpts -> W256
+ EVM: [$sel:code:FrameState] :: FrameState -> ContractCode
+ EVM: [$sel:codeContract:FrameState] :: FrameState -> Addr
+ EVM: [$sel:codeOps:Contract] :: Contract -> Vector (Int, Op)
+ EVM: [$sel:codehash:Contract] :: Contract -> Expr EWord
+ EVM: [$sel:codehash:CreationContext] :: FrameContext -> Expr EWord
+ EVM: [$sel:coinbase:Block] :: Block -> Addr
+ EVM: [$sel:coinbase:VMOpts] :: VMOpts -> Addr
+ EVM: [$sel:constraints:VM] :: VM -> [Prop]
+ EVM: [$sel:context:CreationContext] :: FrameContext -> Addr
+ EVM: [$sel:context:Frame] :: Frame -> FrameContext
+ EVM: [$sel:contract:FrameState] :: FrameState -> Addr
+ EVM: [$sel:contract:Trace] :: Trace -> Contract
+ EVM: [$sel:contract:VMOpts] :: VMOpts -> Contract
+ EVM: [$sel:contractcode:Contract] :: Contract -> ContractCode
+ EVM: [$sel:contracts:Env] :: Env -> Map Addr Contract
+ EVM: [$sel:create:VMOpts] :: VMOpts -> Bool
+ EVM: [$sel:createreversion:CreationContext] :: FrameContext -> Map Addr Contract
+ EVM: [$sel:env:VM] :: VM -> Env
+ EVM: [$sel:external:Contract] :: Contract -> Bool
+ EVM: [$sel:fetchedContracts:Cache] :: Cache -> Map Addr Contract
+ EVM: [$sel:fetchedStorage:Cache] :: Cache -> Map W256 (Map W256 W256)
+ EVM: [$sel:frames:VM] :: VM -> [Frame]
+ EVM: [$sel:gas:FrameState] :: FrameState -> {-# UNPACK #-} !Word64
+ EVM: [$sel:gas:VMOpts] :: VMOpts -> Word64
+ EVM: [$sel:gaslimit:Block] :: Block -> Word64
+ EVM: [$sel:gaslimit:TxState] :: TxState -> Word64
+ EVM: [$sel:gaslimit:VMOpts] :: VMOpts -> Word64
+ EVM: [$sel:gasprice:TxState] :: TxState -> W256
+ EVM: [$sel:gasprice:VMOpts] :: VMOpts -> W256
+ EVM: [$sel:initialStorage:VMOpts] :: VMOpts -> Expr Storage
+ EVM: [$sel:isCreate:TxState] :: TxState -> Bool
+ EVM: [$sel:iterations:VM] :: VM -> Map CodeLocation Int
+ EVM: [$sel:keccakEqs:VM] :: VM -> [Prop]
+ EVM: [$sel:logs:VM] :: VM -> [Expr Log]
+ EVM: [$sel:maxCodeSize:Block] :: Block -> W256
+ EVM: [$sel:maxCodeSize:VMOpts] :: VMOpts -> W256
+ EVM: [$sel:memory:FrameState] :: FrameState -> Expr Buf
+ EVM: [$sel:memorySize:FrameState] :: FrameState -> Word64
+ EVM: [$sel:nonce:Contract] :: Contract -> W256
+ EVM: [$sel:number:Block] :: Block -> W256
+ EVM: [$sel:number:VMOpts] :: VMOpts -> W256
+ EVM: [$sel:offset:CreationContext] :: FrameContext -> W256
+ EVM: [$sel:opIx:Trace] :: Trace -> Int
+ EVM: [$sel:opIxMap:Contract] :: Contract -> Vector Int
+ EVM: [$sel:origStorage:Env] :: Env -> Map W256 (Map W256 W256)
+ EVM: [$sel:origin:TxState] :: TxState -> Addr
+ EVM: [$sel:origin:VMOpts] :: VMOpts -> Addr
+ EVM: [$sel:overrideCaller:VM] :: VM -> Maybe Addr
+ EVM: [$sel:path:Cache] :: Cache -> Map (CodeLocation, Int) Bool
+ EVM: [$sel:pc:FrameState] :: FrameState -> {-# UNPACK #-} !Int
+ EVM: [$sel:prevRandao:Block] :: Block -> W256
+ EVM: [$sel:prevRandao:VMOpts] :: VMOpts -> W256
+ EVM: [$sel:priorityFee:TxState] :: TxState -> W256
+ EVM: [$sel:priorityFee:VMOpts] :: VMOpts -> W256
+ EVM: [$sel:refunds:SubState] :: SubState -> [(Addr, Word64)]
+ EVM: [$sel:result:VM] :: VM -> Maybe VMResult
+ EVM: [$sel:returndata:FrameState] :: FrameState -> Expr Buf
+ EVM: [$sel:schedule:Block] :: Block -> FeeSchedule Word64
+ EVM: [$sel:schedule:VMOpts] :: VMOpts -> FeeSchedule Word64
+ EVM: [$sel:selfdestructs:SubState] :: SubState -> [Addr]
+ EVM: [$sel:sha3Crack:Env] :: Env -> Map W256 ByteString
+ EVM: [$sel:size:CreationContext] :: FrameContext -> W256
+ EVM: [$sel:stack:FrameState] :: FrameState -> [Expr EWord]
+ EVM: [$sel:state:Frame] :: Frame -> FrameState
+ EVM: [$sel:state:VM] :: VM -> FrameState
+ EVM: [$sel:static:FrameState] :: FrameState -> Bool
+ EVM: [$sel:storage:Env] :: Env -> Expr Storage
+ EVM: [$sel:subState:CreationContext] :: FrameContext -> SubState
+ EVM: [$sel:substate:CreationContext] :: FrameContext -> SubState
+ EVM: [$sel:substate:TxState] :: TxState -> SubState
+ EVM: [$sel:target:CreationContext] :: FrameContext -> Addr
+ EVM: [$sel:timestamp:Block] :: Block -> Expr EWord
+ EVM: [$sel:timestamp:VMOpts] :: VMOpts -> Expr EWord
+ EVM: [$sel:toAddr:TxState] :: TxState -> Addr
+ EVM: [$sel:touchedAccounts:SubState] :: SubState -> [Addr]
+ EVM: [$sel:tracedata:Trace] :: Trace -> TraceData
+ EVM: [$sel:traces:VM] :: VM -> TreePos Empty Trace
+ EVM: [$sel:tx:VM] :: VM -> TxState
+ EVM: [$sel:txAccessList:VMOpts] :: VMOpts -> Map Addr [W256]
+ EVM: [$sel:txReversion:TxState] :: TxState -> Map Addr Contract
+ EVM: [$sel:value:TxState] :: TxState -> Expr EWord
+ EVM: [$sel:value:VMOpts] :: VMOpts -> Expr EWord
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ (EVM.Types.Expr 'EVM.Types.Buf, [EVM.Types.Prop]), b GHC.Types.~ (EVM.Types.Expr 'EVM.Types.Buf, [EVM.Types.Prop])) => Optics.Label.LabelOptic "calldata" k EVM.VMOpts EVM.VMOpts a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Map.Internal.Map (EVM.CodeLocation, GHC.Types.Int) GHC.Types.Bool, b GHC.Types.~ Data.Map.Internal.Map (EVM.CodeLocation, GHC.Types.Int) GHC.Types.Bool) => Optics.Label.LabelOptic "path" k EVM.Cache EVM.Cache a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Map.Internal.Map EVM.CodeLocation GHC.Types.Int, b GHC.Types.~ Data.Map.Internal.Map EVM.CodeLocation GHC.Types.Int) => Optics.Label.LabelOptic "iterations" k EVM.VM EVM.VM a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Map.Internal.Map EVM.Types.Addr EVM.Contract, b GHC.Types.~ Data.Map.Internal.Map EVM.Types.Addr EVM.Contract) => Optics.Label.LabelOptic "contracts" k EVM.Env EVM.Env a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Map.Internal.Map EVM.Types.Addr EVM.Contract, b GHC.Types.~ Data.Map.Internal.Map EVM.Types.Addr EVM.Contract) => Optics.Label.LabelOptic "fetchedContracts" k EVM.Cache EVM.Cache a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Map.Internal.Map EVM.Types.Addr EVM.Contract, b GHC.Types.~ Data.Map.Internal.Map EVM.Types.Addr EVM.Contract) => Optics.Label.LabelOptic "txReversion" k EVM.TxState EVM.TxState a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Map.Internal.Map EVM.Types.Addr [EVM.Types.W256], b GHC.Types.~ Data.Map.Internal.Map EVM.Types.Addr [EVM.Types.W256]) => Optics.Label.LabelOptic "txAccessList" k EVM.VMOpts EVM.VMOpts a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Map.Internal.Map EVM.Types.W256 (Data.Map.Internal.Map EVM.Types.W256 EVM.Types.W256), b GHC.Types.~ Data.Map.Internal.Map EVM.Types.W256 (Data.Map.Internal.Map EVM.Types.W256 EVM.Types.W256)) => Optics.Label.LabelOptic "fetchedStorage" k EVM.Cache EVM.Cache a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Map.Internal.Map EVM.Types.W256 (Data.Map.Internal.Map EVM.Types.W256 EVM.Types.W256), b GHC.Types.~ Data.Map.Internal.Map EVM.Types.W256 (Data.Map.Internal.Map EVM.Types.W256 EVM.Types.W256)) => Optics.Label.LabelOptic "origStorage" k EVM.Env EVM.Env a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Map.Internal.Map EVM.Types.W256 Data.ByteString.Internal.Type.ByteString, b GHC.Types.~ Data.Map.Internal.Map EVM.Types.W256 Data.ByteString.Internal.Type.ByteString) => Optics.Label.LabelOptic "sha3Crack" k EVM.Env EVM.Env a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Set.Internal.Set (EVM.Types.Addr, EVM.Types.W256), b GHC.Types.~ Data.Set.Internal.Set (EVM.Types.Addr, EVM.Types.W256)) => Optics.Label.LabelOptic "accessedStorageKeys" k EVM.SubState EVM.SubState a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Set.Internal.Set EVM.Types.Addr, b GHC.Types.~ Data.Set.Internal.Set EVM.Types.Addr) => Optics.Label.LabelOptic "accessedAddresses" k EVM.SubState EVM.SubState a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Tree.Zipper.TreePos Data.Tree.Zipper.Empty EVM.Trace, b GHC.Types.~ Data.Tree.Zipper.TreePos Data.Tree.Zipper.Empty EVM.Trace) => Optics.Label.LabelOptic "traces" k EVM.VM EVM.VM a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Vector.Storable.Vector GHC.Types.Int, b GHC.Types.~ Data.Vector.Storable.Vector GHC.Types.Int) => Optics.Label.LabelOptic "opIxMap" k EVM.Contract EVM.Contract a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Vector.Vector (GHC.Types.Int, EVM.Op.Op), b GHC.Types.~ Data.Vector.Vector (GHC.Types.Int, EVM.Op.Op)) => Optics.Label.LabelOptic "codeOps" k EVM.Contract EVM.Contract a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Block, b GHC.Types.~ EVM.Block) => Optics.Label.LabelOptic "block" k EVM.VM EVM.VM a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Cache, b GHC.Types.~ EVM.Cache) => Optics.Label.LabelOptic "cache" k EVM.VM EVM.VM a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Contract, b GHC.Types.~ EVM.Contract) => Optics.Label.LabelOptic "contract" k EVM.Trace EVM.Trace a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Contract, b GHC.Types.~ EVM.Contract) => Optics.Label.LabelOptic "contract" k EVM.VMOpts EVM.VMOpts a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.ContractCode, b GHC.Types.~ EVM.ContractCode) => Optics.Label.LabelOptic "code" k EVM.FrameState EVM.FrameState a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.ContractCode, b GHC.Types.~ EVM.ContractCode) => Optics.Label.LabelOptic "contractcode" k EVM.Contract EVM.Contract a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Env, b GHC.Types.~ EVM.Env) => Optics.Label.LabelOptic "env" k EVM.VM EVM.VM a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.FeeSchedule.FeeSchedule GHC.Word.Word64, b GHC.Types.~ EVM.FeeSchedule.FeeSchedule GHC.Word.Word64) => Optics.Label.LabelOptic "schedule" k EVM.Block EVM.Block a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.FeeSchedule.FeeSchedule GHC.Word.Word64, b GHC.Types.~ EVM.FeeSchedule.FeeSchedule GHC.Word.Word64) => Optics.Label.LabelOptic "schedule" k EVM.VMOpts EVM.VMOpts a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.FrameContext, b GHC.Types.~ EVM.FrameContext) => Optics.Label.LabelOptic "context" k EVM.Frame EVM.Frame a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.FrameState, b GHC.Types.~ EVM.FrameState) => Optics.Label.LabelOptic "state" k EVM.Frame EVM.Frame a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.FrameState, b GHC.Types.~ EVM.FrameState) => Optics.Label.LabelOptic "state" k EVM.VM EVM.VM a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.SubState, b GHC.Types.~ EVM.SubState) => Optics.Label.LabelOptic "substate" k EVM.TxState EVM.TxState a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.TraceData, b GHC.Types.~ EVM.TraceData) => Optics.Label.LabelOptic "tracedata" k EVM.Trace EVM.Trace a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.TxState, b GHC.Types.~ EVM.TxState) => Optics.Label.LabelOptic "tx" k EVM.VM EVM.VM a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Addr, b GHC.Types.~ EVM.Types.Addr) => Optics.Label.LabelOptic "address" k EVM.VMOpts EVM.VMOpts a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Addr, b GHC.Types.~ EVM.Types.Addr) => Optics.Label.LabelOptic "codeContract" k EVM.FrameState EVM.FrameState a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Addr, b GHC.Types.~ EVM.Types.Addr) => Optics.Label.LabelOptic "coinbase" k EVM.Block EVM.Block a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Addr, b GHC.Types.~ EVM.Types.Addr) => Optics.Label.LabelOptic "coinbase" k EVM.VMOpts EVM.VMOpts a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Addr, b GHC.Types.~ EVM.Types.Addr) => Optics.Label.LabelOptic "contract" k EVM.FrameState EVM.FrameState a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Addr, b GHC.Types.~ EVM.Types.Addr) => Optics.Label.LabelOptic "origin" k EVM.TxState EVM.TxState a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Addr, b GHC.Types.~ EVM.Types.Addr) => Optics.Label.LabelOptic "origin" k EVM.VMOpts EVM.VMOpts a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Addr, b GHC.Types.~ EVM.Types.Addr) => Optics.Label.LabelOptic "toAddr" k EVM.TxState EVM.TxState a b
+ EVM: 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.FrameState EVM.FrameState a b
+ EVM: 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 "memory" k EVM.FrameState EVM.FrameState a b
+ EVM: 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.FrameState EVM.FrameState a b
+ EVM: 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 "caller" k EVM.FrameState EVM.FrameState a b
+ EVM: 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 "caller" k EVM.VMOpts EVM.VMOpts a b
+ EVM: 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.FrameState EVM.FrameState a b
+ EVM: 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 "codehash" k EVM.Contract EVM.Contract a b
+ EVM: 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 "codehash" k EVM.FrameContext EVM.FrameContext a b
+ EVM: 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 "timestamp" k EVM.Block EVM.Block a b
+ EVM: 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 "timestamp" k EVM.VMOpts EVM.VMOpts a b
+ EVM: 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 "value" k EVM.TxState EVM.TxState a b
+ EVM: 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 "value" k EVM.VMOpts EVM.VMOpts a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Expr 'EVM.Types.Storage, b GHC.Types.~ EVM.Types.Expr 'EVM.Types.Storage) => Optics.Label.LabelOptic "initialStorage" k EVM.VMOpts EVM.VMOpts a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.Expr 'EVM.Types.Storage, b GHC.Types.~ EVM.Types.Expr 'EVM.Types.Storage) => Optics.Label.LabelOptic "storage" k EVM.Env EVM.Env a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.W256, b GHC.Types.~ EVM.Types.W256) => Optics.Label.LabelOptic "balance" k EVM.Contract EVM.Contract a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.W256, b GHC.Types.~ EVM.Types.W256) => Optics.Label.LabelOptic "baseFee" k EVM.Block EVM.Block a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.W256, b GHC.Types.~ EVM.Types.W256) => Optics.Label.LabelOptic "baseFee" k EVM.VMOpts EVM.VMOpts a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.W256, b GHC.Types.~ EVM.Types.W256) => Optics.Label.LabelOptic "chainId" k EVM.Env EVM.Env a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.W256, b GHC.Types.~ EVM.Types.W256) => Optics.Label.LabelOptic "chainId" k EVM.VMOpts EVM.VMOpts a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.W256, b GHC.Types.~ EVM.Types.W256) => Optics.Label.LabelOptic "gasprice" k EVM.TxState EVM.TxState a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.W256, b GHC.Types.~ EVM.Types.W256) => Optics.Label.LabelOptic "gasprice" k EVM.VMOpts EVM.VMOpts a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.W256, b GHC.Types.~ EVM.Types.W256) => Optics.Label.LabelOptic "maxCodeSize" k EVM.Block EVM.Block a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.W256, b GHC.Types.~ EVM.Types.W256) => Optics.Label.LabelOptic "maxCodeSize" k EVM.VMOpts EVM.VMOpts a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.W256, b GHC.Types.~ EVM.Types.W256) => Optics.Label.LabelOptic "nonce" k EVM.Contract EVM.Contract a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.W256, b GHC.Types.~ EVM.Types.W256) => Optics.Label.LabelOptic "number" k EVM.Block EVM.Block a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.W256, b GHC.Types.~ EVM.Types.W256) => Optics.Label.LabelOptic "number" k EVM.VMOpts EVM.VMOpts a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.W256, b GHC.Types.~ EVM.Types.W256) => Optics.Label.LabelOptic "prevRandao" k EVM.Block EVM.Block a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.W256, b GHC.Types.~ EVM.Types.W256) => Optics.Label.LabelOptic "prevRandao" k EVM.VMOpts EVM.VMOpts a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.W256, b GHC.Types.~ EVM.Types.W256) => Optics.Label.LabelOptic "priorityFee" k EVM.TxState EVM.TxState a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Types.W256, b GHC.Types.~ EVM.Types.W256) => Optics.Label.LabelOptic "priorityFee" k EVM.VMOpts EVM.VMOpts a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ GHC.Maybe.Maybe EVM.Types.Addr, b GHC.Types.~ GHC.Maybe.Maybe EVM.Types.Addr) => Optics.Label.LabelOptic "overrideCaller" k EVM.VM EVM.VM a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ GHC.Maybe.Maybe EVM.VMResult, b GHC.Types.~ GHC.Maybe.Maybe EVM.VMResult) => Optics.Label.LabelOptic "result" k EVM.VM EVM.VM a b
+ EVM: 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 "allowFFI" k EVM.VM EVM.VM a b
+ EVM: 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 "allowFFI" k EVM.VMOpts EVM.VMOpts a b
+ EVM: 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 "create" k EVM.VMOpts EVM.VMOpts a b
+ EVM: 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 "external" k EVM.Contract EVM.Contract a b
+ EVM: 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 "isCreate" k EVM.TxState EVM.TxState a b
+ EVM: 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.FrameState EVM.FrameState a b
+ EVM: 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 "opIx" k EVM.Trace EVM.Trace a b
+ EVM: 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.FrameState EVM.FrameState a b
+ EVM: 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 "blockGaslimit" k EVM.VMOpts EVM.VMOpts a b
+ EVM: 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 "burned" k EVM.VM EVM.VM a b
+ EVM: 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 "gas" k EVM.FrameState EVM.FrameState a b
+ EVM: 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 "gas" k EVM.VMOpts EVM.VMOpts a b
+ EVM: 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 "gaslimit" k EVM.Block EVM.Block a b
+ EVM: 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 "gaslimit" k EVM.TxState EVM.TxState a b
+ EVM: 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 "gaslimit" k EVM.VMOpts EVM.VMOpts a b
+ EVM: 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.FrameState EVM.FrameState a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ [(EVM.Types.Addr, GHC.Word.Word64)], b GHC.Types.~ [(EVM.Types.Addr, GHC.Word.Word64)]) => Optics.Label.LabelOptic "refunds" k EVM.SubState EVM.SubState a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ [EVM.Frame], b GHC.Types.~ [EVM.Frame]) => Optics.Label.LabelOptic "frames" k EVM.VM EVM.VM a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ [EVM.Types.Addr], b GHC.Types.~ [EVM.Types.Addr]) => Optics.Label.LabelOptic "selfdestructs" k EVM.SubState EVM.SubState a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ [EVM.Types.Addr], b GHC.Types.~ [EVM.Types.Addr]) => Optics.Label.LabelOptic "touchedAccounts" k EVM.SubState EVM.SubState a b
+ EVM: 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.FrameState EVM.FrameState a b
+ EVM: 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.VM EVM.VM a b
+ EVM: 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.VM EVM.VM a b
+ EVM: 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 "keccakEqs" k EVM.VM EVM.VM a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.An_AffineTraversal, a GHC.Types.~ (Data.Map.Internal.Map EVM.Types.Addr EVM.Contract, EVM.Types.Expr 'EVM.Types.Storage), b GHC.Types.~ (Data.Map.Internal.Map EVM.Types.Addr EVM.Contract, EVM.Types.Expr 'EVM.Types.Storage)) => Optics.Label.LabelOptic "callreversion" k EVM.FrameContext EVM.FrameContext a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.An_AffineTraversal, a GHC.Types.~ Data.Map.Internal.Map EVM.Types.Addr EVM.Contract, b GHC.Types.~ Data.Map.Internal.Map EVM.Types.Addr EVM.Contract) => Optics.Label.LabelOptic "createreversion" k EVM.FrameContext EVM.FrameContext a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.An_AffineTraversal, a GHC.Types.~ EVM.SubState, b GHC.Types.~ EVM.SubState) => Optics.Label.LabelOptic "subState" k EVM.FrameContext EVM.FrameContext a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.An_AffineTraversal, a GHC.Types.~ EVM.SubState, b GHC.Types.~ EVM.SubState) => Optics.Label.LabelOptic "substate" k EVM.FrameContext EVM.FrameContext a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.An_AffineTraversal, a GHC.Types.~ EVM.Types.Addr, b GHC.Types.~ EVM.Types.Addr) => Optics.Label.LabelOptic "address" k EVM.FrameContext EVM.FrameContext a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.An_AffineTraversal, a GHC.Types.~ EVM.Types.Addr, b GHC.Types.~ EVM.Types.Addr) => Optics.Label.LabelOptic "context" k EVM.FrameContext EVM.FrameContext a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.An_AffineTraversal, a GHC.Types.~ EVM.Types.Addr, b GHC.Types.~ EVM.Types.Addr) => Optics.Label.LabelOptic "target" k EVM.FrameContext EVM.FrameContext a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.An_AffineTraversal, a GHC.Types.~ EVM.Types.Expr 'EVM.Types.Buf, b GHC.Types.~ EVM.Types.Expr 'EVM.Types.Buf) => Optics.Label.LabelOptic "calldata" k EVM.FrameContext EVM.FrameContext a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.An_AffineTraversal, a GHC.Types.~ EVM.Types.W256, b GHC.Types.~ EVM.Types.W256) => Optics.Label.LabelOptic "offset" k EVM.FrameContext EVM.FrameContext a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.An_AffineTraversal, a GHC.Types.~ EVM.Types.W256, b GHC.Types.~ EVM.Types.W256) => Optics.Label.LabelOptic "size" k EVM.FrameContext EVM.FrameContext a b
+ EVM: instance (k GHC.Types.~ Optics.Internal.Optic.Types.An_AffineTraversal, a GHC.Types.~ GHC.Maybe.Maybe EVM.Types.W256, b GHC.Types.~ GHC.Maybe.Maybe EVM.Types.W256) => Optics.Label.LabelOptic "abi" k EVM.FrameContext EVM.FrameContext a b
+ EVM: instance GHC.Generics.Generic EVM.Cache
+ EVM: instance GHC.Generics.Generic EVM.Env
+ EVM: instance GHC.Generics.Generic EVM.FrameContext
+ EVM: instance GHC.Generics.Generic EVM.FrameState
+ EVM: instance GHC.Generics.Generic EVM.Trace
+ EVM: instance GHC.Generics.Generic EVM.TraceData
+ EVM: instance GHC.Generics.Generic EVM.VM
+ EVM: use' :: (VM -> a) -> EVM a
+ EVM.Facts: instance EVM.Facts.AsASCII Data.ByteString.Internal.Type.ByteString
+ EVM.Fetch: fetchChainIdFrom :: Text -> IO (Maybe W256)
+ EVM.SMT: [$sel:blockContext:CexVars] :: CexVars -> [Text]
+ EVM.SMT: [$sel:buffers:CexVars] :: CexVars -> Map Text (Expr EWord)
+ EVM.SMT: [$sel:calldata:CexVars] :: CexVars -> [Text]
+ EVM.SMT: [$sel:txContext:CexVars] :: CexVars -> [Text]
+ EVM.Solidity: [$sel:file:SM] :: SrcMap -> {-# UNPACK #-} !Int
+ EVM.Solidity: [$sel:jump:SM] :: SrcMap -> JumpType
+ EVM.Solidity: [$sel:length:SM] :: SrcMap -> {-# UNPACK #-} !Int
+ EVM.Solidity: [$sel:modifierDepth:SM] :: SrcMap -> {-# UNPACK #-} !Int
+ EVM.Solidity: [$sel:offset:SM] :: SrcMap -> {-# UNPACK #-} !Int
+ EVM.Solvers: [$sel:process:SolverInstance] :: SolverInstance -> ProcessHandle
+ EVM.Solvers: [$sel:solvertype:SolverInstance] :: SolverInstance -> Solver
+ EVM.Solvers: [$sel:stderr:SolverInstance] :: SolverInstance -> Handle
+ EVM.Solvers: [$sel:stdin:SolverInstance] :: SolverInstance -> Handle
+ EVM.Solvers: [$sel:stdout:SolverInstance] :: SolverInstance -> Handle
+ EVM.Solvers: mkTimeout :: Maybe Natural -> Text
+ EVM.TTY: [$sel:contracts:UiBrowserState] :: UiBrowserState -> List Name (Addr, Contract)
+ EVM.TTY: [$sel:dapp:UiTestPickerState] :: UiTestPickerState -> DappInfo
+ EVM.TTY: [$sel:opts:UiTestPickerState] :: UiTestPickerState -> UnitTestOptions
+ EVM.TTY: [$sel:showMemory:UiVmState] :: UiVmState -> Bool
+ EVM.TTY: [$sel:snapshots:UiVmState] :: UiVmState -> Map Int (VM, Stepper ())
+ EVM.TTY: [$sel:step:UiVmState] :: UiVmState -> Int
+ EVM.TTY: [$sel:stepper:UiVmState] :: UiVmState -> Stepper ()
+ EVM.TTY: [$sel:testOpts:UiVmState] :: UiVmState -> UnitTestOptions
+ EVM.TTY: [$sel:tests:UiTestPickerState] :: UiTestPickerState -> List Name (Text, Text)
+ EVM.TTY: [$sel:vm:UiBrowserState] :: UiBrowserState -> UiVmState
+ EVM.TTY: [$sel:vm:UiVmState] :: UiVmState -> VM
+ EVM.TTY: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Brick.Widgets.List.List EVM.TTY.Name (Data.Text.Internal.Text, Data.Text.Internal.Text), b GHC.Types.~ Brick.Widgets.List.List EVM.TTY.Name (Data.Text.Internal.Text, Data.Text.Internal.Text)) => Optics.Label.LabelOptic "tests" k EVM.TTY.UiTestPickerState EVM.TTY.UiTestPickerState a b
+ EVM.TTY: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Brick.Widgets.List.List EVM.TTY.Name (EVM.Types.Addr, EVM.Contract), b GHC.Types.~ Brick.Widgets.List.List EVM.TTY.Name (EVM.Types.Addr, EVM.Contract)) => Optics.Label.LabelOptic "contracts" k EVM.TTY.UiBrowserState EVM.TTY.UiBrowserState a b
+ EVM.TTY: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ Data.Map.Internal.Map GHC.Types.Int (EVM.VM, EVM.Stepper.Stepper ()), b GHC.Types.~ Data.Map.Internal.Map GHC.Types.Int (EVM.VM, EVM.Stepper.Stepper ())) => Optics.Label.LabelOptic "snapshots" k EVM.TTY.UiVmState EVM.TTY.UiVmState a b
+ EVM.TTY: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Dapp.DappInfo, b GHC.Types.~ EVM.Dapp.DappInfo) => Optics.Label.LabelOptic "dapp" k EVM.TTY.UiTestPickerState EVM.TTY.UiTestPickerState a b
+ EVM.TTY: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.Stepper.Stepper (), b GHC.Types.~ EVM.Stepper.Stepper ()) => Optics.Label.LabelOptic "stepper" k EVM.TTY.UiVmState EVM.TTY.UiVmState a b
+ EVM.TTY: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.TTY.UiVmState, b GHC.Types.~ EVM.TTY.UiVmState) => Optics.Label.LabelOptic "vm" k EVM.TTY.UiBrowserState EVM.TTY.UiBrowserState a b
+ EVM.TTY: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.UnitTest.UnitTestOptions, b GHC.Types.~ EVM.UnitTest.UnitTestOptions) => Optics.Label.LabelOptic "opts" k EVM.TTY.UiTestPickerState EVM.TTY.UiTestPickerState a b
+ EVM.TTY: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.UnitTest.UnitTestOptions, b GHC.Types.~ EVM.UnitTest.UnitTestOptions) => Optics.Label.LabelOptic "testOpts" k EVM.TTY.UiVmState EVM.TTY.UiVmState a b
+ EVM.TTY: instance (k GHC.Types.~ Optics.Internal.Optic.Types.A_Lens, a GHC.Types.~ EVM.VM, b GHC.Types.~ EVM.VM) => Optics.Label.LabelOptic "vm" k EVM.TTY.UiVmState EVM.TTY.UiVmState a b
+ EVM.TTY: 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 "showMemory" k EVM.TTY.UiVmState EVM.TTY.UiVmState a b
+ EVM.TTY: 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 "step" k EVM.TTY.UiVmState EVM.TTY.UiVmState a b
+ EVM.Transaction: [$sel:accessList:Transaction] :: Transaction -> [AccessListEntry]
+ EVM.Transaction: [$sel:address:AccessListEntry] :: AccessListEntry -> Addr
+ EVM.Transaction: [$sel:chainId:Transaction] :: Transaction -> W256
+ EVM.Transaction: [$sel:gasLimit:Transaction] :: Transaction -> Word64
+ EVM.Transaction: [$sel:gasPrice:Transaction] :: Transaction -> Maybe W256
+ EVM.Transaction: [$sel:maxFeePerGas:Transaction] :: Transaction -> Maybe W256
+ EVM.Transaction: [$sel:maxPriorityFeeGas:Transaction] :: Transaction -> Maybe W256
+ EVM.Transaction: [$sel:nonce:Transaction] :: Transaction -> W256
+ EVM.Transaction: [$sel:r:Transaction] :: Transaction -> W256
+ EVM.Transaction: [$sel:s:Transaction] :: Transaction -> W256
+ EVM.Transaction: [$sel:storageKeys:AccessListEntry] :: AccessListEntry -> [W256]
+ EVM.Transaction: [$sel:toAddr:Transaction] :: Transaction -> Maybe Addr
+ EVM.Transaction: [$sel:txdata:Transaction] :: Transaction -> ByteString
+ EVM.Transaction: [$sel:txtype:Transaction] :: Transaction -> TxType
+ EVM.Transaction: [$sel:v:Transaction] :: Transaction -> W256
+ EVM.Transaction: [$sel:value:Transaction] :: Transaction -> W256
+ EVM.Types: FunctionSelector :: Word32 -> FunctionSelector
+ EVM.Types: [$sel:unFunctionSelector:FunctionSelector] :: FunctionSelector -> Word32
+ EVM.Types: instance GHC.Classes.Eq EVM.Types.FunctionSelector
+ EVM.Types: instance GHC.Classes.Ord EVM.Types.FunctionSelector
+ EVM.Types: instance GHC.Enum.Enum EVM.Types.FunctionSelector
+ EVM.Types: instance GHC.Num.Num EVM.Types.FunctionSelector
+ EVM.Types: instance GHC.Real.Integral EVM.Types.FunctionSelector
+ EVM.Types: instance GHC.Real.Real EVM.Types.FunctionSelector
+ EVM.Types: instance GHC.Show.Show EVM.Types.FunctionSelector
+ EVM.Types: newtype FunctionSelector
+ EVM.UnitTest: [$sel:address:TestVMParams] :: TestVMParams -> Addr
+ EVM.UnitTest: [$sel:balanceCreate:TestVMParams] :: TestVMParams -> W256
+ EVM.UnitTest: [$sel:baseFee:TestVMParams] :: TestVMParams -> W256
+ EVM.UnitTest: [$sel:caller:TestVMParams] :: TestVMParams -> Addr
+ EVM.UnitTest: [$sel:chainId:TestVMParams] :: TestVMParams -> W256
+ EVM.UnitTest: [$sel:coinbase:TestVMParams] :: TestVMParams -> Addr
+ EVM.UnitTest: [$sel:gasCall:TestVMParams] :: TestVMParams -> Word64
+ EVM.UnitTest: [$sel:gasCreate:TestVMParams] :: TestVMParams -> Word64
+ EVM.UnitTest: [$sel:gaslimit:TestVMParams] :: TestVMParams -> Word64
+ EVM.UnitTest: [$sel:gasprice:TestVMParams] :: TestVMParams -> W256
+ EVM.UnitTest: [$sel:maxCodeSize:TestVMParams] :: TestVMParams -> W256
+ EVM.UnitTest: [$sel:number:TestVMParams] :: TestVMParams -> W256
+ EVM.UnitTest: [$sel:origin:TestVMParams] :: TestVMParams -> Addr
+ EVM.UnitTest: [$sel:prevrandao:TestVMParams] :: TestVMParams -> W256
+ EVM.UnitTest: [$sel:priorityFee:TestVMParams] :: TestVMParams -> W256
+ EVM.UnitTest: [$sel:timestamp:TestVMParams] :: TestVMParams -> W256
- EVM: BadCheatCode :: Maybe Word32 -> Error
+ EVM: BadCheatCode :: FunctionSelector -> Error
- EVM: VM :: Maybe VMResult -> FrameState -> [Frame] -> Env -> Block -> TxState -> [Expr Log] -> TreePos Empty Trace -> Cache -> {-# UNPACK #-} !Word64 -> Map CodeLocation Int -> [Prop] -> [Prop] -> Bool -> Maybe (Expr EWord) -> VM
+ EVM: VM :: Maybe VMResult -> FrameState -> [Frame] -> Env -> Block -> TxState -> [Expr Log] -> TreePos Empty Trace -> Cache -> {-# UNPACK #-} !Word64 -> Map CodeLocation Int -> [Prop] -> [Prop] -> Bool -> Maybe Addr -> VM
- EVM: VMOpts :: Contract -> (Expr Buf, [Prop]) -> StorageBase -> Expr EWord -> W256 -> Addr -> Expr EWord -> Addr -> Word64 -> Word64 -> W256 -> Expr EWord -> Addr -> W256 -> W256 -> Word64 -> W256 -> W256 -> FeeSchedule Word64 -> W256 -> Bool -> Map Addr [W256] -> Bool -> VMOpts
+ EVM: VMOpts :: Contract -> (Expr Buf, [Prop]) -> Expr Storage -> Expr EWord -> W256 -> Addr -> Expr EWord -> Addr -> Word64 -> Word64 -> W256 -> Expr EWord -> Addr -> W256 -> W256 -> Word64 -> W256 -> W256 -> FeeSchedule Word64 -> W256 -> Bool -> Map Addr [W256] -> Bool -> VMOpts
- EVM: cheatActions :: Map Word32 CheatAction
+ EVM: cheatActions :: Map FunctionSelector CheatAction
- EVM: pushTo :: MonadState s m => ASetter s s [a] [a] -> a -> m ()
+ EVM: pushTo :: MonadState s m => Lens s s [a] [a] -> a -> m ()
- EVM: pushToSequence :: MonadState s m => ASetter s s (Seq a) (Seq a) -> a -> m ()
+ EVM: pushToSequence :: MonadState s m => Setter s s (Seq a) (Seq a) -> a -> m ()
- EVM.Dapp: DappInfo :: FilePath -> Map Text SolcContract -> Map W256 (CodeType, SolcContract) -> [(Code, SolcContract)] -> SourceCache -> [(Text, [(Test, [AbiType])])] -> Map Word32 Method -> Map W256 Event -> Map W256 SolError -> Map Int Value -> (SrcMap -> Maybe Value) -> DappInfo
+ EVM.Dapp: DappInfo :: FilePath -> Map Text SolcContract -> Map W256 (CodeType, SolcContract) -> [(Code, SolcContract)] -> SourceCache -> [(Text, [(Test, [AbiType])])] -> Map FunctionSelector Method -> Map W256 Event -> Map W256 SolError -> Map Int Value -> (SrcMap -> Maybe Value) -> DappInfo
- EVM.Dapp: [$sel:abiMap:DappInfo] :: DappInfo -> Map Word32 Method
+ EVM.Dapp: [$sel:abiMap:DappInfo] :: DappInfo -> Map FunctionSelector Method
- EVM.Dapp: unitTestMarkerAbi :: Word32
+ EVM.Dapp: unitTestMarkerAbi :: FunctionSelector
- EVM.Expr: word256At :: Functor f => Expr EWord -> (Expr EWord -> f (Expr EWord)) -> Expr Buf -> f (Expr Buf)
+ EVM.Expr: word256At :: Expr EWord -> Lens (Expr Buf) (Expr Buf) (Expr EWord) (Expr EWord)
- EVM.Solidity: SolcContract :: W256 -> W256 -> ByteString -> ByteString -> Text -> [(Text, AbiType)] -> Map Word32 Method -> Map W256 Event -> Map W256 SolError -> Map W256 [Reference] -> Maybe (Map Text StorageItem) -> Seq SrcMap -> Seq SrcMap -> SolcContract
+ EVM.Solidity: SolcContract :: W256 -> W256 -> ByteString -> ByteString -> Text -> [(Text, AbiType)] -> Map FunctionSelector Method -> Map W256 Event -> Map W256 SolError -> Map W256 [Reference] -> Maybe (Map Text StorageItem) -> Seq SrcMap -> Seq SrcMap -> SolcContract
- EVM.Solidity: [$sel:abiMap:SolcContract] :: SolcContract -> Map Word32 Method
+ EVM.Solidity: [$sel:abiMap:SolcContract] :: SolcContract -> Map FunctionSelector Method
- EVM.Stepper: interpret :: Fetcher -> Stepper a -> StateT VM IO a
+ EVM.Stepper: interpret :: Fetcher -> VM -> Stepper a -> IO a
- EVM.SymExec: abstractVM :: (Expr Buf, [Prop]) -> ByteString -> Maybe Precondition -> StorageModel -> VM
+ EVM.SymExec: abstractVM :: (Expr Buf, [Prop]) -> ByteString -> Maybe Precondition -> Expr Storage -> VM
- EVM.SymExec: flattenExpr :: Expr End -> [([Prop], Expr End)]
+ EVM.SymExec: flattenExpr :: Expr End -> [Expr End]
- EVM.SymExec: interpret :: Fetcher -> Maybe Integer -> Maybe Integer -> Stepper (Expr End) -> StateT VM IO (Expr End)
+ EVM.SymExec: interpret :: Fetcher -> Maybe Integer -> Maybe Integer -> VM -> Stepper (Expr End) -> IO (Expr End)
- EVM.SymExec: loadSymVM :: ContractCode -> Expr Storage -> Expr EWord -> Expr EWord -> Expr Buf -> [Prop] -> VM
+ EVM.SymExec: loadSymVM :: ContractCode -> Expr Storage -> Expr EWord -> Expr EWord -> (Expr Buf, [Prop]) -> VM
- EVM.SymExec: verifyContract :: SolverGroup -> ByteString -> Maybe Sig -> [String] -> VeriOpts -> StorageModel -> Maybe Precondition -> Maybe Postcondition -> IO (Expr End, [VerifyResult])
+ EVM.SymExec: verifyContract :: SolverGroup -> ByteString -> Maybe Sig -> [String] -> VeriOpts -> Expr Storage -> Maybe Precondition -> Maybe Postcondition -> IO (Expr End, [VerifyResult])
- EVM.Types: abiKeccak :: ByteString -> Word32
+ EVM.Types: abiKeccak :: ByteString -> FunctionSelector

Files

CHANGELOG.md view
@@ -5,6 +5,20 @@ 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.50.5] - 2023-03-18++## Changed++- The `--storage-model` parameter has been replaced with `--initial-storage`+- The `--smttimeout` argument now expects a value in seconds not milliseconds+- The default smt timeout has been set to 5 minutes+- `hevm symbolic` now searches only for user defined assertions by default++### Fixed++- The `prank` cheatcode now transfers value from the correct address+- Fixed an off-by-one error in `EVM.Debug.srcMapCodePos`+ ## [0.50.4] - 2023-03-17  ### Fixed@@ -23,8 +37,8 @@ - Implemented a shrinking algorithm for counterexamples - A new differential fuzzing test harness that compares the concrete semantics, as well as parts of the symbolic semantics against the geth evm implementation - The `hevm` library can now be built on Windows systems.-- Support for function pointers in ABI - `equivalence` can now be checked for fully or partially concrete calldata+- Support for function pointers in ABI  ## [0.50.3] - 2023-02-17 
bench/bench.hs view
@@ -1,15 +1,23 @@ module Main where  import GHC.Natural+import Control.Monad+import Data.Maybe+import System.Environment (lookupEnv, getEnv)  import qualified Paths_hevm as Paths -import Test.Tasty (localOption)+import Test.Tasty (localOption, withResource) import Test.Tasty.Bench import Data.Functor import Data.String.Here import Data.ByteString (ByteString)+import System.FilePath.Posix+import Control.Monad.State.Strict+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 (StorageModel(..)) import EVM.SymExec@@ -19,7 +27,76 @@ import EVM.Dapp import EVM.Types import qualified EVM.TTY as TTY+import qualified EVM.Stepper as Stepper+import qualified EVM.Fetch as Fetch +import EVM.Test.BlockchainTests qualified as BCTests++main :: IO ()+main = defaultMain+  [ mkbench erc20 "erc20" Nothing [1]+  , mkbench (pure vat) "vat" Nothing [4]+  , mkbench (pure deposit) "deposit" (Just 32) [4]+  , mkbench (pure uniV2Pair) "uniV2" (Just 10) [4]+  , withResource bcjsons (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 e -> 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+blockchainTests ts = bench "blockchain-tests" $ nfIO $ do+  tests <- ts+  putStrLn "\n    executing tests:"+  let cases = concat . Map.elems . (fmap Map.toList) $ tests+      ignored = Map.keys BCTests.commonProblematicTests+  foldM (\acc (n, c) ->+      if n `elem` ignored+      then pure True+      else do+        res <- runBCTest c+        putStrLn $ "      " <> n+        pure $ acc && res+    ) True cases++-- | executes a single test case and returns a boolean value representing its success+runBCTest :: BCTests.Case -> IO Bool+runBCTest x =+ do+  let vm0 = BCTests.vmForCase x+  result <- execStateT (Stepper.interpret (Fetch.zero 0 (Just 0)) . void $ Stepper.execFully) vm0+  maybeReason <- BCTests.checkExpectation False x result+  pure $ isNothing maybeReason+++--- Helpers ----------------------------------------------------------------------------------------+++debugContract :: ByteString -> IO ()+debugContract c = withSolvers CVC5 4 Nothing $ \solvers -> do+  let prestate = abstractVM (mkCalldata Nothing []) c Nothing SymbolicS+  void $ TTY.runFromVM solvers Nothing Nothing emptyDapp prestate+ findPanics :: Solver -> Natural -> Maybe Integer -> ByteString -> IO () findPanics solver count iters c = do   (_, res) <- withSolvers solver count Nothing $ \s -> do@@ -44,23 +121,6 @@        ]        | i <- counts      ]--main :: IO ()-main = defaultMain-  [ mkbench erc20 "erc20" Nothing [1]-  , mkbench (pure vat) "vat" Nothing [4]-  , mkbench (pure deposit) "deposit" (Just 32) [4]-  , mkbench (pure uniV2Pair) "uniV2" (Just 10) [4]-  ]------ Helpers -------------------------------------------------------------------------------------------debugContract :: ByteString -> IO ()-debugContract c = withSolvers CVC5 4 Nothing $ \solvers -> do-  let prestate = abstractVM (mkCalldata Nothing []) c Nothing SymbolicS-  void $ TTY.runFromVM solvers Nothing Nothing emptyDapp prestate   --- Bytecodes --------------------------------------------------------------------------------------
hevm-cli/hevm-cli.hs view
@@ -5,7 +5,6 @@  module Main where -import EVM (StorageModel(..)) import qualified EVM import EVM.Concrete (createAddress) import qualified EVM.FeeSchedule as FeeSchedule@@ -20,20 +19,22 @@ import EVM.Solidity import EVM.Expr (litAddr) import EVM.Types hiding (word)-import EVM.UnitTest (UnitTestOptions, coverageReport, coverageForUnitTestContract, getParametersFromEnvironmentVariables, testNumber, dappTest)+import EVM.UnitTest (UnitTestOptions, coverageReport, coverageForUnitTestContract, getParametersFromEnvironmentVariables, dappTest) import EVM.Dapp (findUnitTests, dappInfo, DappInfo, emptyDapp) import GHC.Natural import EVM.Format (showTraceTree, formatExpr) import Data.Word (Word64)+import Data.Bifunctor (second) +import qualified Data.Map as Map import qualified EVM.Facts     as Facts import qualified EVM.Facts.Git as Git import qualified EVM.UnitTest  import GHC.Conc-import Control.Lens hiding (pre, passing)+import Optics.Core hiding (pre, Empty) import Control.Monad              (void, when, forM_, unless)-import Control.Monad.State.Strict (execStateT, liftIO)+import Control.Monad.State.Strict (liftIO) import Data.ByteString            (ByteString) import Data.List                  (intercalate, isSuffixOf, intersperse) import Data.Text                  (unpack, pack)@@ -47,7 +48,6 @@ import qualified Data.ByteString        as ByteString import qualified Data.ByteString.Char8  as Char8 import qualified Data.ByteString.Lazy   as LazyByteString-import qualified Data.Map               as Map import qualified Data.Text              as T import qualified Data.Text.IO           as T @@ -89,14 +89,14 @@   -- symbolic execution opts       , jsonFile      :: w ::: Maybe String       <?> "Filename or path to dapp build output (default: out/*.solc.json)"       , dappRoot      :: w ::: Maybe String       <?> "Path to dapp project root directory (default: . )"-      , storageModel  :: w ::: Maybe StorageModel <?> "Select storage model: ConcreteS, SymbolicS (default) or InitialS"+      , initialStorage :: w ::: Maybe (InitialStorage) <?> "Starting state for storage: Empty, Abstract, Concrete <STORE> (default Abstract)"       , sig           :: w ::: Maybe Text         <?> "Signature of types to decode / encode"       , arg           :: w ::: [String]           <?> "Values to encode"       , debug         :: w ::: Bool               <?> "Run interactively"       , getModels     :: w ::: Bool               <?> "Print example testcase for each execution path"       , showTree      :: w ::: Bool               <?> "Print branches explored in tree view"       , showReachableTree :: w ::: Bool           <?> "Print only reachable branches explored in tree view"-      , smttimeout    :: w ::: Maybe Natural      <?> "Timeout given to SMT solver in milliseconds (default: 60000)"+      , smttimeout    :: w ::: Maybe Natural      <?> "Timeout given to SMT solver in seconds (default: 300)"       , maxIterations :: w ::: Maybe Integer      <?> "Number of times we may revisit a particular branching point"       , solver        :: w ::: Maybe Text         <?> "Used SMT solver: z3 (default) or cvc5"       , smtdebug      :: w ::: Bool               <?> "Print smt queries sent to the solver"@@ -110,7 +110,7 @@       , sig           :: w ::: Maybe Text       <?> "Signature of types to decode / encode"       , arg           :: w ::: [String]         <?> "Values to encode"       , calldata      :: w ::: Maybe ByteString <?> "Tx: calldata"-      , smttimeout    :: w ::: Maybe Natural    <?> "Timeout given to SMT solver in milliseconds (default: 60000)"+      , smttimeout    :: w ::: Maybe Natural    <?> "Timeout given to SMT solver in seconds (default: 300)"       , maxIterations :: w ::: Maybe Integer    <?> "Number of times we may revisit a particular branching point"       , solver        :: w ::: Maybe Text       <?> "Used SMT solver: z3 (default) or cvc5"       , smtoutput     :: w ::: Bool             <?> "Print verbose smt output"@@ -165,7 +165,7 @@       , solver        :: w ::: Maybe Text               <?> "Used SMT solver: z3 (default) or cvc5"       , smtdebug      :: w ::: Bool                     <?> "Print smt queries sent to the solver"       , ffi           :: w ::: Bool                     <?> "Allow the usage of the hevm.ffi() cheatcode (WARNING: this allows test authors to execute arbitrary code on your machine)"-      , smttimeout    :: w ::: Maybe Natural            <?> "Timeout given to SMT solver in milliseconds (default: 60000)"+      , smttimeout    :: w ::: Maybe Natural            <?> "Timeout given to SMT solver in seconds (default: 300)"       , maxIterations :: w ::: Maybe Integer            <?> "Number of times we may revisit a particular branching point"       , askSmtIterations :: w ::: Maybe Integer         <?> "Number of times we may revisit a particular branching point before we consult the smt solver to check reachability (default: 5)"       }@@ -187,6 +187,12 @@   parseRecord =     Options.parseRecordWithModifiers Options.lispCaseModifiers +data InitialStorage+  = Empty+  | Concrete [(W256, [(W256, W256)])]+  | Abstract+  deriving (Show, Read, Options.ParseField)+ optsMode :: Command Options.Unwrapped -> Mode optsMode x   | x.debug = Debug@@ -224,7 +230,7 @@   params <- getParametersFromEnvironmentVariables cmd.rpc    let-    testn = params.testNumber+    testn = params.number     block' = if 0 == testn        then EVM.Fetch.Latest        else EVM.Fetch.BlockNumber testn@@ -262,8 +268,7 @@     Version {} -> putStrLn (showVersion Paths.version)     Symbolic {} -> withCurrentDirectory root $ assert cmd     Equivalence {} -> equivalence cmd-    Exec {} ->-      launchExec cmd+    Exec {} -> launchExec cmd     DappTest {} ->       withCurrentDirectory root $ do         cores <- num <$> getNumProcessors@@ -372,8 +377,8 @@ assert cmd = do   let block'  = maybe EVM.Fetch.Latest EVM.Fetch.BlockNumber cmd.block       rpcinfo = (,) block' <$> cmd.rpc-  calldata' <- buildCalldata cmd-  preState <- symvmFromCommand cmd calldata'+  calldata <- buildCalldata cmd+  preState <- symvmFromCommand cmd calldata   let errCodes = fromMaybe defaultPanicCodes cmd.assertions   cores <- num <$> getNumProcessors   let solverCount = fromMaybe cores cmd.numSolvers@@ -391,7 +396,9 @@       let opts = VeriOpts { simp = True, debug = cmd.smtdebug, maxIter = cmd.maxIterations, askSmtIters = cmd.askSmtIterations, rpcInfo = rpcinfo}       (expr, res) <- verify solvers opts preState (Just $ checkAssertions errCodes)       case res of-        [Qed _] -> putStrLn "\nQED: No reachable property violations discovered\n"+        [Qed _] -> do+          putStrLn "\nQED: No reachable property violations discovered\n"+          showExtras solvers cmd calldata expr         _ -> do           let cexs = snd <$> mapMaybe getCex res               timeouts = mapMaybe getTimeout res@@ -401,7 +408,7 @@                    [ ""                    , "Discovered the following counterexamples:"                    , ""-                   ] <> fmap (formatCex (fst calldata')) cexs+                   ] <> fmap (formatCex (fst calldata)) cexs               unknowns                 | null timeouts = []                 | otherwise =@@ -410,21 +417,25 @@                    , ""                    ] <> fmap (formatExpr) timeouts           T.putStrLn $ T.unlines (counterexamples <> unknowns)+          showExtras solvers cmd calldata expr           exitFailure-      when cmd.showTree $ do-        putStrLn "=== Expression ===\n"-        T.putStrLn $ formatExpr expr-        putStrLn ""-      when cmd.showReachableTree $ do-        reached <- reachable solvers expr-        putStrLn "=== Reachable Expression ===\n"-        T.putStrLn (formatExpr . snd $ reached)-        putStrLn ""-      when cmd.getModels $ do-        putStrLn $ "=== Models for " <> show (Expr.numBranches expr) <> " branches ===\n"-        ms <- produceModels solvers expr-        forM_ ms (showModel (fst calldata')) +showExtras :: SolverGroup -> Command Options.Unwrapped -> (Expr Buf, [Prop]) -> Expr End -> IO ()+showExtras solvers cmd calldata expr = do+  when cmd.showTree $ do+    putStrLn "=== Expression ===\n"+    T.putStrLn $ formatExpr expr+    putStrLn ""+  when cmd.showReachableTree $ do+    reached <- reachable solvers expr+    putStrLn "=== Reachable Expression ===\n"+    T.putStrLn (formatExpr . snd $ reached)+    putStrLn ""+  when cmd.getModels $ do+    putStrLn $ "=== Models for " <> show (Expr.numBranches expr) <> " branches ===\n"+    ms <- produceModels solvers expr+    forM_ ms (showModel (fst calldata))+ getCex :: ProofResult a b c -> Maybe b getCex (Cex c) = Just c getCex _ = Nothing@@ -480,9 +491,9 @@   withSolvers Z3 0 Nothing $ \solvers -> do     case optsMode cmd of       Run -> do-        vm' <- execStateT (EVM.Stepper.interpret (EVM.Fetch.oracle solvers rpcinfo) . void $ EVM.Stepper.execFully) vm+        vm' <- EVM.Stepper.interpret (EVM.Fetch.oracle solvers rpcinfo) vm EVM.Stepper.runFully         when cmd.trace $ T.hPutStr stderr (showTraceTree dapp vm')-        case view EVM.result vm' of+        case vm'.result of           Nothing ->             error "internal error; no EVM result"           Just (EVM.VMFailure (EVM.Revert msg)) -> do@@ -506,13 +517,13 @@             case cmd.cache of               Nothing -> pure ()               Just path ->-                Git.saveFacts (Git.RepoAt path) (Facts.cacheFacts (view EVM.cache vm'))+                Git.saveFacts (Git.RepoAt path) (Facts.cacheFacts vm'.cache)        Debug -> void $ TTY.runFromVM solvers rpcinfo Nothing dapp vm       --JsonTrace -> void $ execStateT (interpretWithTrace fetcher EVM.Stepper.runFully) vm       _ -> error "TODO"-     where block' = maybe EVM.Fetch.Latest EVM.Fetch.BlockNumber cmd.block-           rpcinfo = (,) block' <$> cmd.rpc+     where block = maybe EVM.Fetch.Latest EVM.Fetch.BlockNumber cmd.block+           rpcinfo = (,) block <$> cmd.rpc  -- | Creates a (concrete) VM from command line options vmFromCommand :: Command Options.Unwrapped -> IO EVM.VM@@ -521,34 +532,34 @@    (miner,ts,baseFee,blockNum,prevRan) <- case cmd.rpc of     Nothing -> return (0,Lit 0,0,0,0)-    Just url -> EVM.Fetch.fetchBlockFrom block' url >>= \case+    Just url -> EVM.Fetch.fetchBlockFrom block url >>= \case       Nothing -> error "Could not fetch block"-      Just EVM.Block{..} -> return (_coinbase-                                   , _timestamp-                                   , _baseFee-                                   , _number-                                   , _prevRandao+      Just EVM.Block{..} -> return ( coinbase+                                   , timestamp+                                   , baseFee+                                   , number+                                   , prevRandao                                    )    contract <- case (cmd.rpc, cmd.address, cmd.code) of     (Just url, Just addr', Just c) -> do-      EVM.Fetch.fetchContractFrom block' url addr' >>= \case+      EVM.Fetch.fetchContractFrom block url addr' >>= \case         Nothing ->-          error $ "contract not found: " <> show address'-        Just contract' ->+          error $ "contract not found: " <> show address+        Just contract ->           -- if both code and url is given,           -- fetch the contract and overwrite the code           return $             EVM.initialContract  (mkCode $ hexByteString "--code" $ strip0x c)-              & set EVM.balance  (view EVM.balance  contract')-              & set EVM.nonce    (view EVM.nonce    contract')-              & set EVM.external (view EVM.external contract')+              & set #balance  (contract.balance)+              & set #nonce    (contract.nonce)+              & set #external (contract.external)      (Just url, Just addr', Nothing) ->-      EVM.Fetch.fetchContractFrom block' url addr' >>= \case+      EVM.Fetch.fetchContractFrom block url addr' >>= \case         Nothing ->-          error $ "contract not found: " <> show address'-        Just contract' -> return contract'+          error $ "contract not found: " <> show address+        Just contract -> return contract      (_, _, Just c)  ->       return $@@ -563,43 +574,43 @@    return $ EVM.Transaction.initTx $ withCache (vm0 baseFee miner ts' blockNum prevRan contract)     where-        block'   = maybe EVM.Fetch.Latest EVM.Fetch.BlockNumber cmd.block-        value'   = word (.value) 0-        caller'  = addr (.caller) 0-        origin'  = addr (.origin) 0-        calldata' = ConcreteBuf $ bytes (.calldata) ""+        block   = maybe EVM.Fetch.Latest EVM.Fetch.BlockNumber cmd.block+        value   = word (.value) 0+        caller  = addr (.caller) 0+        origin  = addr (.origin) 0+        calldata = ConcreteBuf $ bytes (.calldata) ""         decipher = hexByteString "bytes" . strip0x         mkCode bs = if cmd.create                     then EVM.InitCode bs mempty                     else EVM.RuntimeCode (EVM.ConcreteRuntimeCode bs)-        address' = if cmd.create-              then addr (.address) (createAddress origin' (word (.nonce) 0))+        address = if cmd.create+              then addr (.address) (createAddress origin (word (.nonce) 0))               else addr (.address) 0xacab          vm0 baseFee miner ts blockNum prevRan c = EVM.makeVm $ EVM.VMOpts-          { vmoptContract      = c-          , vmoptCalldata      = (calldata', [])-          , vmoptValue         = Lit value'-          , vmoptAddress       = address'-          , vmoptCaller        = litAddr caller'-          , vmoptOrigin        = origin'-          , vmoptGas           = word64 (.gas) 0xffffffffffffffff-          , vmoptBaseFee       = baseFee-          , vmoptPriorityFee   = word (.priorityFee) 0-          , vmoptGaslimit      = word64 (.gaslimit) 0xffffffffffffffff-          , vmoptCoinbase      = addr (.coinbase) miner-          , vmoptNumber        = word (.number) blockNum-          , vmoptTimestamp     = Lit $ word (.timestamp) ts-          , vmoptBlockGaslimit = word64 (.gaslimit) 0xffffffffffffffff-          , vmoptGasprice      = word (.gasprice) 0-          , vmoptMaxCodeSize   = word (.maxcodesize) 0xffffffff-          , vmoptPrevRandao    = word (.prevRandao) prevRan-          , vmoptSchedule      = FeeSchedule.berlin-          , vmoptChainId       = word (.chainid) 1-          , vmoptCreate        = (.create) cmd-          , vmoptStorageBase   = EVM.Concrete-          , vmoptTxAccessList  = mempty -- TODO: support me soon-          , vmoptAllowFFI      = False+          { contract       = c+          , calldata       = (calldata, [])+          , value          = Lit value+          , address        = address+          , caller         = litAddr caller+          , origin         = origin+          , gas            = word64 (.gas) 0xffffffffffffffff+          , baseFee        = baseFee+          , priorityFee    = word (.priorityFee) 0+          , gaslimit       = word64 (.gaslimit) 0xffffffffffffffff+          , coinbase       = addr (.coinbase) miner+          , number         = word (.number) blockNum+          , timestamp      = Lit $ word (.timestamp) ts+          , blockGaslimit  = word64 (.gaslimit) 0xffffffffffffffff+          , gasprice       = word (.gasprice) 0+          , maxCodeSize    = word (.maxcodesize) 0xffffffff+          , prevRandao     = word (.prevRandao) prevRan+          , schedule       = FeeSchedule.berlin+          , chainId        = word (.chainid) 1+          , create         = (.create) cmd+          , initialStorage = EmptyStore+          , txAccessList   = mempty -- TODO: support me soon+          , allowFFI       = False           }         word f def = fromMaybe def (f cmd)         word64 f def = fromMaybe def (f cmd)@@ -607,37 +618,28 @@         bytes f def = maybe def decipher (f cmd)  symvmFromCommand :: Command Options.Unwrapped -> (Expr Buf, [Prop]) -> IO (EVM.VM)-symvmFromCommand cmd calldata' = do+symvmFromCommand cmd calldata = do   (miner,blockNum,baseFee,prevRan) <- case cmd.rpc of     Nothing -> return (0,0,0,0)-    Just url -> EVM.Fetch.fetchBlockFrom block' url >>= \case+    Just url -> EVM.Fetch.fetchBlockFrom block url >>= \case       Nothing -> error "Could not fetch block"-      Just EVM.Block{..} -> return (_coinbase-                                   , _number-                                   , _baseFee-                                   , _prevRandao+      Just EVM.Block{..} -> return ( coinbase+                                   , number+                                   , baseFee+                                   , prevRandao                                    )    let-    caller' = Caller 0+    caller = Caller 0     ts = maybe Timestamp Lit cmd.timestamp-    callvalue' = maybe (CallValue 0) Lit cmd.value+    callvalue = maybe (CallValue 0) Lit cmd.value   -- TODO: rework this, ConcreteS not needed anymore-  let store = case cmd.storageModel of-                -- InitialS and SymbolicS can read and write to symbolic locations-                -- ConcreteS cannot (instead values can be fetched from rpc!)-                -- Initial defaults to 0 for uninitialized storage slots,-                -- whereas the values of SymbolicS are unconstrained.-                Just InitialS  -> EmptyStore-                Just ConcreteS -> ConcreteStore mempty-                Just SymbolicS -> AbstractStore-                Nothing -> if cmd.create then EmptyStore else AbstractStore-+  let store = maybe AbstractStore parseInitialStorage (cmd.initialStorage)   withCache <- applyCache (cmd.state, cmd.cache) -  contract' <- case (cmd.rpc, cmd.address, cmd.code) of+  contract <- case (cmd.rpc, cmd.address, cmd.code) of     (Just url, Just addr', _) ->-      EVM.Fetch.fetchContractFrom block' url addr' >>= \case+      EVM.Fetch.fetchContractFrom block url addr' >>= \case         Nothing ->           error "contract not found."         Just contract' -> return contract''@@ -649,53 +651,59 @@               Just c -> EVM.initialContract (mkCode $ decipher c)                         -- TODO: fix this                         -- & set EVM.origStorage (view EVM.origStorage contract')-                        & set EVM.balance     (view EVM.balance contract')-                        & set EVM.nonce       (view EVM.nonce contract')-                        & set EVM.external    (view EVM.external contract')+                        & set #balance     (contract'.balance)+                        & set #nonce       (contract'.nonce)+                        & set #external    (contract'.external)      (_, _, Just c)  ->       return (EVM.initialContract . mkCode $ decipher c)     (_, _, Nothing) ->       error "must provide at least (rpc + address) or code" -  return $ (EVM.Transaction.initTx $ withCache $ vm0 baseFee miner ts blockNum prevRan calldata' callvalue' caller' contract')-    & set (EVM.env . EVM.storage) store+  return $ (EVM.Transaction.initTx $ withCache $ vm0 baseFee miner ts blockNum prevRan calldata callvalue caller contract)+    & set (#env % #storage) store    where     decipher = hexByteString "bytes" . strip0x-    block'   = maybe EVM.Fetch.Latest EVM.Fetch.BlockNumber cmd.block-    origin'  = addr (.origin) 0+    block   = maybe EVM.Fetch.Latest EVM.Fetch.BlockNumber cmd.block+    origin  = addr (.origin) 0     mkCode bs = if cmd.create                    then EVM.InitCode bs mempty                    else EVM.RuntimeCode (EVM.ConcreteRuntimeCode bs)-    address' = if cmd.create-          then addr (.address) (createAddress origin' (word (.nonce) 0))+    address = if cmd.create+          then addr (.address) (createAddress origin (word (.nonce) 0))           else addr (.address) 0xacab-    vm0 baseFee miner ts blockNum prevRan cd' callvalue' caller' c = EVM.makeVm $ EVM.VMOpts-      { vmoptContract      = c-      , vmoptCalldata      = cd'-      , vmoptValue         = callvalue'-      , vmoptAddress       = address'-      , vmoptCaller        = caller'-      , vmoptOrigin        = origin'-      , vmoptGas           = word64 (.gas) 0xffffffffffffffff-      , vmoptGaslimit      = word64 (.gaslimit) 0xffffffffffffffff-      , vmoptBaseFee       = baseFee-      , vmoptPriorityFee   = word (.priorityFee) 0-      , vmoptCoinbase      = addr (.coinbase) miner-      , vmoptNumber        = word (.number) blockNum-      , vmoptTimestamp     = ts-      , vmoptBlockGaslimit = word64 (.gaslimit) 0xffffffffffffffff-      , vmoptGasprice      = word (.gasprice) 0-      , vmoptMaxCodeSize   = word (.maxcodesize) 0xffffffff-      , vmoptPrevRandao    = word (.prevRandao) prevRan-      , vmoptSchedule      = FeeSchedule.berlin-      , vmoptChainId       = word (.chainid) 1-      , vmoptCreate        = (.create) cmd-      , vmoptStorageBase   = EVM.Symbolic-      , vmoptTxAccessList  = mempty-      , vmoptAllowFFI      = False+    vm0 baseFee miner ts blockNum prevRan cd callvalue caller c = EVM.makeVm $ EVM.VMOpts+      { contract       = c+      , calldata       = cd+      , value          = callvalue+      , address        = address+      , caller         = caller+      , origin         = origin+      , gas            = word64 (.gas) 0xffffffffffffffff+      , gaslimit       = word64 (.gaslimit) 0xffffffffffffffff+      , baseFee        = baseFee+      , priorityFee    = word (.priorityFee) 0+      , coinbase       = addr (.coinbase) miner+      , number         = word (.number) blockNum+      , timestamp      = ts+      , blockGaslimit  = word64 (.gaslimit) 0xffffffffffffffff+      , gasprice       = word (.gasprice) 0+      , maxCodeSize    = word (.maxcodesize) 0xffffffff+      , prevRandao     = word (.prevRandao) prevRan+      , schedule       = FeeSchedule.berlin+      , chainId        = word (.chainid) 1+      , create         = (.create) cmd+      , initialStorage = maybe AbstractStore parseInitialStorage (cmd.initialStorage)+      , txAccessList   = mempty+      , allowFFI       = False       }     word f def = fromMaybe def (f cmd)     addr f def = fromMaybe def (f cmd)     word64 f def = fromMaybe def (f cmd)++parseInitialStorage :: InitialStorage -> Expr Storage+parseInitialStorage = \case+  Empty -> EmptyStore+  Concrete s -> ConcreteStore (Map.fromList $ fmap (second Map.fromList) s)+  Abstract -> AbstractStore
hevm.cabal view
@@ -2,7 +2,7 @@ name:   hevm version:-  0.50.4+  0.50.5 synopsis:   Ethereum virtual machine evaluator description:@@ -61,6 +61,11 @@     ghc-options: -Werror   if flag(devel)     ghc-options: -j+  ghc-options:+    -Wall+    -Wno-unticked-promoted-constructors+    -Wno-orphans+    -Wno-ambiguous-fields   default-language: GHC2021   default-extensions:     DuplicateRecordFields@@ -68,6 +73,7 @@     NoFieldSelectors     OverloadedRecordDot     OverloadedStrings+    OverloadedLabels     RecordWildCards     TypeFamilies     ViewPatterns@@ -81,7 +87,6 @@     EVM.Concrete,     EVM.Dapp,     EVM.Debug,-    EVM.Demand,     EVM.Dev,     EVM.Expr,     EVM.SMT,@@ -116,7 +121,6 @@     Paths_hevm   autogen-modules:     Paths_hevm-  ghc-options: -Wall -Wno-deprecations -Wno-unticked-promoted-constructors -Wno-orphans   if os(linux) || os(windows)     extra-libraries: stdc++   extra-libraries:@@ -158,8 +162,10 @@     free                              >= 5.1.3 && < 5.2,     haskeline                         >= 0.8.0 && < 0.9,     process                           >= 1.6.5 && < 1.7,-    lens                              >= 5.1.1 && < 5.2,-    lens-aeson                        >= 1.2.2 && < 1.3,+    optics-core                       >= 0.4.1 && < 0.5,+    optics-extra                      >= 0.4.2.1 && < 0.5,+    optics-th                         >= 0.4.1 && < 0.5,+    aeson-optics                      >= 1.2.0.1 && < 1.3,     monad-par                         >= 0.3.5 && < 0.4,     async                             >= 2.2.4 && < 2.3,     multiset                          >= 0.3.4 && < 0.4,@@ -193,7 +199,7 @@     hevm-cli   main-is:     hevm-cli.hs-  ghc-options: -Wall -threaded -with-rtsopts=-N -Wno-unticked-promoted-constructors -Wno-orphans+  ghc-options: -threaded -with-rtsopts=-N   other-modules:     Paths_hevm   if os(darwin)@@ -219,8 +225,6 @@     filepath,     free,     hevm,-    lens,-    lens-aeson,     memory,     mtl,     optparse-generic,@@ -234,7 +238,8 @@     vector,     vty,     stm,-    spawn+    spawn,+    optics-core   if os(windows)     buildable: False @@ -242,7 +247,6 @@  common test-base   import: shared-  ghc-options: -Wall -Wno-unticked-promoted-constructors -Wno-orphans   hs-source-dirs:     test   extra-libraries:@@ -266,7 +270,6 @@     filepath,     here,     hevm,-    lens,     mtl,     data-dword,     process,@@ -286,13 +289,17 @@     spawn >= 0.3,     witherable,     smt2-parser >= 0.1.0.1,-    operational+    operational,+    optics-core,+    optics-extra  library test-utils   import:     test-base   exposed-modules:-    EVM.TestUtils+    EVM.Test.Utils+    EVM.Test.Tracing+    EVM.Test.BlockchainTests   if os(windows)     buildable: False @@ -304,8 +311,9 @@   build-depends:     test-utils   other-modules:-    EVM.TestUtils-    EVM.Tracing+    EVM.Test.Utils+    EVM.Test.Tracing+    EVM.Test.BlockchainTests   if os(windows)     buildable: False   if os(darwin)@@ -353,6 +361,8 @@     bench.hs   hs-source-dirs:     bench+  ghc-options:+    -O2   if os(darwin)      extra-libraries: c++   else@@ -368,4 +378,9 @@     bytestring,     text,     hevm,-    here+    here,+    test-utils,+    filemanip,+    filepath,+    containers,+    mtl
src/EVM.hs view
@@ -1,2763 +1,2651 @@ {-# Language ImplicitParams #-}-{-# Language DataKinds #-}-{-# Language GADTs #-}-{-# Language TemplateHaskell #-}--module EVM where--import Prelude hiding (log, exponent, GT, LT)--import EVM.ABI-import EVM.Concrete (createAddress, create2Address)-import EVM.Expr (readStorage, writeStorage, readByte, readWord, writeWord,-  writeByte, bufLength, indexWord, litAddr, readBytes, word256At, copySlice)-import EVM.Expr qualified as Expr-import EVM.FeeSchedule (FeeSchedule (..))-import EVM.Op-import EVM.Precompiled qualified-import EVM.Solidity-import EVM.Types hiding (IllegalOverflow, Error)-import EVM.Sign qualified--import Control.Lens hiding (op, (:<), (|>), (.>))-import Control.Monad.State.Strict hiding (state)-import Data.Bits (FiniteBits, countLeadingZeros, finiteBitSize)-import Data.ByteArray qualified as BA-import Data.ByteString (ByteString)-import Data.ByteString qualified as BS-import Data.ByteString.Lazy (fromStrict)-import Data.ByteString.Lazy qualified as LS-import Data.ByteString.Char8 qualified as Char8-import Data.Foldable (toList)-import Data.List (find)-import Data.Map.Strict (Map)-import Data.Map.Strict qualified as Map-import Data.Maybe (fromMaybe, fromJust)-import Data.Set (Set, insert, member, fromList)-import Data.Sequence (Seq)-import Data.Sequence qualified as Seq-import Data.Text (unpack)-import Data.Text.Encoding (decodeUtf8, encodeUtf8)-import Data.Tree-import Data.Tree.Zipper qualified as Zipper-import Data.Tuple.Curry-import Data.Vector qualified as RegularVector-import Data.Vector qualified as V-import Data.Vector.Storable (Vector)-import Data.Vector.Storable qualified as Vector-import Data.Vector.Storable.Mutable qualified as Vector-import Data.Word (Word8, Word32, Word64)-import Options.Generic as Options--import Crypto.Hash (Digest, SHA256, RIPEMD160)-import Crypto.Hash qualified as Crypto-import Crypto.Number.ModArithmetic (expFast)-import Crypto.PubKey.ECC.ECDSA (signDigestWith, PrivateKey(..), Signature(..))---- * Data types---- | EVM failure modes-data Error-  = BalanceTooLow W256 W256-  | UnrecognizedOpcode Word8-  | SelfDestruction-  | StackUnderrun-  | BadJumpDestination-  | Revert (Expr Buf)-  | OutOfGas Word64 Word64-  | BadCheatCode (Maybe Word32)-  | StackLimitExceeded-  | IllegalOverflow-  | Query Query-  | Choose Choose-  | StateChangeWhileStatic-  | InvalidMemoryAccess-  | CallDepthLimitReached-  | MaxCodeSizeExceeded W256 W256-  | InvalidFormat-  | PrecompileFailure-  | forall a . UnexpectedSymbolicArg Int String [Expr a]-  | DeadPath-  | NotUnique (Expr EWord)-  | SMTTimeout-  | FFI [AbiValue]-  | ReturnDataOutOfBounds-  | NonceOverflow-deriving instance Show Error---- | The possible result states of a VM-data VMResult-  = VMFailure Error -- ^ An operation failed-  | VMSuccess (Expr Buf) -- ^ Reached STOP, RETURN, or end-of-code--deriving instance Show VMResult---- | The state of a stepwise EVM execution-data VM = VM-  { _result         :: Maybe VMResult-  , _state          :: FrameState-  , _frames         :: [Frame]-  , _env            :: Env-  , _block          :: Block-  , _tx             :: TxState-  , _logs           :: [Expr Log]-  , _traces         :: Zipper.TreePos Zipper.Empty Trace-  , _cache          :: Cache-  , _burned         :: {-# UNPACK #-} !Word64-  , _iterations     :: Map CodeLocation Int-  , _constraints    :: [Prop]-  , _keccakEqs      :: [Prop]-  , _allowFFI       :: Bool-  , _overrideCaller :: Maybe (Expr EWord)-  }-  deriving (Show)--data Trace = Trace-  { _traceOpIx     :: Int-  , _traceContract :: Contract-  , _traceData     :: TraceData-  }-  deriving (Show)--data TraceData-  = EventTrace (Expr EWord) (Expr Buf) [Expr EWord]-  | FrameTrace FrameContext-  | QueryTrace Query-  | ErrorTrace Error-  | EntryTrace Text-  | ReturnTrace (Expr Buf) FrameContext-  deriving (Show)---- | Queries halt execution until resolved through RPC calls or SMT queries-data Query where-  PleaseFetchContract :: Addr -> (Contract -> EVM ()) -> Query-  --PleaseMakeUnique    :: SBV a -> [SBool] -> (IsUnique a -> EVM ()) -> Query-  PleaseFetchSlot     :: Addr -> W256 -> (W256 -> EVM ()) -> Query-  PleaseAskSMT        :: Expr EWord -> [Prop] -> (BranchCondition -> EVM ()) -> Query-  PleaseDoFFI         :: [String] -> (ByteString -> EVM ()) -> Query--data Choose where-  PleaseChoosePath    :: Expr EWord -> (Bool -> EVM ()) -> Choose--instance Show Query where-  showsPrec _ = \case-    PleaseFetchContract addr _ ->-      (("<EVM.Query: fetch contract " ++ show addr ++ ">") ++)-    PleaseFetchSlot addr slot _ ->-      (("<EVM.Query: fetch slot "-        ++ show slot ++ " for "-        ++ show addr ++ ">") ++)-    PleaseAskSMT condition constraints _ ->-      (("<EVM.Query: ask SMT about "-        ++ show condition ++ " in context "-        ++ show constraints ++ ">") ++)---     PleaseMakeUnique val constraints _ ->---       (("<EVM.Query: make value "---         ++ show val ++ " unique in context "---         ++ show constraints ++ ">") ++)-    PleaseDoFFI cmd _ ->-      (("<EVM.Query: do ffi: " ++ (show cmd)) ++)--instance Show Choose where-  showsPrec _ = \case-    PleaseChoosePath _ _ ->-      (("<EVM.Choice: waiting for user to select path (0,1)") ++)---- | Alias for the type of e.g. @exec1@.-type EVM a = State VM a--type CodeLocation = (Addr, Int)---- | The possible return values of a SMT query-data BranchCondition = Case Bool | Unknown | Inconsistent-  deriving Show---- | The possible return values of a `is unique` SMT query-data IsUnique a = Unique a | Multiple | InconsistentU | TimeoutU-  deriving Show---- | The cache is data that can be persisted for efficiency:--- any expensive query that is constant at least within a block.-data Cache = Cache-  { _fetchedContracts :: Map Addr Contract,-    _fetchedStorage :: Map W256 (Map W256 W256),-    _path :: Map (CodeLocation, Int) Bool-  } deriving Show--data StorageBase = Concrete | Symbolic-  deriving (Show, Eq)---- | A way to specify an initial VM state-data VMOpts = VMOpts-  { vmoptContract :: Contract-  , vmoptCalldata :: (Expr Buf, [Prop])-  , vmoptStorageBase :: StorageBase-  , vmoptValue :: Expr EWord-  , vmoptPriorityFee :: W256-  , vmoptAddress :: Addr-  , vmoptCaller :: Expr EWord-  , vmoptOrigin :: Addr-  , vmoptGas :: Word64-  , vmoptGaslimit :: Word64-  , vmoptNumber :: W256-  , vmoptTimestamp :: Expr EWord-  , vmoptCoinbase :: Addr-  , vmoptPrevRandao :: W256-  , vmoptMaxCodeSize :: W256-  , vmoptBlockGaslimit :: Word64-  , vmoptGasprice :: W256-  , vmoptBaseFee :: W256-  , vmoptSchedule :: FeeSchedule Word64-  , vmoptChainId :: W256-  , vmoptCreate :: Bool-  , vmoptTxAccessList :: Map Addr [W256]-  , vmoptAllowFFI :: Bool-  } deriving Show---- | An entry in the VM's "call/create stack"-data Frame = Frame-  { _frameContext   :: FrameContext-  , _frameState     :: FrameState-  }-  deriving (Show)---- | Call/create info-data FrameContext-  = CreationContext-    { creationContextAddress   :: Addr-    , creationContextCodehash  :: Expr EWord-    , creationContextReversion :: Map Addr Contract-    , creationContextSubstate  :: SubState-    }-  | CallContext-    { callContextTarget    :: Addr-    , callContextContext   :: Addr-    , callContextOffset    :: W256-    , callContextSize      :: W256-    , callContextCodehash  :: Expr EWord-    , callContextAbi       :: Maybe W256-    , callContextData      :: Expr Buf-    , callContextReversion :: (Map Addr Contract, Expr Storage)-    , callContextSubState  :: SubState-    }-  deriving (Show)---- | The "registers" of the VM along with memory and data stack-data FrameState = FrameState-  { _contract     :: Addr-  , _codeContract :: Addr-  , _code         :: ContractCode-  , _pc           :: {-# UNPACK #-} !Int-  , _stack        :: [Expr EWord]-  , _memory       :: Expr Buf-  , _memorySize   :: Word64-  , _calldata     :: Expr Buf-  , _callvalue    :: Expr EWord-  , _caller       :: Expr EWord-  , _gas          :: {-# UNPACK #-} !Word64-  , _returndata   :: Expr Buf-  , _static       :: Bool-  }-  deriving (Show)---- | The state that spans a whole transaction-data TxState = TxState-  { _gasprice            :: W256-  , _txgaslimit          :: Word64-  , _txPriorityFee       :: W256-  , _origin              :: Addr-  , _toAddr              :: Addr-  , _value               :: Expr EWord-  , _substate            :: SubState-  , _isCreate            :: Bool-  , _txReversion         :: Map Addr Contract-  }-  deriving (Show)---- | The "accrued substate" across a transaction-data SubState = SubState-  { _selfdestructs   :: [Addr]-  , _touchedAccounts :: [Addr]-  , _accessedAddresses :: Set Addr-  , _accessedStorageKeys :: Set (Addr, W256)-  , _refunds         :: [(Addr, Word64)]-  -- in principle we should include logs here, but do not for now-  }-  deriving (Show)--{- |-  A contract is either in creation (running its "constructor") or-  post-creation, and code in these two modes is treated differently-  by instructions like @EXTCODEHASH@, so we distinguish these two-  code types.--  The definition follows the structure of code output by solc. We need to use-  some heuristics here to deal with symbolic data regions that may be present-  in the bytecode since the fully abstract case is impractical:--  - initcode has concrete code, followed by an abstract data "section"-  - runtimecode has a fixed length, but may contain fixed size symbolic regions (due to immutable)--  hopefully we do not have to deal with dynamic immutable before we get a real data section...--}-data ContractCode-  = InitCode ByteString (Expr Buf) -- ^ "Constructor" code, during contract creation-  | RuntimeCode RuntimeCode -- ^ "Instance" code, after contract creation-  deriving (Show)---- | We have two variants here to optimize the fully concrete case.--- ConcreteRuntimeCode just wraps a ByteString--- SymbolicRuntimeCode is a fixed length vector of potentially symbolic bytes, which lets us handle symbolic pushdata (e.g. from immutable variables in solidity).-data RuntimeCode-  = ConcreteRuntimeCode ByteString-  | SymbolicRuntimeCode (V.Vector (Expr Byte))-  deriving (Show, Eq, Ord)---- runtime err when used for symbolic code-instance Eq ContractCode where-  (InitCode a b) == (InitCode c d) = a == c && b == d-  (RuntimeCode x) == (RuntimeCode y) = x == y-  _ == _ = False--deriving instance Ord ContractCode---- | A contract can either have concrete or symbolic storage--- depending on what type of execution we are doing--- data Storage---   = Concrete (Map Word Expr EWord)---   | Symbolic [(Expr EWord, Expr EWord)] (SArray (WordN 256) (WordN 256))---   deriving (Show)---- to allow for Eq Contract (which useful for debugging vmtests)--- we mock an instance of Eq for symbolic storage.--- It should not (cannot) be used though.--- instance Eq Storage where---   (==) (Concrete a) (Concrete b) = fmap forceLit a == fmap forceLit b---   (==) (Symbolic _ _) (Concrete _) = False---   (==) (Concrete _) (Symbolic _ _) = False---   (==) _ _ = error "do not compare two symbolic arrays like this!"---- | The state of a contract-data Contract = Contract-  { _contractcode :: ContractCode-  , _balance      :: W256-  , _nonce        :: W256-  , _codehash     :: Expr EWord-  , _opIxMap      :: Vector Int-  , _codeOps      :: RegularVector.Vector (Int, Op)-  , _external     :: Bool-  }--deriving instance Show Contract---- | When doing symbolic execution, we have three different--- ways to model the storage of contracts. This determines--- not only the initial contract storage model but also how--- RPC or state fetched contracts will be modeled.-data StorageModel-  = ConcreteS    -- ^ Uses `Concrete` Storage. Reading / Writing from abstract-                 -- locations causes a runtime failure. Can be nicely combined with RPC.--  | SymbolicS    -- ^ Uses `Symbolic` Storage. Reading / Writing never reaches RPC,-                 -- but always done using an SMT array with no default value.--  | InitialS     -- ^ Uses `Symbolic` Storage. Reading / Writing never reaches RPC,-                 -- but always done using an SMT array with 0 as the default value.--  deriving (Read, Show)--instance ParseField StorageModel---- | Various environmental data-data Env = Env-  { _contracts    :: Map Addr Contract-  , _chainId      :: W256-  , _storage      :: Expr Storage-  , _origStorage  :: Map W256 (Map W256 W256)-  , _sha3Crack    :: Map W256 ByteString-  --, _keccakUsed   :: [([SWord 8], SWord 256)]-  }-  deriving (Show)----- | Data about the block-data Block = Block-  { _coinbase    :: Addr-  , _timestamp   :: Expr EWord-  , _number      :: W256-  , _prevRandao  :: W256-  , _gaslimit    :: Word64-  , _baseFee     :: W256-  , _maxCodeSize :: W256-  , _schedule    :: FeeSchedule Word64-  } deriving (Show, Generic)---blankState :: FrameState-blankState = FrameState-  { _contract     = 0-  , _codeContract = 0-  , _code         = RuntimeCode (ConcreteRuntimeCode "")-  , _pc           = 0-  , _stack        = mempty-  , _memory       = mempty-  , _memorySize   = 0-  , _calldata     = mempty-  , _callvalue    = (Lit 0)-  , _caller       = (Lit 0)-  , _gas          = 0-  , _returndata   = mempty-  , _static       = False-  }--makeLenses ''FrameState-makeLenses ''Frame-makeLenses ''Block-makeLenses ''TxState-makeLenses ''SubState-makeLenses ''Contract-makeLenses ''Env-makeLenses ''Cache-makeLenses ''Trace-makeLenses ''VM---- | An "external" view of a contract's bytecode, appropriate for--- e.g. @EXTCODEHASH@.-bytecode :: Getter Contract (Expr Buf)-bytecode = contractcode . to f-  where f (InitCode _ _) = mempty-        f (RuntimeCode (ConcreteRuntimeCode bs)) = ConcreteBuf bs-        f (RuntimeCode (SymbolicRuntimeCode ops)) = Expr.fromList ops--instance Semigroup Cache where-  a <> b = Cache-    { _fetchedContracts = Map.unionWith unifyCachedContract a._fetchedContracts b._fetchedContracts-    , _fetchedStorage = Map.unionWith unifyCachedStorage a._fetchedStorage b._fetchedStorage-    , _path = mappend a._path b._path-    }--unifyCachedStorage :: Map W256 W256 -> Map W256 W256 -> Map W256 W256-unifyCachedStorage _ _ = undefined---- only intended for use in Cache merges, where we expect--- everything to be Concrete-unifyCachedContract :: Contract -> Contract -> Contract-unifyCachedContract _ _ = undefined-  {--unifyCachedContract a b = a & set storage merged-  where merged = case (view storage a, view storage b) of-                   (ConcreteStore sa, ConcreteStore sb) ->-                     ConcreteStore (mappend sa sb)-                   _ ->-                     view storage a-   -}--instance Monoid Cache where-  mempty = Cache { _fetchedContracts = mempty,-                   _fetchedStorage = mempty,-                   _path = mempty-                 }---- * Data accessors--currentContract :: VM -> Maybe Contract-currentContract vm =-  Map.lookup vm._state._codeContract vm._env._contracts---- * Data constructors--makeVm :: VMOpts -> VM-makeVm o =-  let txaccessList = o.vmoptTxAccessList-      txorigin = o.vmoptOrigin-      txtoAddr = o.vmoptAddress-      initialAccessedAddrs = fromList $ [txorigin, txtoAddr] ++ [1..9] ++ (Map.keys txaccessList)-      initialAccessedStorageKeys = fromList $ foldMap (uncurry (map . (,))) (Map.toList txaccessList)-      touched = if o.vmoptCreate then [txorigin] else [txorigin, txtoAddr]-  in-  VM-  { _result = Nothing-  , _frames = mempty-  , _tx = TxState-    { _gasprice = o.vmoptGasprice-    , _txgaslimit = o.vmoptGaslimit-    , _txPriorityFee = o.vmoptPriorityFee-    , _origin = txorigin-    , _toAddr = txtoAddr-    , _value = o.vmoptValue-    , _substate = SubState mempty touched initialAccessedAddrs initialAccessedStorageKeys mempty-    --, _accessList = txaccessList-    , _isCreate = o.vmoptCreate-    , _txReversion = Map.fromList-      [(o.vmoptAddress , o.vmoptContract )]-    }-  , _logs = []-  , _traces = Zipper.fromForest []-  , _block = Block-    { _coinbase = o.vmoptCoinbase-    , _timestamp = o.vmoptTimestamp-    , _number = o.vmoptNumber-    , _prevRandao = o.vmoptPrevRandao-    , _maxCodeSize = o.vmoptMaxCodeSize-    , _gaslimit = o.vmoptBlockGaslimit-    , _baseFee = o.vmoptBaseFee-    , _schedule = o.vmoptSchedule-    }-  , _state = FrameState-    { _pc = 0-    , _stack = mempty-    , _memory = mempty-    , _memorySize = 0-    , _code = o.vmoptContract._contractcode-    , _contract = o.vmoptAddress-    , _codeContract = o.vmoptAddress-    , _calldata = fst o.vmoptCalldata-    , _callvalue = o.vmoptValue-    , _caller = o.vmoptCaller-    , _gas = o.vmoptGas-    , _returndata = mempty-    , _static = False-    }-  , _env = Env-    { _sha3Crack = mempty-    , _chainId = o.vmoptChainId-    , _storage = if o.vmoptStorageBase == Concrete then EmptyStore else AbstractStore-    , _origStorage = mempty-    , _contracts = Map.fromList-      [(o.vmoptAddress, o.vmoptContract )]-    --, _keccakUsed = mempty-    --, _storageModel = vmoptStorageModel o-    }-  , _cache = Cache mempty mempty mempty-  , _burned = 0-  , _constraints = snd o.vmoptCalldata-  , _keccakEqs = mempty-  , _iterations = mempty-  , _allowFFI = o.vmoptAllowFFI-  , _overrideCaller = Nothing-  }---- | Initialize empty contract with given code-initialContract :: ContractCode -> Contract-initialContract theContractCode = Contract-  { _contractcode = theContractCode-  , _codehash = hashcode theContractCode-  , _balance  = 0-  , _nonce    = if creation then 1 else 0-  , _opIxMap  = mkOpIxMap theContractCode-  , _codeOps  = mkCodeOps theContractCode-  , _external = False-  } where-      creation = case theContractCode of-        InitCode _ _  -> True-        RuntimeCode _ -> False---- * Opcode dispatch (exec1)---- | Update program counter-next :: (?op :: Word8) => EVM ()-next = modifying (state . pc) (+ (opSize ?op))---- | Executes the EVM one step-exec1 :: EVM ()-exec1 = do-  vm <- get--  let-    -- Convenient aliases-    mem  = vm._state._memory-    stk  = vm._state._stack-    self = vm._state._contract-    this = fromMaybe (error "internal error: state contract") (Map.lookup self vm._env._contracts)--    fees@FeeSchedule {..} = vm._block._schedule--    doStop = finishFrame (FrameReturned mempty)--  if self > 0x0 && self <= 0x9 then do-    -- call to precompile-    let ?op = 0x00 -- dummy value-    case bufLength vm._state._calldata of-      (Lit calldatasize) -> do-          copyBytesToMemory vm._state._calldata (Lit calldatasize) (Lit 0) (Lit 0)-          executePrecompile self vm._state._gas 0 calldatasize 0 0 []-          vmx <- get-          case vmx._state._stack of-            (x:_) -> case x of-              Lit (num -> x' :: Integer) -> case x' of-                0 -> do-                  fetchAccount self $ \_ -> do-                    touchAccount self-                    vmError PrecompileFailure-                _ -> fetchAccount self $ \_ -> do-                    touchAccount self-                    out <- use (state . returndata)-                    finishFrame (FrameReturned out)-              e -> vmError $-                UnexpectedSymbolicArg vmx._state._pc "precompile returned a symbolic value" [e]-            _ ->-              underrun-      e -> vmError $ UnexpectedSymbolicArg vm._state._pc "cannot call precompiles with symbolic data" [e]--  else if vm._state._pc >= opslen vm._state._code-    then doStop--    else do-      let ?op = case vm._state._code of-                  InitCode conc _ -> BS.index conc vm._state._pc-                  RuntimeCode (ConcreteRuntimeCode bs) -> BS.index bs vm._state._pc-                  RuntimeCode (SymbolicRuntimeCode ops) ->-                    fromMaybe (error "could not analyze symbolic code") $-                      unlitByte $ ops V.! vm._state._pc--      case getOp(?op) of--        OpPush n' -> do-          let n = fromIntegral n'-              !xs = case vm._state._code of-                InitCode conc _ -> Lit $ word $ padRight n $ BS.take n (BS.drop (1 + vm._state._pc) conc)-                RuntimeCode (ConcreteRuntimeCode bs) -> Lit $ word $ BS.take n $ BS.drop (1 + vm._state._pc) bs-                RuntimeCode (SymbolicRuntimeCode ops) ->-                  let bytes = V.take n $ V.drop (1 + vm._state._pc) ops-                  in readWord (Lit 0) $ Expr.fromList $ padLeft' 32 bytes-          limitStack 1 $-            burn g_verylow $ do-              next-              pushSym xs--        OpDup i ->-          case preview (ix (fromIntegral i - 1)) stk of-            Nothing -> underrun-            Just y ->-              limitStack 1 $-                burn g_verylow $ do-                  next-                  pushSym y--        OpSwap i ->-          if length stk < (fromIntegral i) + 1-            then underrun-            else-              burn g_verylow $ do-                next-                zoom (state . stack) $ do-                  assign (ix 0) (stk ^?! ix (fromIntegral i))-                  assign (ix (fromIntegral i)) (stk ^?! ix 0)--        OpLog n ->-          notStatic $-          case stk of-            (xOffset':xSize':xs) ->-              if length xs < (fromIntegral n)-              then underrun-              else-                forceConcrete2 (xOffset', xSize') "LOG" $ \(xOffset, xSize) -> do-                    let (topics, xs') = splitAt (fromIntegral n) xs-                        bytes         = readMemory xOffset' xSize' vm-                        logs'         = (LogEntry (litAddr self) bytes topics) : vm._logs-                    burn (g_log + g_logdata * (num xSize) + num n * g_logtopic) $-                      accessMemoryRange xOffset xSize $ do-                        traceTopLog logs'-                        next-                        assign (state . stack) xs'-                        assign logs logs'-            _ ->-              underrun--        OpStop -> doStop--        OpAdd -> stackOp2 g_verylow (uncurry Expr.add)-        OpMul -> stackOp2 g_low (uncurry Expr.mul)-        OpSub -> stackOp2 g_verylow (uncurry Expr.sub)--        OpDiv -> stackOp2 g_low (uncurry Expr.div)--        OpSdiv -> stackOp2 g_low (uncurry Expr.sdiv)--        OpMod-> stackOp2 g_low (uncurry Expr.mod)--        OpSmod -> stackOp2 g_low (uncurry Expr.smod)-        OpAddmod -> stackOp3 g_mid (uncurryN Expr.addmod)-        OpMulmod -> stackOp3 g_mid (uncurryN Expr.mulmod)--        OpLt -> stackOp2 g_verylow (uncurry Expr.lt)-        OpGt -> stackOp2 g_verylow (uncurry Expr.gt)-        OpSlt -> stackOp2 g_verylow (uncurry Expr.slt)-        OpSgt -> stackOp2 g_verylow (uncurry Expr.sgt)--        OpEq -> stackOp2 g_verylow (uncurry Expr.eq)-        OpIszero -> stackOp1 g_verylow Expr.iszero--        OpAnd -> stackOp2 g_verylow (uncurry Expr.and)-        OpOr -> stackOp2 g_verylow (uncurry Expr.or)-        OpXor -> stackOp2 g_verylow (uncurry Expr.xor)-        OpNot -> stackOp1 g_verylow Expr.not--        OpByte -> stackOp2 g_verylow (\(i, w) -> Expr.padByte $ Expr.indexWord i w)--        OpShl -> stackOp2 g_verylow (uncurry Expr.shl)-        OpShr -> stackOp2 g_verylow (uncurry Expr.shr)-        OpSar -> stackOp2 g_verylow (uncurry Expr.sar)--        -- more accurately refered to as KECCAK-        OpSha3 ->-          case stk of-            (xOffset' : xSize' : xs) ->-              forceConcrete xOffset' "sha3 offset must be concrete" $-                \xOffset -> forceConcrete xSize' "sha3 size must be concrete" $ \xSize ->-                  burn (g_sha3 + g_sha3word * ceilDiv (num xSize) 32) $-                    accessMemoryRange xOffset xSize $ do-                      (hash, invMap) <- case readMemory xOffset' xSize' vm of-                                          ConcreteBuf bs -> do-                                            let hash' = keccak' bs-                                            eqs <- use keccakEqs-                                            assign keccakEqs $ PEq (Lit hash') (Keccak (ConcreteBuf bs)):eqs-                                            pure (Lit hash', Map.singleton hash' bs)-                                          buf -> pure (Keccak buf, mempty)-                      next-                      assign (state . stack) (hash : xs)-                      (env . sha3Crack) <>= invMap-            _ -> underrun--        OpAddress ->-          limitStack 1 $-            burn g_base (next >> push (num self))--        OpBalance ->-          case stk of-            (x':xs) -> forceConcrete x' "BALANCE" $ \x ->-              accessAndBurn (num x) $-                fetchAccount (num x) $ \c -> do-                  next-                  assign (state . stack) xs-                  push (num c._balance)-            [] ->-              underrun--        OpOrigin ->-          limitStack 1 . burn g_base $-            next >> push (num vm._tx._origin)--        OpCaller ->-          limitStack 1 . burn g_base $-            next >> pushSym vm._state._caller--        OpCallvalue ->-          limitStack 1 . burn g_base $-            next >> pushSym vm._state._callvalue--        OpCalldataload -> stackOp1 g_verylow $-          \ind -> Expr.readWord ind vm._state._calldata--        OpCalldatasize ->-          limitStack 1 . burn g_base $-            next >> pushSym (bufLength vm._state._calldata)--        OpCalldatacopy ->-          case stk of-            (xTo' : xFrom : xSize' : xs) ->-              forceConcrete2 (xTo', xSize') "CALLDATACOPY" $-                \(xTo, xSize) ->-                  burn (g_verylow + g_copy * ceilDiv (num xSize) 32) $-                    accessMemoryRange xTo xSize $ do-                      next-                      assign (state . stack) xs-                      copyBytesToMemory vm._state._calldata xSize' xFrom xTo'-            _ -> underrun--        OpCodesize ->-          limitStack 1 . burn g_base $-            next >> pushSym (codelen vm._state._code)--        OpCodecopy ->-          case stk of-            (memOffset' : codeOffset : n' : xs) ->-              forceConcrete2 (memOffset', n') "CODECOPY" $-                \(memOffset,n) -> do-                  case toWord64 n of-                    Nothing -> vmError IllegalOverflow-                    Just n'' ->-                      if n'' <= ( (maxBound :: Word64) - g_verylow ) `div` g_copy * 32 then-                        burn (g_verylow + g_copy * ceilDiv (num n) 32) $-                          accessMemoryRange memOffset n $ do-                            next-                            assign (state . stack) xs-                            copyBytesToMemory (toBuf vm._state._code) n' codeOffset memOffset'-                      else vmError IllegalOverflow-            _ -> underrun--        OpGasprice ->-          limitStack 1 . burn g_base $-            next >> push vm._tx._gasprice--        OpExtcodesize ->-          case stk of-            (x':xs) -> case x' of-              (Lit x) -> if x == num cheatCode-                then do-                  next-                  assign (state . stack) xs-                  pushSym (Lit 1)-                else-                  accessAndBurn (num x) $-                    fetchAccount (num x) $ \c -> do-                      next-                      assign (state . stack) xs-                      pushSym (bufLength (view bytecode c))-              _ -> do-                assign (state . stack) xs-                pushSym (CodeSize x')-                next-            [] ->-              underrun--        OpExtcodecopy ->-          case stk of-            ( extAccount'-              : memOffset'-              : codeOffset-              : codeSize'-              : xs ) ->-              forceConcrete3 (extAccount', memOffset', codeSize') "EXTCODECOPY" $-                \(extAccount, memOffset, codeSize) -> do-                  acc <- accessAccountForGas (num extAccount)-                  let cost = if acc then g_warm_storage_read else g_cold_account_access-                  burn (cost + g_copy * ceilDiv (num codeSize) 32) $-                    accessMemoryRange memOffset codeSize $-                      fetchAccount (num extAccount) $ \c -> do-                        next-                        assign (state . stack) xs-                        copyBytesToMemory (view bytecode c) codeSize' codeOffset memOffset'-            _ -> underrun--        OpReturndatasize ->-          limitStack 1 . burn g_base $-            next >> pushSym (bufLength vm._state._returndata)--        OpReturndatacopy ->-          case stk of-            (xTo' : xFrom : xSize' :xs) -> forceConcrete2 (xTo', xSize') "RETURNDATACOPY" $-              \(xTo, xSize) ->-                burn (g_verylow + g_copy * ceilDiv (num xSize) 32) $-                  accessMemoryRange xTo xSize $ do-                    next-                    assign (state . stack) xs--                    let jump True = vmError EVM.ReturnDataOutOfBounds-                        jump False = copyBytesToMemory vm._state._returndata xSize' xFrom xTo'--                    case (xFrom, bufLength vm._state._returndata) of-                      (Lit f, Lit l) ->-                        jump $ l < f + xSize || f + xSize < f-                      _ -> do-                        let oob = Expr.lt (bufLength vm._state._returndata) (Expr.add xFrom xSize')-                            overflow = Expr.lt (Expr.add xFrom xSize') (xFrom)-                        loc <- codeloc-                        branch loc (Expr.or oob overflow) jump-            _ -> underrun--        OpExtcodehash ->-          case stk of-            (x':xs) -> forceConcrete x' "EXTCODEHASH" $ \x ->-              accessAndBurn (num x) $ do-                next-                assign (state . stack) xs-                fetchAccount (num x) $ \c ->-                   if accountEmpty c-                     then push (num (0 :: Int))-                     else pushSym $ keccak (view bytecode c)-            [] ->-              underrun--        OpBlockhash -> do-          -- We adopt the fake block hash scheme of the VMTests,-          -- so that blockhash(i) is the hash of i as decimal ASCII.-          stackOp1 g_blockhash $ \case-            (Lit i) -> if i + 256 < vm._block._number || i >= vm._block._number-                       then Lit 0-                       else (num i :: Integer) & show & Char8.pack & keccak' & Lit-            i -> BlockHash i--        OpCoinbase ->-          limitStack 1 . burn g_base $-            next >> push (num vm._block._coinbase)--        OpTimestamp ->-          limitStack 1 . burn g_base $-            next >> pushSym vm._block._timestamp--        OpNumber ->-          limitStack 1 . burn g_base $-            next >> push vm._block._number--        OpPrevRandao -> do-          limitStack 1 . burn g_base $-            next >> push vm._block._prevRandao--        OpGaslimit ->-          limitStack 1 . burn g_base $-            next >> push (num vm._block._gaslimit)--        OpChainid ->-          limitStack 1 . burn g_base $-            next >> push vm._env._chainId--        OpSelfbalance ->-          limitStack 1 . burn g_low $-            next >> push this._balance--        OpBaseFee ->-          limitStack 1 . burn g_base $-            next >> push vm._block._baseFee--        OpPop ->-          case stk of-            (_:xs) -> burn g_base (next >> assign (state . stack) xs)-            _      -> underrun--        OpMload ->-          case stk of-            (x':xs) -> forceConcrete x' "MLOAD" $ \x ->-              burn g_verylow $-                accessMemoryWord x $ do-                  next-                  assign (state . stack) (readWord (Lit x) mem : xs)-            _ -> underrun--        OpMstore ->-          case stk of-            (x':y:xs) -> forceConcrete x' "MSTORE index" $ \x ->-              burn g_verylow $-                accessMemoryWord x $ do-                  next-                  assign (state . memory) (writeWord (Lit x) y mem)-                  assign (state . stack) xs-            _ -> underrun--        OpMstore8 ->-          case stk of-            (x':y:xs) -> forceConcrete x' "MSTORE8" $ \x ->-              burn g_verylow $-                accessMemoryRange x 1 $ do-                  let yByte = indexWord (Lit 31) y-                  next-                  modifying (state . memory) (writeByte (Lit x) yByte)-                  assign (state . stack) xs-            _ -> underrun--        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)-            _ -> underrun--        OpSstore ->-          notStatic $-          case stk of-            (x:new:xs) ->-              accessStorage self x $ \current -> do-                availableGas <- use (state . gas)--                if num availableGas <= g_callstipend-                  then finishFrame (FrameErrored (OutOfGas availableGas (num g_callstipend)))-                  else do-                    let original = case readStorage (litAddr self) x (ConcreteStore vm._env._origStorage) of-                                     Just (Lit v) -> v-                                     _ -> 0-                    let storage_cost = case (maybeLitWord current, maybeLitWord 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--                    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 . storage)-                        (writeStorage (litAddr self) x new)--                      case (maybeLitWord current, maybeLitWord 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 new' == 0-                                        then refund (g_sreset + g_access_list_storage_key)-                                        else unRefund (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-            _ -> underrun--        OpJump ->-          case stk of-            (x:xs) ->-              burn g_mid $ forceConcrete x "JUMP: symbolic jumpdest" $ \x' ->-                case toInt x' of-                  Nothing -> vmError EVM.BadJumpDestination-                  Just i -> checkJump i xs-            _ -> underrun--        OpJumpi -> do-          case stk of-            (x:y:xs) -> forceConcrete x "JUMPI: symbolic jumpdest" $ \x' ->-                burn g_high $-                  let jump :: Bool -> EVM ()-                      jump False = assign (state . stack) xs >> next-                      jump _    = case toInt x' of-                        Nothing -> vmError EVM.BadJumpDestination-                        Just i -> checkJump i xs-                  in case maybeLitWord y of-                      Just y' -> jump (0 /= y')-                      -- if the jump condition is symbolic, we explore both sides-                      Nothing -> do-                        loc <- codeloc-                        branch loc y jump-            _ -> underrun--        OpPc ->-          limitStack 1 . burn g_base $-            next >> push (num vm._state._pc)--        OpMsize ->-          limitStack 1 . burn g_base $-            next >> push (num vm._state._memorySize)--        OpGas ->-          limitStack 1 . burn g_base $-            next >> push (num (vm._state._gas - g_base))--        OpJumpdest -> burn g_jumpdest next--        OpExp ->-          -- NOTE: this can be done symbolically using unrolling like this:-          --       https://hackage.haskell.org/package/sbv-9.0/docs/src/Data.SBV.Core.Model.html#.%5E-          --       However, it requires symbolic gas, since the gas depends on the exponent-          case stk of-            (base:exponent':xs) -> forceConcrete exponent' "EXP: symbolic exponent" $ \exponent ->-              let cost = if exponent == 0-                         then g_exp-                         else g_exp + g_expbyte * num (ceilDiv (1 + log2 exponent) 8)-              in burn cost $ do-                next-                state . stack .= Expr.exp base exponent' : xs-            _ -> underrun--        OpSignextend -> stackOp2 g_low (uncurry Expr.sex)--        OpCreate ->-          notStatic $-          case stk of-            (xValue' : xOffset' : xSize' : xs) -> forceConcrete3 (xValue', xOffset', xSize') "CREATE" $-              \(xValue, xOffset, xSize) -> do-                accessMemoryRange xOffset xSize $ do-                  availableGas <- use (state . gas)-                  let-                    newAddr = createAddress self this._nonce-                    (cost, gas') = costOfCreate fees availableGas 0-                  _ <- accessAccountForGas newAddr-                  burn (cost - gas') $ do-                    -- unfortunately we have to apply some (pretty hacky)-                    -- heuristics here to parse the unstructured buffer read-                    -- from memory into a code and data section-                    let initCode = readMemory xOffset' xSize' vm-                    create self this (num gas') xValue xs newAddr initCode-            _ -> underrun--        OpCall ->-          case stk of-            ( xGas'-              : xTo-              : xValue'-              : xInOffset'-              : xInSize'-              : xOutOffset'-              : xOutSize'-              : xs-             ) -> forceConcrete6 (xGas', xValue', xInOffset', xInSize', xOutOffset', xOutSize') "CALL" $-              \(xGas, xValue, xInOffset, xInSize, xOutOffset, xOutSize) ->-                (if xValue > 0 then notStatic else id) $-                  delegateCall this (num xGas) xTo xTo xValue xInOffset xInSize xOutOffset xOutSize xs $ \callee -> do-                    zoom state $ do-                      assign callvalue (Lit xValue)-                      assign caller $ fromMaybe (litAddr self) (vm ^. overrideCaller)-                      assign contract callee-                    assign overrideCaller Nothing-                    transfer self callee xValue-                    touchAccount self-                    touchAccount callee-            _ ->-              underrun--        OpCallcode ->-          case stk of-            ( xGas'-              : xTo-              : xValue'-              : xInOffset'-              : xInSize'-              : xOutOffset'-              : xOutSize'-              : xs-              ) -> forceConcrete6 (xGas', xValue', xInOffset', xInSize', xOutOffset', xOutSize') "CALLCODE" $-                \(xGas, xValue, xInOffset, xInSize, xOutOffset, xOutSize) ->-                  delegateCall this (num xGas) xTo (litAddr self) xValue xInOffset xInSize xOutOffset xOutSize xs $ \_ -> do-                    zoom state $ do-                      assign callvalue (Lit xValue)-                      assign caller $ fromMaybe (litAddr self) (vm ^. overrideCaller)-                    assign overrideCaller Nothing-                    touchAccount self-            _ ->-              underrun--        OpReturn ->-          case stk of-            (xOffset' : xSize' :_) -> forceConcrete2 (xOffset', xSize') "RETURN" $ \(xOffset, xSize) ->-              accessMemoryRange xOffset xSize $ do-                let-                  output = readMemory xOffset' xSize' vm-                  codesize = fromMaybe (error "RETURN: cannot return dynamically sized abstract data")-                               . unlit . bufLength $ output-                  maxsize = vm._block._maxCodeSize-                  creation = case vm._frames of-                    [] -> vm._tx._isCreate-                    frame:_ -> case frame._frameContext of-                       CreationContext {} -> True-                       CallContext {} -> False-                if creation-                then-                  if codesize > maxsize-                  then-                    finishFrame (FrameErrored (MaxCodeSizeExceeded maxsize codesize))-                  else do-                    let frameReturned = burn (g_codedeposit * num codesize) $-                                          finishFrame (FrameReturned output)-                        frameErrored = finishFrame $ FrameErrored InvalidFormat-                    case readByte (Lit 0) output of-                      LitByte 0xef -> frameErrored-                      LitByte _ -> frameReturned-                      y -> do-                        loc <- codeloc-                        branch loc (Expr.eqByte y (LitByte 0xef)) $ \case-                          True -> frameErrored-                          False -> frameReturned-                else-                   finishFrame (FrameReturned output)-            _ -> underrun--        OpDelegatecall ->-          case stk of-            (xGas'-             :xTo-             :xInOffset'-             :xInSize'-             :xOutOffset'-             :xOutSize'-             :xs) -> forceConcrete5 (xGas', xInOffset', xInSize', xOutOffset', xOutSize') "DELEGATECALL" $-              \(xGas, xInOffset, xInSize, xOutOffset, xOutSize) ->-                delegateCall this (num xGas) xTo (litAddr self) 0 xInOffset xInSize xOutOffset xOutSize xs $ \_ -> do-                  touchAccount self-            _ -> underrun--        OpCreate2 -> notStatic $-          case stk of-            (xValue'-             :xOffset'-             :xSize'-             :xSalt'-             :xs) -> forceConcrete4 (xValue', xOffset', xSize', xSalt') "CREATE2" $-              \(xValue, xOffset, xSize, xSalt) ->-                accessMemoryRange xOffset xSize $ do-                  availableGas <- use (state . gas)--                  forceConcreteBuf (readMemory xOffset' xSize' vm) "CREATE2" $-                    \initCode -> do-                      let-                        newAddr  = create2Address self xSalt initCode-                        (cost, gas') = costOfCreate fees availableGas xSize-                      _ <- accessAccountForGas newAddr-                      burn (cost - gas') $ create self this gas' xValue xs newAddr (ConcreteBuf initCode)-            _ -> underrun--        OpStaticcall ->-          case stk of-            (xGas'-             :xTo-             :xInOffset'-             :xInSize'-             :xOutOffset'-             :xOutSize'-             :xs) -> forceConcrete5 (xGas', xInOffset', xInSize', xOutOffset', xOutSize') "STATICCALL" $-              \(xGas, xInOffset, xInSize, xOutOffset, xOutSize) -> do-                delegateCall this (num xGas) xTo xTo 0 xInOffset xInSize xOutOffset xOutSize xs $ \callee -> do-                  zoom state $ do-                    assign callvalue (Lit 0)-                    assign caller $ fromMaybe (litAddr self) (vm ^. overrideCaller)-                    assign contract callee-                    assign static True-                  assign overrideCaller Nothing-                  touchAccount self-                  touchAccount callee-            _ ->-              underrun--        OpSelfdestruct ->-          notStatic $-          case stk of-            [] -> underrun-            (xTo':_) -> forceConcrete xTo' "SELFDESTRUCT" $ \(num -> xTo) -> do-              acc <- accessAccountForGas (num xTo)-              let cost = if acc then 0 else g_cold_account_access-                  funds = this._balance-                  recipientExists = accountExists xTo vm-                  c_new = if not recipientExists && funds /= 0-                          then g_selfdestruct_newaccount-                          else 0-              burn (g_selfdestruct + c_new + cost) $ do-                   selfdestruct self-                   touchAccount xTo--                   if funds /= 0-                   then fetchAccount xTo $ \_ -> do-                          env . contracts . ix xTo . balance += funds-                          assign (env . contracts . ix self . balance) 0-                          doStop-                   else doStop--        OpRevert ->-          case stk of-            (xOffset':xSize':_) -> forceConcrete2 (xOffset', xSize') "REVERT" $ \(xOffset, xSize) ->-              accessMemoryRange xOffset xSize $ do-                let output = readMemory xOffset' xSize' vm-                finishFrame (FrameReverted output)-            _ -> underrun--        OpUnknown xxx ->-          vmError (UnrecognizedOpcode xxx)--transfer :: Addr -> Addr -> W256 -> EVM ()-transfer xFrom xTo xValue =-  zoom (env . contracts) $ do-    ix xFrom . balance -= xValue-    ix xTo  . balance += xValue---- | Checks a *CALL for failure; OOG, too many callframes, memory access etc.-callChecks-  :: (?op :: Word8)-  => Contract -> Word64 -> Addr -> Addr -> W256 -> W256 -> W256 -> W256 -> W256 -> [Expr EWord]-   -- continuation with gas available for call-  -> (Word64 -> EVM ())-  -> EVM ()-callChecks this xGas xContext xTo xValue xInOffset xInSize xOutOffset xOutSize xs continue = do-  vm <- get-  let fees = vm._block._schedule-  accessMemoryRange xInOffset xInSize $-    accessMemoryRange xOutOffset xOutSize $ do-      availableGas <- use (state . gas)-      let recipientExists = accountExists xContext vm-      (cost, gas') <- costOfCall fees recipientExists xValue availableGas xGas xTo-      burn (cost - gas') $ do-        if xValue > num this._balance-        then do-          assign (state . stack) (Lit 0 : xs)-          assign (state . returndata) mempty-          pushTrace $ ErrorTrace $ BalanceTooLow xValue this._balance-          next-        else if length vm._frames >= 1024-             then do-               assign (state . stack) (Lit 0 : xs)-               assign (state . returndata) mempty-               pushTrace $ ErrorTrace CallDepthLimitReached-               next-             else continue gas'--precompiledContract-  :: (?op :: Word8)-  => Contract-  -> Word64-  -> Addr-  -> Addr-  -> W256-  -> W256 -> W256 -> W256 -> W256-  -> [Expr EWord]-  -> EVM ()-precompiledContract this xGas precompileAddr recipient xValue inOffset inSize outOffset outSize xs =-  callChecks this xGas recipient precompileAddr xValue inOffset inSize outOffset outSize xs $ \gas' ->-  do-    executePrecompile precompileAddr gas' inOffset inSize outOffset outSize xs-    self <- use (state . contract)-    stk <- use (state . stack)-    pc' <- use (state . pc)-    result' <- use result-    case result' of-      Nothing -> case stk of-        (x:_) -> case maybeLitWord x of-          Just 0 ->-            return ()-          Just 1 ->-            fetchAccount recipient $ \_ -> do-              transfer self recipient xValue-              touchAccount self-              touchAccount recipient-          _ -> vmError $ UnexpectedSymbolicArg pc' "unexpected return value from precompile" [x]-        _ -> underrun-      _ -> pure ()--executePrecompile-  :: (?op :: Word8)-  => Addr-  -> Word64 -> W256 -> W256 -> W256 -> W256 -> [Expr EWord]-  -> EVM ()-executePrecompile preCompileAddr gasCap inOffset inSize outOffset outSize xs  = do-  vm <- get-  let input = readMemory (Lit inOffset) (Lit inSize) vm-      fees = vm._block._schedule-      cost = costOfPrecompile fees preCompileAddr input-      notImplemented = error $ "precompile at address " <> show preCompileAddr <> " not yet implemented"-      precompileFail = burn (gasCap - cost) $ do-                         assign (state . stack) (Lit 0 : xs)-                         pushTrace $ ErrorTrace PrecompileFailure-                         next-  if cost > gasCap then-    burn gasCap $ do-      assign (state . stack) (Lit 0 : xs)-      next-  else-    burn cost $-      case preCompileAddr of-        -- ECRECOVER-        0x1 ->-          -- TODO: support symbolic variant-          forceConcreteBuf input "ECRECOVER" $ \input' -> do-            case EVM.Precompiled.execute 0x1 (truncpadlit 128 input') 32 of-              Nothing -> do-                -- return no output for invalid signature-                assign (state . stack) (Lit 1 : xs)-                assign (state . returndata) mempty-                next-              Just output -> do-                assign (state . stack) (Lit 1 : xs)-                assign (state . returndata) (ConcreteBuf output)-                copyBytesToMemory (ConcreteBuf output) (Lit outSize) (Lit 0) (Lit outOffset)-                next--        -- SHA2-256-        0x2 -> forceConcreteBuf input "SHA2-256" $ \input' -> do-          let-            hash = sha256Buf input'-            sha256Buf x = ConcreteBuf $ BA.convert (Crypto.hash x :: Digest SHA256)-          assign (state . stack) (Lit 1 : xs)-          assign (state . returndata) hash-          copyBytesToMemory hash (Lit outSize) (Lit 0) (Lit outOffset)-          next--        -- RIPEMD-160-        0x3 ->-         -- TODO: support symbolic variant-         forceConcreteBuf input "RIPEMD160" $ \input' ->--          let-            padding = BS.pack $ replicate 12 0-            hash' = BA.convert (Crypto.hash input' :: Digest RIPEMD160)-            hash  = ConcreteBuf $ padding <> hash'-          in do-            assign (state . stack) (Lit 1 : xs)-            assign (state . returndata) hash-            copyBytesToMemory hash (Lit outSize) (Lit 0) (Lit outOffset)-            next--        -- IDENTITY-        0x4 -> do-            assign (state . stack) (Lit 1 : xs)-            assign (state . returndata) input-            copyCallBytesToMemory input (Lit outSize) (Lit 0) (Lit outOffset)-            next--        -- MODEXP-        0x5 ->-         -- TODO: support symbolic variant-         forceConcreteBuf input "MODEXP" $ \input' ->--          let-            (lenb, lene, lenm) = parseModexpLength input'--            output = ConcreteBuf $-              if isZero (96 + lenb + lene) lenm input'-              then truncpadlit (num lenm) (asBE (0 :: Int))-              else-                let-                  b = asInteger $ lazySlice 96 lenb input'-                  e = asInteger $ lazySlice (96 + lenb) lene input'-                  m = asInteger $ lazySlice (96 + lenb + lene) lenm input'-                in-                  padLeft (num lenm) (asBE (expFast b e m))-          in do-            assign (state . stack) (Lit 1 : xs)-            assign (state . returndata) output-            copyBytesToMemory output (Lit outSize) (Lit 0) (Lit outOffset)-            next--        -- ECADD-        0x6 ->-         -- TODO: support symbolic variant-         forceConcreteBuf input "ECADD" $ \input' ->-           case EVM.Precompiled.execute 0x6 (truncpadlit 128 input') 64 of-          Nothing -> precompileFail-          Just output -> do-            let truncpaddedOutput = ConcreteBuf $ truncpadlit 64 output-            assign (state . stack) (Lit 1 : xs)-            assign (state . returndata) truncpaddedOutput-            copyBytesToMemory truncpaddedOutput (Lit outSize) (Lit 0) (Lit outOffset)-            next--        -- ECMUL-        0x7 ->-         -- TODO: support symbolic variant-         forceConcreteBuf input "ECMUL" $ \input' ->--          case EVM.Precompiled.execute 0x7 (truncpadlit 96 input') 64 of-          Nothing -> precompileFail-          Just output -> do-            let truncpaddedOutput = ConcreteBuf $ truncpadlit 64 output-            assign (state . stack) (Lit 1 : xs)-            assign (state . returndata) truncpaddedOutput-            copyBytesToMemory truncpaddedOutput (Lit outSize) (Lit 0) (Lit outOffset)-            next--        -- ECPAIRING-        0x8 ->-         -- TODO: support symbolic variant-         forceConcreteBuf input "ECPAIR" $ \input' ->--          case EVM.Precompiled.execute 0x8 input' 32 of-          Nothing -> precompileFail-          Just output -> do-            let truncpaddedOutput = ConcreteBuf $ truncpadlit 32 output-            assign (state . stack) (Lit 1 : xs)-            assign (state . returndata) truncpaddedOutput-            copyBytesToMemory truncpaddedOutput (Lit outSize) (Lit 0) (Lit outOffset)-            next--        -- BLAKE2-        0x9 ->-         -- TODO: support symbolic variant-         forceConcreteBuf input "BLAKE2" $ \input' -> do--          case (BS.length input', 1 >= BS.last input') of-            (213, True) -> case EVM.Precompiled.execute 0x9 input' 64 of-              Just output -> do-                let truncpaddedOutput = ConcreteBuf $ truncpadlit 64 output-                assign (state . stack) (Lit 1 : xs)-                assign (state . returndata) truncpaddedOutput-                copyBytesToMemory truncpaddedOutput (Lit outSize) (Lit 0) (Lit outOffset)-                next-              Nothing -> precompileFail-            _ -> precompileFail---        _   -> notImplemented--truncpadlit :: Int -> ByteString -> ByteString-truncpadlit n xs = if m > n then BS.take n xs-                   else BS.append xs (BS.replicate (n - m) 0)-  where m = BS.length xs--lazySlice :: W256 -> W256 -> ByteString -> LS.ByteString-lazySlice offset size bs =-  let bs' = LS.take (num size) (LS.drop (num offset) (fromStrict bs))-  in bs' <> LS.replicate ((num size) - LS.length bs') 0--parseModexpLength :: ByteString -> (W256, W256, W256)-parseModexpLength input =-  let lenb = word $ LS.toStrict $ lazySlice  0 32 input-      lene = word $ LS.toStrict $ lazySlice 32 64 input-      lenm = word $ LS.toStrict $ lazySlice 64 96 input-  in (lenb, lene, lenm)----- checks if a range of ByteString bs starting at offset and length size is all zeros.-isZero :: W256 -> W256 -> ByteString -> Bool-isZero offset size bs =-  LS.all (== 0) $-    LS.take (num size) $-      LS.drop (num offset) $-        fromStrict bs--asInteger :: LS.ByteString -> Integer-asInteger xs = if xs == mempty then 0-  else 256 * asInteger (LS.init xs)-      + num (LS.last xs)---- * Opcode helper actions--noop :: Monad m => m ()-noop = pure ()--pushTo :: MonadState s m => ASetter s s [a] [a] -> a -> m ()-pushTo f x = f %= (x :)--pushToSequence :: MonadState s m => ASetter s s (Seq a) (Seq a) -> a -> m ()-pushToSequence f x = f %= (Seq.|> x)--getCodeLocation :: VM -> CodeLocation-getCodeLocation vm = (vm._state._contract, vm._state._pc)--branch :: CodeLocation -> Expr EWord -> (Bool -> EVM ()) -> EVM ()-branch loc cond continue = do-  pathconds <- use constraints-  assign result . Just . VMFailure . Query $ PleaseAskSMT cond pathconds choosePath-  where-     choosePath (Case v) = do assign result Nothing-                              pushTo constraints $ if v then (cond ./= (Lit 0)) else (cond .== (Lit 0))-                              iteration <- use (iterations . at loc . non 0)-                              assign (cache . path . at (loc, iteration)) (Just v)-                              assign (iterations . at loc) (Just (iteration + 1))-                              continue v-     -- Both paths are possible; we ask for more input-     choosePath Unknown = assign result . Just . VMFailure . Choose . PleaseChoosePath cond $ choosePath . Case-     -- None of the paths are possible; fail this branch-     choosePath Inconsistent = vmError DeadPath----- | Construct RPC Query and halt execution until resolved-fetchAccount :: Addr -> (Contract -> EVM ()) -> EVM ()-fetchAccount addr continue =-  use (env . contracts . at addr) >>= \case-    Just c -> continue c-    Nothing ->-      use (cache . fetchedContracts . at addr) >>= \case-        Just c -> do-          assign (env . contracts . at addr) (Just c)-          continue c-        Nothing -> do-          assign result . Just . VMFailure $ Query $-            PleaseFetchContract addr-              (\c -> do assign (cache . fetchedContracts . at addr) (Just c)-                        assign (env . contracts . at addr) (Just c)-                        assign result Nothing-                        continue c)--accessStorage-  :: Addr                   -- ^ Contract address-  -> Expr EWord             -- ^ Storage slot key-  -> (Expr EWord -> EVM ()) -- ^ Continuation-  -> EVM ()-accessStorage addr slot continue = do-  store <- use (env . storage)-  use (env . contracts . at addr) >>= \case-    Just c ->-      case readStorage (litAddr addr) slot store of-        -- Notice that if storage is symbolic, we always continue straight away-        Just x ->-          continue x-        Nothing ->-          if c._external then-            forceConcrete slot "cannot read symbolic slots via RPC" $ \litSlot -> do-              -- check if the slot is cached-              cachedStore <- use (cache . fetchedStorage)-              case Map.lookup (num addr) cachedStore >>= Map.lookup litSlot of-                Nothing -> mkQuery litSlot-                Just val -> continue (Lit val)-          else do-            modifying (env . storage) (writeStorage (litAddr addr) slot (Lit 0))-            continue $ Lit 0-    Nothing ->-      fetchAccount addr $ \_ ->-        accessStorage addr slot continue-  where-      mkQuery s = assign result . Just . VMFailure . Query $-                    PleaseFetchSlot addr s-                      (\x -> do-                          modifying (cache . fetchedStorage . ix (num addr)) (Map.insert s x)-                          modifying (env . storage) (writeStorage (litAddr addr) slot (Lit x))-                          assign result Nothing-                          continue (Lit x))--accountExists :: Addr -> VM -> Bool-accountExists addr vm =-  case Map.lookup addr vm._env._contracts of-    Just c -> not (accountEmpty c)-    Nothing -> False---- EIP 161-accountEmpty :: Contract -> Bool-accountEmpty c =-  case c._contractcode of-    RuntimeCode (ConcreteRuntimeCode "") -> True-    RuntimeCode (SymbolicRuntimeCode b) -> null b-    _ -> False-  && c._nonce == 0-  && c._balance  == 0---- * How to finalize a transaction-finalize :: EVM ()-finalize = do-  let-    revertContracts  = use (tx . txReversion) >>= assign (env . contracts)-    revertSubstate   = assign (tx . substate) (SubState mempty mempty mempty mempty mempty)--  use result >>= \case-    Nothing ->-      error "Finalising an unfinished tx."-    Just (VMFailure (EVM.Revert _)) -> do-      revertContracts-      revertSubstate-    Just (VMFailure _) -> do-      -- burn remaining gas-      assign (state . gas) 0-      revertContracts-      revertSubstate-    Just (VMSuccess output) -> do-      -- deposit the code from a creation tx-      pc' <- use (state . pc)-      creation <- use (tx . isCreate)-      createe  <- use (state . contract)-      createeExists <- (Map.member createe) <$> use (env . contracts)-      let onContractCode contractCode =-            when (creation && createeExists) $ replaceCode createe contractCode-      case output of-        ConcreteBuf bs ->-          onContractCode $ RuntimeCode (ConcreteRuntimeCode bs)-        _ ->-          case Expr.toList output of-            Nothing ->-              vmError $ UnexpectedSymbolicArg pc' "runtime code cannot have an abstract lentgh" [output]-            Just ops ->-              onContractCode $ RuntimeCode (SymbolicRuntimeCode ops)--  -- compute and pay the refund to the caller and the-  -- corresponding payment to the miner-  txOrigin     <- use (tx . origin)-  sumRefunds   <- (sum . (snd <$>)) <$> (use (tx . substate . refunds))-  miner        <- use (block . coinbase)-  blockReward  <- num . (.r_block) <$> (use (block . schedule))-  gasPrice     <- use (tx . gasprice)-  priorityFee  <- use (tx . txPriorityFee)-  gasLimit     <- use (tx . txgaslimit)-  gasRemaining <- use (state . gas)--  let-    gasUsed      = gasLimit - gasRemaining-    cappedRefund = min (quot gasUsed 5) (num sumRefunds)-    originPay    = (num $ gasRemaining + cappedRefund) * gasPrice--    minerPay     = priorityFee * (num gasUsed)--  modifying (env . contracts)-     (Map.adjust (over balance (+ originPay)) txOrigin)-  modifying (env . contracts)-     (Map.adjust (over balance (+ minerPay)) miner)-  touchAccount miner--  -- pay out the block reward, recreating the miner if necessary-  preuse (env . contracts . ix miner) >>= \case-    Nothing -> modifying (env . contracts)-      (Map.insert miner (initialContract (EVM.RuntimeCode (ConcreteRuntimeCode ""))))-    Just _  -> noop-  modifying (env . contracts)-    (Map.adjust (over balance (+ blockReward)) miner)--  -- perform state trie clearing (EIP 161), of selfdestructs-  -- and touched accounts. addresses are cleared if they have-  --    a) selfdestructed, or-  --    b) been touched and-  --    c) are empty.-  -- (see Yellow Paper "Accrued Substate")-  ---  -- remove any destructed addresses-  destroyedAddresses <- use (tx . substate . selfdestructs)-  modifying (env . contracts)-    (Map.filterWithKey (\k _ -> (k `notElem` destroyedAddresses)))-  -- then, clear any remaining empty and touched addresses-  touchedAddresses <- use (tx . substate . touchedAccounts)-  modifying (env . contracts)-    (Map.filterWithKey-      (\k a -> not ((k `elem` touchedAddresses) && accountEmpty a)))---- | Loads the selected contract as the current contract to execute-loadContract :: Addr -> EVM ()-loadContract target =-  preuse (env . contracts . ix target . contractcode) >>=-    \case-      Nothing ->-        error "Call target doesn't exist"-      Just targetCode -> do-        assign (state . contract) target-        assign (state . code)     targetCode-        assign (state . codeContract) target--limitStack :: Int -> EVM () -> EVM ()-limitStack n continue = do-  stk <- use (state . stack)-  if length stk + n > 1024-    then vmError EVM.StackLimitExceeded-    else continue--notStatic :: EVM () -> EVM ()-notStatic continue = do-  bad <- use (state . static)-  if bad-    then vmError StateChangeWhileStatic-    else continue---- | Burn gas, failing if insufficient gas is available-burn :: Word64 -> EVM () -> EVM ()-burn n continue = do-  available <- use (state . gas)-  if n <= available-    then do-      state . gas -= n-      burned += n-      continue-    else-      vmError (OutOfGas available n)--forceConcrete :: Expr EWord -> String -> (W256 -> EVM ()) -> EVM ()-forceConcrete n msg continue = case maybeLitWord n of-  Nothing -> do-    vm <- get-    vmError $ UnexpectedSymbolicArg vm._state._pc msg [n]-  Just c -> continue c--forceConcrete2 :: (Expr EWord, Expr EWord) -> String -> ((W256, W256) -> EVM ()) -> EVM ()-forceConcrete2 (n,m) msg continue = case (maybeLitWord n, maybeLitWord m) of-  (Just c, Just d) -> continue (c, d)-  _ -> do-    vm <- get-    vmError $ UnexpectedSymbolicArg vm._state._pc msg [n, m]--forceConcrete3 :: (Expr EWord, Expr EWord, Expr EWord) -> String -> ((W256, W256, W256) -> EVM ()) -> EVM ()-forceConcrete3 (k,n,m) msg continue = case (maybeLitWord k, maybeLitWord n, maybeLitWord m) of-  (Just c, Just d, Just f) -> continue (c, d, f)-  _ -> do-    vm <- get-    vmError $ UnexpectedSymbolicArg vm._state._pc msg [k, n, m]--forceConcrete4 :: (Expr EWord, Expr EWord, Expr EWord, Expr EWord) -> String -> ((W256, W256, W256, W256) -> EVM ()) -> EVM ()-forceConcrete4 (k,l,n,m) msg continue = case (maybeLitWord k, maybeLitWord l, maybeLitWord n, maybeLitWord m) of-  (Just b, Just c, Just d, Just f) -> continue (b, c, d, f)-  _ -> do-    vm <- get-    vmError $ UnexpectedSymbolicArg vm._state._pc msg [k, l, n, m]--forceConcrete5 :: (Expr EWord, Expr EWord, Expr EWord, Expr EWord, Expr EWord) -> String -> ((W256, W256, W256, W256, W256) -> EVM ()) -> EVM ()-forceConcrete5 (k,l,m,n,o) msg continue = case (maybeLitWord k, maybeLitWord l, maybeLitWord m, maybeLitWord n, maybeLitWord o) of-  (Just a, Just b, Just c, Just d, Just e) -> continue (a, b, c, d, e)-  _ -> do-    vm <- get-    vmError $ UnexpectedSymbolicArg vm._state._pc msg [k, l, m, n, o]--forceConcrete6 :: (Expr EWord, Expr EWord, Expr EWord, Expr EWord, Expr EWord, Expr EWord) -> String -> ((W256, W256, W256, W256, W256, W256) -> EVM ()) -> EVM ()-forceConcrete6 (k,l,m,n,o,p) msg continue = case (maybeLitWord k, maybeLitWord l, maybeLitWord m, maybeLitWord n, maybeLitWord o, maybeLitWord p) of-  (Just a, Just b, Just c, Just d, Just e, Just f) -> continue (a, b, c, d, e, f)-  _ -> do-    vm <- get-    vmError $ UnexpectedSymbolicArg vm._state._pc msg [k, l, m, n, o, p]--forceConcreteBuf :: Expr Buf -> String -> (ByteString -> EVM ()) -> EVM ()-forceConcreteBuf (ConcreteBuf b) _ continue = continue b-forceConcreteBuf b msg _ = do-    vm <- get-    vmError $ UnexpectedSymbolicArg vm._state._pc msg [b]---- * Substate manipulation-refund :: Word64 -> EVM ()-refund n = do-  self <- use (state . contract)-  pushTo (tx . substate . refunds) (self, n)--unRefund :: Word64 -> EVM ()-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 :: Addr -> EVM()-touchAccount = pushTo ((tx . substate) . touchedAccounts)--selfdestruct :: Addr -> EVM()-selfdestruct = pushTo ((tx . substate) . selfdestructs)--accessAndBurn :: Addr -> EVM () -> EVM ()-accessAndBurn x cont = do-  FeeSchedule {..} <- use ( block . schedule )-  acc <- accessAccountForGas x-  let cost = if acc then g_warm_storage_read else g_cold_account_access-  burn cost cont---- | 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 :: Addr -> EVM Bool-accessAccountForGas addr = do-  accessedAddrs <- use (tx . substate . accessedAddresses)-  let accessed = member addr accessedAddrs-  assign (tx . substate . accessedAddresses) (insert addr accessedAddrs)-  return accessed---- | 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 :: Addr -> Expr EWord -> EVM Bool-accessStorageForGas addr key = do-  accessedStrkeys <- use (tx . substate . accessedStorageKeys)-  case maybeLitWord key of-    Just litword -> do-      let accessed = member (addr, litword) accessedStrkeys-      assign (tx . substate . accessedStorageKeys) (insert (addr, litword) accessedStrkeys)-      return accessed-    _ -> return False---- * Cheat codes---- The cheat code is 7109709ecfa91a80626ff3989d68f67f5b1dd12d.--- Call this address using one of the cheatActions below to do--- special things, e.g. changing the block timestamp. Beware that--- these are necessarily hevm specific.-cheatCode :: Addr-cheatCode = num (keccak' "hevm cheat code")--cheat-  :: (?op :: Word8)-  => (W256, W256) -> (W256, W256)-  -> EVM ()-cheat (inOffset, inSize) (outOffset, outSize) = do-  mem <- use (state . memory)-  vm <- get-  let-    abi = readBytes 4 (Lit inOffset) mem-    input = readMemory (Lit $ inOffset + 4) (Lit $ inSize - 4) vm-  case maybeLitWord abi of-    Nothing -> vmError $ UnexpectedSymbolicArg vm._state._pc "symbolic cheatcode selector" [abi]-    Just (fromIntegral -> abi') ->-      case Map.lookup abi' cheatActions of-        Nothing ->-          vmError (BadCheatCode (Just abi'))-        Just action -> do-            action (Lit outOffset) (Lit outSize) input-            next-            push 1--type CheatAction = Expr EWord -> Expr EWord -> Expr Buf -> EVM ()--cheatActions :: Map Word32 CheatAction-cheatActions =-  Map.fromList-    [ action "ffi(string[])" $-        \sig outOffset outSize input -> do-          vm <- get-          if vm._allowFFI then-            case decodeBuf [AbiArrayDynamicType AbiStringType] input of-              CAbi valsArr -> case valsArr of-                [AbiArrayDynamic AbiStringType strsV] ->-                  let-                    cmd = fmap-                            (\case-                              (AbiString a) -> unpack $ decodeUtf8 a-                              _ -> "")-                            (V.toList strsV)-                    cont bs = do-                      let encoded = ConcreteBuf bs-                      assign (state . returndata) encoded-                      copyBytesToMemory encoded outSize (Lit 0) outOffset-                      assign result Nothing-                  in assign result (Just . VMFailure . Query $ (PleaseDoFFI cmd cont))-                _ -> vmError (BadCheatCode sig)-              _ -> vmError (BadCheatCode sig)-          else-            let msg = encodeUtf8 "ffi disabled: run again with --ffi if you want to allow tests to call external scripts"-            in vmError . EVM.Revert . ConcreteBuf $-              abiMethod "Error(string)" (AbiTuple . V.fromList $ [AbiString msg]),--      action "warp(uint256)" $-        \sig _ _ input -> case decodeStaticArgs 0 1 input of-          [x]  -> assign (block . timestamp) x-          _ -> vmError (BadCheatCode sig),--      action "roll(uint256)" $-        \sig _ _ input -> case decodeStaticArgs 0 1 input of-          [x] -> forceConcrete x "cannot roll to a symbolic block number" (assign (block . number))-          _ -> vmError (BadCheatCode sig),--      action "store(address,bytes32,bytes32)" $-        \sig _ _ input -> case decodeStaticArgs 0 3 input of-          [a, slot, new] ->-            forceConcrete a "cannot store at a symbolic address" $ \(num -> a') ->-              fetchAccount a' $ \_ -> do-                modifying (env . storage) (writeStorage (litAddr a') slot new)-          _ -> vmError (BadCheatCode sig),--      action "load(address,bytes32)" $-        \sig outOffset _ input -> case decodeStaticArgs 0 2 input of-          [a, slot] ->-            forceConcrete a "cannot load from a symbolic address" $ \(num -> a') ->-              accessStorage a' slot $ \res -> do-                assign (state . returndata . word256At (Lit 0)) res-                assign (state . memory . word256At outOffset) res-          _ -> vmError (BadCheatCode sig),--      action "sign(uint256,bytes32)" $-        \sig outOffset _ input -> case decodeStaticArgs 0 2 input of-          [sk, hash] ->-            forceConcrete2 (sk, hash) "cannot sign symbolic data" $ \(sk', hash') -> do-              let (v,r,s) = EVM.Sign.sign hash' (toInteger sk')-                  encoded = encodeAbiValue $-                    AbiTuple (RegularVector.fromList-                      [ AbiUInt 8 $ num v-                      , AbiBytes 32 (word256Bytes r)-                      , AbiBytes 32 (word256Bytes s)-                      ])-              assign (state . returndata) (ConcreteBuf encoded)-              copyBytesToMemory (ConcreteBuf encoded) (Lit . num . BS.length $ encoded) (Lit 0) outOffset-          _ -> vmError (BadCheatCode sig),--      action "addr(uint256)" $-        \sig outOffset _ input -> case decodeStaticArgs 0 1 input of-          [sk] -> forceConcrete sk "cannot derive address for a symbolic key" $ \sk' -> do-            let a = EVM.Sign.deriveAddr $ num sk'-            case a of-              Nothing -> vmError (BadCheatCode sig)-              Just address -> do-                let expAddr = litAddr address-                assign (state . returndata . word256At (Lit 0)) expAddr-                assign (state . memory . word256At outOffset) expAddr-          _ -> vmError (BadCheatCode sig),--      action "prank(address)" $-        \sig _ _ input -> case decodeStaticArgs 0 1 input of-          [addr]  -> assign overrideCaller (Just addr)-          _ -> vmError (BadCheatCode sig)--    ]-  where-    action s f = (abiKeccak s, f (Just $ abiKeccak s))---- | We don't wanna introduce the machinery needed to sign with a random nonce,--- so we just use the same nonce every time (420). This is obviusly very--- insecure, but fine for testing purposes.-ethsign :: PrivateKey -> Digest Crypto.Keccak_256 -> Signature-ethsign sk digest = go 420-  where-    go k = case signDigestWith k sk digest of-       Nothing  -> go (k + 1)-       Just sig -> sig---- * General call implementation ("delegateCall")--- note that the continuation is ignored in the precompile case-delegateCall-  :: (?op :: Word8)-  => Contract -> Word64 -> Expr EWord -> Expr EWord -> W256 -> W256 -> W256 -> W256 -> W256-  -> [Expr EWord]-  -> (Addr -> EVM ())-  -> EVM ()-delegateCall this gasGiven xTo xContext xValue xInOffset xInSize xOutOffset xOutSize xs continue =-  forceConcrete2 (xTo, xContext) "cannot delegateCall with symbolic target or context" $-    \((num -> xTo'), (num -> xContext')) ->-      if xTo' > 0 && xTo' <= 9-      then precompiledContract this gasGiven xTo' xContext' xValue xInOffset xInSize xOutOffset xOutSize xs-      else if xTo' == cheatCode then-        do-          assign (state . stack) xs-          cheat (xInOffset, xInSize) (xOutOffset, xOutSize)-      else-        callChecks this gasGiven xContext' xTo' xValue xInOffset xInSize xOutOffset xOutSize xs $-        \xGas -> do-          vm0 <- get-          fetchAccount xTo' $ \target ->-                burn xGas $ do-                  let newContext = CallContext-                                    { callContextTarget    = xTo'-                                    , callContextContext   = xContext'-                                    , callContextOffset    = xOutOffset-                                    , callContextSize      = xOutSize-                                    , callContextCodehash  = target._codehash-                                    , callContextReversion = (vm0._env._contracts, vm0._env._storage)-                                    , callContextSubState  = vm0._tx._substate-                                    , callContextAbi =-                                        if xInSize >= 4-                                        then case unlit $ readBytes 4 (Lit xInOffset) vm0._state._memory-                                             of Nothing -> Nothing-                                                Just abi -> Just $ num abi-                                        else Nothing-                                    , callContextData = (readMemory (Lit xInOffset) (Lit xInSize) vm0)-                                    }--                  pushTrace (FrameTrace newContext)-                  next-                  vm1 <- get--                  pushTo frames $ Frame-                    { _frameState = vm1._state { _stack = xs }-                    , _frameContext = newContext-                    }--                  let clearInitCode = \case-                        (InitCode _ _) -> InitCode mempty mempty-                        a -> a--                  zoom state $ do-                    assign gas (num xGas)-                    assign pc 0-                    assign code (clearInitCode target._contractcode)-                    assign codeContract xTo'-                    assign stack mempty-                    assign memory mempty-                    assign memorySize 0-                    assign returndata mempty-                    assign calldata (copySlice (Lit xInOffset) (Lit 0) (Lit xInSize) vm0._state._memory mempty)--                  continue xTo'---- -- * Contract creation---- EIP 684-collision :: Maybe Contract -> Bool-collision c' = case c' of-  Just c -> c._nonce /= 0 || case c._contractcode of-    RuntimeCode (ConcreteRuntimeCode "") -> False-    RuntimeCode (SymbolicRuntimeCode b) -> not $ null b-    _ -> True-  Nothing -> False--create :: (?op :: Word8)-  => Addr -> Contract-  -> Word64 -> W256 -> [Expr EWord] -> Addr -> Expr Buf -> EVM ()-create self this xGas' xValue xs newAddr initCode = do-  vm0 <- get-  let xGas = num xGas'-  if this._nonce == num (maxBound :: Word64)-  then do-    assign (state . stack) (Lit 0 : xs)-    assign (state . returndata) mempty-    pushTrace $ ErrorTrace NonceOverflow-    next-  else if xValue > this._balance-  then do-    assign (state . stack) (Lit 0 : xs)-    assign (state . returndata) mempty-    pushTrace $ ErrorTrace $ BalanceTooLow xValue this._balance-    next-  else if length vm0._frames >= 1024-  then do-    assign (state . stack) (Lit 0 : xs)-    assign (state . returndata) mempty-    pushTrace $ ErrorTrace CallDepthLimitReached-    next-  else if collision $ Map.lookup newAddr vm0._env._contracts-  then burn xGas $ do-    assign (state . stack) (Lit 0 : xs)-    assign (state . returndata) mempty-    modifying (env . contracts . ix self . nonce) succ-    next-  else burn xGas $ do-    touchAccount self-    touchAccount newAddr-    let-    -- unfortunately we have to apply some (pretty hacky)-    -- heuristics here to parse the unstructured buffer read-    -- from memory into a code and data section-    -- TODO: comment explaining whats going on here-    let contract' = do-          prefixLen <- Expr.concPrefix initCode-          prefix <- Expr.toList $ Expr.take (num prefixLen) initCode-          let sym = Expr.drop (num prefixLen) initCode-          conc <- mapM unlitByte prefix-          pure $ InitCode (BS.pack $ V.toList conc) sym-    case contract' of-      Nothing ->-        vmError $ UnexpectedSymbolicArg vm0._state._pc "initcode must have a concrete prefix" []-      Just c -> do-        let-          newContract = initialContract c-          newContext  =-            CreationContext { creationContextAddress   = newAddr-                            , creationContextCodehash  = newContract._codehash-                            , creationContextReversion = vm0._env._contracts-                            , creationContextSubstate  = vm0._tx._substate-                            }--        zoom (env . contracts) $ do-          oldAcc <- use (at newAddr)-          let oldBal = maybe 0 (._balance) oldAcc--          assign (at newAddr) (Just (newContract & balance .~ oldBal))-          modifying (ix self . nonce) succ--        let resetStorage = \case-              ConcreteStore s -> ConcreteStore (Map.delete (num newAddr) s)-              AbstractStore -> AbstractStore-              EmptyStore -> EmptyStore-              SStore {} -> error "trying to reset symbolic storage with writes in create"-              GVar _  -> error "unexpected global variable"--        modifying (env . storage) resetStorage-        modifying (env . origStorage) (Map.delete (num newAddr))--        transfer self newAddr xValue--        pushTrace (FrameTrace newContext)-        next-        vm1 <- get-        pushTo frames $ Frame-          { _frameContext = newContext-          , _frameState   = vm1._state { _stack = xs }-          }--        assign state $-          blankState-            & set contract   newAddr-            & set codeContract newAddr-            & set code       c-            & set callvalue  (Lit xValue)-            & set caller     (litAddr self)-            & set gas        xGas'---- | Replace a contract's code, like when CREATE returns--- from the constructor code.-replaceCode :: Addr -> ContractCode -> EVM ()-replaceCode target newCode =-  zoom (env . contracts . at target) $-    get >>= \case-      Just now -> case now._contractcode of-        InitCode _ _ ->-          put . Just $-            (initialContract newCode)-              { _balance = now._balance-              , _nonce = now._nonce-              }-        RuntimeCode _ ->-          error ("internal error: can't replace code of deployed contract " <> show target)-      Nothing ->-        error "internal error: can't replace code of nonexistent contract"--replaceCodeOfSelf :: ContractCode -> EVM ()-replaceCodeOfSelf newCode = do-  vm <- get-  replaceCode vm._state._contract newCode--resetState :: EVM ()-resetState = do-  assign result Nothing-  assign frames []-  assign state  blankState----- * VM error implementation--vmError :: Error -> EVM ()-vmError e = finishFrame (FrameErrored e)--underrun :: EVM ()-underrun = vmError EVM.StackUnderrun---- | A stack frame can be popped in three ways.-data FrameResult-  = FrameReturned (Expr Buf) -- ^ STOP, RETURN, or no more code-  | FrameReverted (Expr Buf) -- ^ REVERT-  | FrameErrored Error -- ^ Any other error-  deriving Show---- | This function defines how to pop the current stack frame in either of--- the ways specified by 'FrameResult'.------ 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 :: FrameResult -> EVM ()-finishFrame how = do-  oldVm <- get--  case oldVm._frames of-    -- Is the current frame the only one?-    [] -> do-      case how of-          FrameReturned output -> assign result . Just $ VMSuccess output-          FrameReverted buffer -> assign result . Just $ VMFailure (EVM.Revert buffer)-          FrameErrored e       -> assign result . Just $ VMFailure e-      finalize--    -- Are there some remaining frames?-    nextFrame : remainingFrames -> do--      -- Insert a debug trace.-      insertTrace $-        case how of-          FrameErrored e ->-            ErrorTrace e-          FrameReverted e ->-            ErrorTrace (EVM.Revert e)-          FrameReturned output ->-            ReturnTrace output nextFrame._frameContext-      -- Pop to the previous level of the debug trace stack.-      popTrace--      -- Pop the top frame.-      assign frames remainingFrames-      -- Install the state of the frame to which we shall return.-      assign state nextFrame._frameState--      -- When entering a call, the gas allowance is counted as burned-      -- in advance; this unburns the remainder and adds it to the-      -- parent frame.-      let remainingGas = oldVm._state._gas-          reclaimRemainingGasAllowance = do-            modifying burned (subtract remainingGas)-            modifying (state . gas) (+ remainingGas)--      -- Now dispatch on whether we were creating or calling,-      -- and whether we shall return, revert, or error (six cases).-      case nextFrame._frameContext of--        -- Were we calling?-        CallContext _ _ (Lit -> outOffset) (Lit -> outSize) _ _ _ reversion substate' -> do--          -- Excerpt K.1. from the yellow paper:-          -- K.1. Deletion of an Account Despite Out-of-gas.-          -- At block 2675119, in the transaction 0xcf416c536ec1a19ed1fb89e4ec7ffb3cf73aa413b3aa9b77d60e4fd81a4296ba,-          -- an account at address 0x03 was called and an out-of-gas occurred during the call.-          -- Against the equation (197), this added 0x03 in the set of touched addresses, and this transaction turned σ[0x03] into ∅.--          -- In other words, we special case address 0x03 and keep it in the set of touched accounts during revert-          touched <- use (tx . substate . touchedAccounts)--          let-            substate'' = over touchedAccounts (maybe id cons (find (3 ==) touched)) substate'-            (contractsReversion, storageReversion) = reversion-            revertContracts = assign (env . contracts) contractsReversion-            revertStorage = assign (env . storage) storageReversion-            revertSubstate  = assign (tx . substate) substate''--          case how of-            -- Case 1: Returning from a call?-            FrameReturned output -> do-              assign (state . returndata) output-              copyCallBytesToMemory output outSize (Lit 0) outOffset-              reclaimRemainingGasAllowance-              push 1--            -- Case 2: Reverting during a call?-            FrameReverted output -> do-              revertContracts-              revertStorage-              revertSubstate-              assign (state . returndata) output-              copyCallBytesToMemory output outSize (Lit 0) outOffset-              reclaimRemainingGasAllowance-              push 0--            -- Case 3: Error during a call?-            FrameErrored _ -> do-              revertContracts-              revertStorage-              revertSubstate-              assign (state . returndata) mempty-              push 0-        -- Or were we creating?-        CreationContext _ _ reversion substate' -> do-          creator <- use (state . contract)-          let-            createe = oldVm._state._contract-            revertContracts = assign (env . contracts) reversion'-            revertSubstate  = assign (tx . substate) substate'--            -- persist the nonce through the reversion-            reversion' = (Map.adjust (over nonce (+ 1)) creator) reversion--          case how of-            -- Case 4: Returning during a creation?-            FrameReturned output -> do-              let onContractCode contractCode = do-                    replaceCode createe contractCode-                    assign (state . returndata) mempty-                    reclaimRemainingGasAllowance-                    push (num createe)-              case output of-                ConcreteBuf bs ->-                  onContractCode $ RuntimeCode (ConcreteRuntimeCode bs)-                _ ->-                  case Expr.toList output of-                    Nothing -> vmError $-                      UnexpectedSymbolicArg-                        oldVm._state._pc-                        "runtime code cannot have an abstract length"-                        [output]-                    Just newCode -> do-                      onContractCode $ RuntimeCode (SymbolicRuntimeCode newCode)--            -- Case 5: Reverting during a creation?-            FrameReverted output -> do-              revertContracts-              revertSubstate-              assign (state . returndata) output-              reclaimRemainingGasAllowance-              push 0--            -- Case 6: Error during a creation?-            FrameErrored _ -> do-              revertContracts-              revertSubstate-              assign (state . returndata) mempty-              push 0----- * Memory helpers--accessUnboundedMemoryRange-  :: Word64-  -> Word64-  -> EVM ()-  -> EVM ()-accessUnboundedMemoryRange _ 0 continue = continue-accessUnboundedMemoryRange f l continue = do-  m0 <- num <$> use (state . memorySize)-  fees <- gets (._block._schedule)-  do-    let m1 = 32 * ceilDiv (max m0 (f + l)) 32-    burn (memoryCost fees m1 - memoryCost fees m0) $ do-      assign (state . memorySize) m1-      continue--accessMemoryRange-  :: W256-  -> W256-  -> EVM ()-  -> EVM ()-accessMemoryRange _ 0 continue = continue-accessMemoryRange f l continue =-  case (,) <$> toWord64 f <*> toWord64 l of-    Nothing -> vmError IllegalOverflow-    Just (f64, l64) ->-      if f64 + l64 < l64-        then vmError IllegalOverflow-        else accessUnboundedMemoryRange f64 l64 continue--accessMemoryWord-  :: W256 -> EVM () -> EVM ()-accessMemoryWord x = accessMemoryRange x 32--copyBytesToMemory-  :: Expr Buf -> Expr EWord -> Expr EWord -> Expr EWord -> EVM ()-copyBytesToMemory bs size xOffset yOffset =-  if size == (Lit 0) then noop-  else do-    mem <- use (state . memory)-    assign (state . memory) $-      copySlice xOffset yOffset size bs mem--copyCallBytesToMemory-  :: Expr Buf -> Expr EWord -> Expr EWord -> Expr EWord -> EVM ()-copyCallBytesToMemory bs size xOffset yOffset =-  if size == (Lit 0) then noop-  else do-    mem <- use (state . memory)-    assign (state . memory) $-      copySlice xOffset yOffset (Expr.min size (bufLength bs)) bs mem--readMemory :: Expr EWord -> Expr EWord -> VM -> Expr Buf-readMemory offset size vm = copySlice offset (Lit 0) size vm._state._memory mempty---- * Tracing--withTraceLocation :: TraceData -> EVM Trace-withTraceLocation x = do-  vm <- get-  let this = fromJust $ currentContract vm-  pure Trace-    { _traceData = x-    , _traceContract = this-    , _traceOpIx = fromMaybe 0 $ this._opIxMap Vector.!? vm._state._pc-    }--pushTrace :: TraceData -> EVM ()-pushTrace x = do-  trace <- withTraceLocation x-  modifying traces $-    \t -> Zipper.children $ Zipper.insert (Node trace []) t--insertTrace :: TraceData -> EVM ()-insertTrace x = do-  trace <- withTraceLocation x-  modifying traces $-    \t -> Zipper.nextSpace $ Zipper.insert (Node trace []) t--popTrace :: EVM ()-popTrace =-  modifying traces $-    \t -> case Zipper.parent t of-            Nothing -> error "internal error (trace root)"-            Just t' -> Zipper.nextSpace t'--zipperRootForest :: Zipper.TreePos Zipper.Empty a -> Forest a-zipperRootForest z =-  case Zipper.parent z of-    Nothing -> Zipper.toForest z-    Just z' -> zipperRootForest (Zipper.nextSpace z')--traceForest :: VM -> Forest Trace-traceForest vm = zipperRootForest vm._traces--traceTopLog :: [Expr Log] -> EVM ()-traceTopLog [] = noop-traceTopLog ((LogEntry addr bytes topics) : _) = do-  trace <- withTraceLocation (EventTrace addr bytes topics)-  modifying traces $-    \t -> Zipper.nextSpace (Zipper.insert (Node trace []) t)-traceTopLog ((GVar _) : _) = error "unexpected global variable"---- * Stack manipulation--push :: W256 -> EVM ()-push = pushSym . Lit--pushSym :: Expr EWord -> EVM ()-pushSym x = state . stack %= (x :)---stackOp1-  :: (?op :: Word8)-  => Word64-  -> ((Expr EWord) -> (Expr EWord))-  -> EVM ()-stackOp1 cost f =-  use (state . stack) >>= \case-    (x:xs) ->-      burn cost $ do-        next-        let !y = f x-        state . stack .= y : xs-    _ ->-      underrun--stackOp2-  :: (?op :: Word8)-  => Word64-  -> (((Expr EWord), (Expr EWord)) -> (Expr EWord))-  -> EVM ()-stackOp2 cost f =-  use (state . stack) >>= \case-    (x:y:xs) ->-      burn cost $ do-        next-        state . stack .= f (x, y) : xs-    _ ->-      underrun--stackOp3-  :: (?op :: Word8)-  => Word64-  -> (((Expr EWord), (Expr EWord), (Expr EWord)) -> (Expr EWord))-  -> EVM ()-stackOp3 cost f =-  use (state . stack) >>= \case-    (x:y:z:xs) ->-      burn cost $ do-      next-      state . stack .= f (x, y, z) : xs-    _ ->-      underrun---- * Bytecode data functions--checkJump :: Int -> [Expr EWord] -> EVM ()-checkJump x xs = do-  theCode <- use (state . code)-  self <- use (state . codeContract)-  theCodeOps <- use (env . contracts . ix self . codeOps)-  theOpIxMap <- use (env . contracts . ix self . opIxMap)-  let op = case theCode of-        InitCode ops _ -> BS.indexMaybe ops x-        RuntimeCode (ConcreteRuntimeCode ops) -> BS.indexMaybe ops x-        RuntimeCode (SymbolicRuntimeCode ops) -> ops V.!? x >>= unlitByte-  case op of-    Nothing -> vmError EVM.BadJumpDestination-    Just b ->-      if 0x5b == b && OpJumpdest == snd (theCodeOps RegularVector.! (theOpIxMap Vector.! num x))-         then do-           state . stack .= xs-           state . pc .= num x-         else-           vmError EVM.BadJumpDestination--opSize :: Word8 -> Int-opSize x | x >= 0x60 && x <= 0x7f = num x - 0x60 + 2-opSize _                          = 1----  i of the resulting vector contains the operation index for--- the program counter value i.  This is needed because source map--- entries are per operation, not per byte.-mkOpIxMap :: ContractCode -> Vector Int-mkOpIxMap (InitCode conc _)-  = Vector.create $ Vector.new (BS.length conc) >>= \v ->-      -- Loop over the byte string accumulating a vector-mutating action.-      -- This is somewhat obfuscated, but should be fast.-      let (_, _, _, m) = BS.foldl' (go v) (0 :: Word8, 0, 0, return ()) conc-      in m >> return v-      where-        -- concrete case-        go v (0, !i, !j, !m) x | x >= 0x60 && x <= 0x7f =-          {- Start of PUSH op. -} (x - 0x60 + 1, i + 1, j,     m >> Vector.write v i j)-        go v (1, !i, !j, !m) _ =-          {- End of PUSH op. -}   (0,            i + 1, j + 1, m >> Vector.write v i j)-        go v (0, !i, !j, !m) _ =-          {- Other op. -}         (0,            i + 1, j + 1, m >> Vector.write v i j)-        go v (n, !i, !j, !m) _ =-          {- PUSH data. -}        (n - 1,        i + 1, j,     m >> Vector.write v i j)--mkOpIxMap (RuntimeCode (ConcreteRuntimeCode ops)) =-  mkOpIxMap (InitCode ops mempty) -- a bit hacky--mkOpIxMap (RuntimeCode (SymbolicRuntimeCode ops))-  = Vector.create $ Vector.new (length ops) >>= \v ->-      let (_, _, _, m) = foldl (go v) (0, 0, 0, return ()) (stripBytecodeMetadataSym $ V.toList ops)-      in m >> return v-      where-        go v (0, !i, !j, !m) x = case unlitByte x of-          Just x' -> if x' >= 0x60 && x' <= 0x7f-            -- start of PUSH op ---                     then (x' - 0x60 + 1, i + 1, j,     m >> Vector.write v i j)-            -- other data ---                     else (0,             i + 1, j + 1, m >> Vector.write v i j)-          _ -> error $ "cannot analyze symbolic code:\nx: " <> show x <> " i: " <> show i <> " j: " <> show j--        go v (1, !i, !j, !m) _ =-          {- End of PUSH op. -}   (0,            i + 1, j + 1, m >> Vector.write v i j)-        go v (n, !i, !j, !m) _ =-          {- PUSH data. -}        (n - 1,        i + 1, j,     m >> Vector.write v i j)---vmOp :: VM -> Maybe Op-vmOp vm =-  let i  = vm ^. state . pc-      code' = vm ^. state . code-      (op, pushdata) = case code' of-        InitCode xs' _ ->-          (BS.index xs' i, fmap LitByte $ BS.unpack $ BS.drop i xs')-        RuntimeCode (ConcreteRuntimeCode xs') ->-          (BS.index xs' i, fmap LitByte $ BS.unpack $ BS.drop i xs')-        RuntimeCode (SymbolicRuntimeCode xs') ->-          ( fromMaybe (error "unexpected symbolic code") . unlitByte $ xs' V.! i , V.toList $ V.drop i xs')-  in if (opslen code' < i)-     then Nothing-     else Just (readOp op pushdata)--vmOpIx :: VM -> Maybe Int-vmOpIx vm =-  do self <- currentContract vm-     self._opIxMap Vector.!? vm._state._pc--opParams :: VM -> Map String (Expr EWord)-opParams vm =-  case vmOp vm of-    Just OpCreate ->-      params $ words "value offset size"-    Just OpCall ->-      params $ words "gas to value in-offset in-size out-offset out-size"-    Just OpSstore ->-      params $ words "index value"-    Just OpCodecopy ->-      params $ words "mem-offset code-offset code-size"-    Just OpSha3 ->-      params $ words "offset size"-    Just OpCalldatacopy ->-      params $ words "to from size"-    Just OpExtcodecopy ->-      params $ words "account mem-offset code-offset code-size"-    Just OpReturn ->-      params $ words "offset size"-    Just OpJumpi ->-      params $ words "destination condition"-    _ -> mempty-  where-    params xs =-      if length (vm ^. state . stack) >= length xs-      then Map.fromList (zip xs (vm ^. state . stack))-      else mempty---- Maps operation indicies into a pair of (bytecode index, operation)-mkCodeOps :: ContractCode -> RegularVector.Vector (Int, Op)-mkCodeOps contractCode =-  let l = case contractCode of-            InitCode bytes _ ->-              LitByte <$> (BS.unpack bytes)-            RuntimeCode (ConcreteRuntimeCode ops) ->-              LitByte <$> (BS.unpack $ stripBytecodeMetadata ops)-            RuntimeCode (SymbolicRuntimeCode ops) ->-              stripBytecodeMetadataSym $ V.toList ops-  in RegularVector.fromList . toList $ go 0 l-  where-    go !i !xs =-      case uncons xs of-        Nothing ->-          mempty-        Just (x, xs') ->-          let x' = fromMaybe (error "unexpected symbolic code argument") $ unlitByte x-              j = opSize x'-          in (i, readOp x' xs') Seq.<| go (i + j) (drop j xs)---- * Gas cost calculation helpers---- Gas cost function for CALL, transliterated from the Yellow Paper.-costOfCall-  :: FeeSchedule Word64-  -> Bool -> W256 -> Word64 -> Word64 -> Addr-  -> EVM (Word64, Word64)-costOfCall (FeeSchedule {..}) recipientExists xValue availableGas xGas target = do-  acc <- accessAccountForGas target-  let call_base_gas = if acc then g_warm_storage_read else g_cold_account_access-      c_new = if not recipientExists && xValue /= 0-            then g_newaccount-            else 0-      c_xfer = if xValue /= 0  then num g_callvalue else 0-      c_extra = call_base_gas + c_xfer + c_new-      c_gascap =  if availableGas >= c_extra-                  then min xGas (allButOne64th (availableGas - c_extra))-                  else xGas-      c_callgas = if xValue /= 0 then c_gascap + g_callstipend else c_gascap-  return (c_gascap + c_extra, c_callgas)---- Gas cost of create, including hash cost if needed-costOfCreate-  :: FeeSchedule Word64-  -> Word64 -> W256 -> (Word64, Word64)-costOfCreate (FeeSchedule {..}) availableGas hashSize =-  (createCost + initGas, initGas)-  where-    createCost = g_create + hashCost-    hashCost   = g_sha3word * ceilDiv (num hashSize) 32-    initGas    = allButOne64th (availableGas - createCost)--concreteModexpGasFee :: ByteString -> Word64-concreteModexpGasFee input =-  if lenb < num (maxBound :: Word32) &&-     (lene < num (maxBound :: Word32) || (lenb == 0 && lenm == 0)) &&-     lenm < num (maxBound :: Word64)-  then-    max 200 ((multiplicationComplexity * iterCount) `div` 3)-  else-    maxBound -- TODO: this is not 100% correct, return Nothing on overflow-  where (lenb, lene, lenm) = parseModexpLength input-        ez = isZero (96 + lenb) lene input-        e' = word $ LS.toStrict $-          lazySlice (96 + lenb) (min 32 lene) input-        nwords :: Word64-        nwords = ceilDiv (num $ max lenb lenm) 8-        multiplicationComplexity = nwords * nwords-        iterCount' :: Word64-        iterCount' | lene <= 32 && ez = 0-                   | lene <= 32 = num (log2 e')-                   | e' == 0 = 8 * (num lene - 32)-                   | otherwise = num (log2 e') + 8 * (num lene - 32)-        iterCount = max iterCount' 1---- Gas cost of precompiles-costOfPrecompile :: FeeSchedule Word64 -> Addr -> Expr Buf -> Word64-costOfPrecompile (FeeSchedule {..}) precompileAddr input =-  let errorDynamicSize = error "precompile input cannot have a dynamic size"-      inputLen = case input of-                   ConcreteBuf bs -> fromIntegral $ BS.length bs-                   AbstractBuf _ -> errorDynamicSize-                   buf -> case bufLength buf of-                            Lit l -> num l -- TODO: overflow-                            _ -> errorDynamicSize-  in case precompileAddr of-    -- ECRECOVER-    0x1 -> 3000-    -- SHA2-256-    0x2 -> num $ (((inputLen + 31) `div` 32) * 12) + 60-    -- RIPEMD-160-    0x3 -> num $ (((inputLen + 31) `div` 32) * 120) + 600-    -- IDENTITY-    0x4 -> num $ (((inputLen + 31) `div` 32) * 3) + 15-    -- MODEXP-    0x5 -> case input of-             ConcreteBuf i -> concreteModexpGasFee i-             _ -> error "Unsupported symbolic modexp gas calc "-    -- ECADD-    0x6 -> g_ecadd-    -- ECMUL-    0x7 -> g_ecmul-    -- ECPAIRING-    0x8 -> (inputLen `div` 192) * g_pairing_point + g_pairing_base-    -- BLAKE2-    0x9 -> case input of-             ConcreteBuf i -> g_fround * (num $ asInteger $ lazySlice 0 4 i)-             _ -> error "Unsupported symbolic blake2 gas calc"-    _ -> error ("unimplemented precompiled contract " ++ show precompileAddr)---- Gas cost of memory expansion-memoryCost :: FeeSchedule Word64 -> Word64 -> Word64-memoryCost FeeSchedule{..} byteCount =-  let-    wordCount = ceilDiv byteCount 32-    linearCost = g_memory * wordCount-    quadraticCost = div (wordCount * wordCount) 512-  in-    linearCost + quadraticCost---- * Arithmetic--ceilDiv :: (Num a, Integral a) => a -> a -> a-ceilDiv m n = div (m + n - 1) n--allButOne64th :: (Num a, Integral a) => a -> a-allButOne64th n = n - div n 64--log2 :: FiniteBits b => b -> Int-log2 x = finiteBitSize x - 1 - countLeadingZeros x--hashcode :: ContractCode -> Expr EWord-hashcode (InitCode ops args) = keccak $ (ConcreteBuf ops) <> args-hashcode (RuntimeCode (ConcreteRuntimeCode ops)) = keccak (ConcreteBuf ops)-hashcode (RuntimeCode (SymbolicRuntimeCode ops)) = keccak . Expr.fromList $ ops---- | The length of the code ignoring any constructor args.--- This represents the region that can contain executable opcodes-opslen :: ContractCode -> Int-opslen (InitCode ops _) = BS.length ops-opslen (RuntimeCode (ConcreteRuntimeCode ops)) = BS.length ops-opslen (RuntimeCode (SymbolicRuntimeCode ops)) = length ops---- | The length of the code including any constructor args.--- This can return an abstract value-codelen :: ContractCode -> Expr EWord-codelen c@(InitCode {}) = bufLength $ toBuf c-codelen (RuntimeCode (ConcreteRuntimeCode ops)) = Lit . num $ BS.length ops-codelen (RuntimeCode (SymbolicRuntimeCode ops)) = Lit . num $ length ops--toBuf :: ContractCode -> Expr Buf-toBuf (InitCode ops args) = ConcreteBuf ops <> args-toBuf (RuntimeCode (ConcreteRuntimeCode ops)) = ConcreteBuf ops-toBuf (RuntimeCode (SymbolicRuntimeCode ops)) = Expr.fromList ops---codeloc :: EVM CodeLocation-codeloc = do-  vm <- get-  let self = vm._state._contract-      loc = vm._state._pc-  pure (self, loc)---- * Emacs setup---- Local Variables:--- outline-regexp: "-- \\*+\\|data \\|newtype \\|type \\| +-- op: "--- outline-heading-alist:---   (("-- *" . 1) ("data " . 2) ("newtype " . 2) ("type " . 2))--- compile-command: "make"--- End:+{-# Language UndecidableInstances #-}+{-# Language TemplateHaskell #-}+{-# Language ScopedTypeVariables #-}+{-# Language GADTs #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE TypeApplications #-}++module EVM where++import Prelude hiding (log, exponent, GT, LT)++import Optics.Core+import Optics.TH+import Optics.State+import Optics.State.Operators+import Optics.Zoom+import Optics.Operators.Unsafe++import EVM.ABI+import EVM.Concrete (createAddress, create2Address)+import EVM.Expr (readStorage, writeStorage, readByte, readWord, writeWord,+  writeByte, bufLength, indexWord, litAddr, readBytes, word256At, copySlice)+import EVM.Expr qualified as Expr+import EVM.FeeSchedule (FeeSchedule (..))+import EVM.Op+import EVM.Precompiled qualified+import EVM.Solidity+import EVM.Types hiding (IllegalOverflow, Error)+import EVM.Sign qualified++import Control.Monad.State.Strict hiding (state)+import Data.Bits (FiniteBits, countLeadingZeros, finiteBitSize)+import Data.ByteArray qualified as BA+import Data.ByteString (ByteString)+import Data.ByteString qualified as BS+import Data.ByteString.Lazy (fromStrict)+import Data.ByteString.Lazy qualified as LS+import Data.ByteString.Char8 qualified as Char8+import Data.Foldable (toList)+import Data.List (find)+import Data.Map.Strict (Map)+import Data.Map.Strict qualified as Map+import Data.Maybe (fromMaybe, fromJust)+import Data.Set (Set, insert, member, fromList)+import Data.Sequence (Seq)+import Data.Sequence qualified as Seq+import Data.Text (unpack)+import Data.Text.Encoding (decodeUtf8, encodeUtf8)+import Data.Tree+import Data.Tree.Zipper qualified as Zipper+import Data.Tuple.Curry+import Data.Vector qualified as RegularVector+import Data.Vector qualified as V+import Data.Vector.Storable (Vector)+import Data.Vector.Storable qualified as Vector+import Data.Vector.Storable.Mutable qualified as Vector+import Data.Word (Word8, Word32, Word64)+import Options.Generic as Options++import Crypto.Hash (Digest, SHA256, RIPEMD160)+import Crypto.Hash qualified as Crypto+import Crypto.Number.ModArithmetic (expFast)++-- * Data types++-- | EVM failure modes+data Error+  = BalanceTooLow W256 W256+  | UnrecognizedOpcode Word8+  | SelfDestruction+  | StackUnderrun+  | BadJumpDestination+  | Revert (Expr Buf)+  | OutOfGas Word64 Word64+  | BadCheatCode FunctionSelector+  | StackLimitExceeded+  | IllegalOverflow+  | Query Query+  | Choose Choose+  | StateChangeWhileStatic+  | InvalidMemoryAccess+  | CallDepthLimitReached+  | MaxCodeSizeExceeded W256 W256+  | InvalidFormat+  | PrecompileFailure+  | forall a . UnexpectedSymbolicArg Int String [Expr a]+  | DeadPath+  | NotUnique (Expr EWord)+  | SMTTimeout+  | FFI [AbiValue]+  | ReturnDataOutOfBounds+  | NonceOverflow+deriving instance Show Error++-- | The possible result states of a VM+data VMResult+  = VMFailure Error -- ^ An operation failed+  | VMSuccess (Expr Buf) -- ^ Reached STOP, RETURN, or end-of-code++deriving instance Show VMResult++-- | The state of a stepwise EVM execution+data VM = VM+  { result         :: Maybe VMResult+  , state          :: FrameState+  , frames         :: [Frame]+  , env            :: Env+  , block          :: Block+  , tx             :: TxState+  , logs           :: [Expr Log]+  , traces         :: Zipper.TreePos Zipper.Empty Trace+  , cache          :: Cache+  , burned         :: {-# UNPACK #-} !Word64+  , iterations     :: Map CodeLocation Int+  , constraints    :: [Prop]+  , keccakEqs      :: [Prop]+  , allowFFI       :: Bool+  , overrideCaller :: Maybe Addr+  }+  deriving (Show, Generic)++data Trace = Trace+  { opIx      :: Int+  , contract  :: Contract+  , tracedata :: TraceData+  }+  deriving (Show, Generic)++data TraceData+  = EventTrace (Expr EWord) (Expr Buf) [Expr EWord]+  | FrameTrace FrameContext+  | QueryTrace Query+  | ErrorTrace Error+  | EntryTrace Text+  | ReturnTrace (Expr Buf) FrameContext+  deriving (Show, Generic)++-- | Queries halt execution until resolved through RPC calls or SMT queries+data Query where+  PleaseFetchContract :: Addr -> (Contract -> EVM ()) -> Query+  PleaseFetchSlot     :: Addr -> W256 -> (W256 -> EVM ()) -> Query+  PleaseAskSMT        :: Expr EWord -> [Prop] -> (BranchCondition -> EVM ()) -> Query+  PleaseDoFFI         :: [String] -> (ByteString -> EVM ()) -> Query++data Choose where+  PleaseChoosePath    :: Expr EWord -> (Bool -> EVM ()) -> Choose++instance Show Query where+  showsPrec _ = \case+    PleaseFetchContract addr _ ->+      (("<EVM.Query: fetch contract " ++ show addr ++ ">") ++)+    PleaseFetchSlot addr slot _ ->+      (("<EVM.Query: fetch slot "+        ++ show slot ++ " for "+        ++ show addr ++ ">") ++)+    PleaseAskSMT condition constraints _ ->+      (("<EVM.Query: ask SMT about "+        ++ show condition ++ " in context "+        ++ show constraints ++ ">") ++)+    PleaseDoFFI cmd _ ->+      (("<EVM.Query: do ffi: " ++ (show cmd)) ++)++instance Show Choose where+  showsPrec _ = \case+    PleaseChoosePath _ _ ->+      (("<EVM.Choice: waiting for user to select path (0,1)") ++)++-- | Alias for the type of e.g. @exec1@.+type EVM a = State VM a++type CodeLocation = (Addr, Int)++-- | The possible return values of a SMT query+data BranchCondition = Case Bool | Unknown | Inconsistent+  deriving Show++-- | The possible return values of a `is unique` SMT query+data IsUnique a = Unique a | Multiple | InconsistentU | TimeoutU+  deriving Show++-- | The cache is data that can be persisted for efficiency:+-- any expensive query that is constant at least within a block.+data Cache = Cache+  { fetchedContracts :: Map Addr Contract,+    fetchedStorage :: Map W256 (Map W256 W256),+    path :: Map (CodeLocation, Int) Bool+  } deriving (Show, Generic)++-- | A way to specify an initial VM state+data VMOpts = VMOpts+  { contract :: Contract+  , calldata :: (Expr Buf, [Prop])+  , initialStorage :: Expr Storage+  , value :: Expr EWord+  , priorityFee :: W256+  , address :: Addr+  , caller :: Expr EWord+  , origin :: Addr+  , gas :: Word64+  , gaslimit :: Word64+  , number :: W256+  , timestamp :: Expr EWord+  , coinbase :: Addr+  , prevRandao :: W256+  , maxCodeSize :: W256+  , blockGaslimit :: Word64+  , gasprice :: W256+  , baseFee :: W256+  , schedule :: FeeSchedule Word64+  , chainId :: W256+  , create :: Bool+  , txAccessList :: Map Addr [W256]+  , allowFFI :: Bool+  } deriving Show+++-- | An entry in the VM's "call/create stack"+data Frame = Frame+  { context :: FrameContext+  , state   :: FrameState+  }+  deriving (Show)++-- | Call/create info+data FrameContext+  = CreationContext+    { address         :: Addr+    , codehash        :: Expr EWord+    , createreversion :: Map Addr Contract+    , substate        :: SubState+    }+  | CallContext+    { target        :: Addr+    , context       :: Addr+    , offset        :: W256+    , size          :: W256+    , codehash      :: Expr EWord+    , abi           :: Maybe W256+    , calldata      :: Expr Buf+    , callreversion :: (Map Addr Contract, Expr Storage)+    , subState      :: SubState+    }+  deriving (Show, Generic)++-- | The "registers" of the VM along with memory and data stack+data FrameState = FrameState+  { contract     :: Addr+  , codeContract :: Addr+  , code         :: ContractCode+  , pc           :: {-# UNPACK #-} !Int+  , stack        :: [Expr EWord]+  , memory       :: Expr Buf+  , memorySize   :: Word64+  , calldata     :: Expr Buf+  , callvalue    :: Expr EWord+  , caller       :: Expr EWord+  , gas          :: {-# UNPACK #-} !Word64+  , returndata   :: Expr Buf+  , static       :: Bool+  }+  deriving (Show, Generic)++-- | The state that spans a whole transaction+data TxState = TxState+  { gasprice    :: W256+  , gaslimit    :: Word64+  , priorityFee :: W256+  , origin      :: Addr+  , toAddr      :: Addr+  , value       :: Expr EWord+  , substate    :: SubState+  , isCreate    :: Bool+  , txReversion :: Map Addr Contract+  }+  deriving (Show)++-- | The "accrued substate" across a transaction+data SubState = SubState+  { selfdestructs       :: [Addr]+  , touchedAccounts     :: [Addr]+  , accessedAddresses   :: Set Addr+  , accessedStorageKeys :: Set (Addr, W256)+  , refunds             :: [(Addr, Word64)]+  -- in principle we should include logs here, but do not for now+  }+  deriving (Show)++{- |+  A contract is either in creation (running its "constructor") or+  post-creation, and code in these two modes is treated differently+  by instructions like @EXTCODEHASH@, so we distinguish these two+  code types.++  The definition follows the structure of code output by solc. We need to use+  some heuristics here to deal with symbolic data regions that may be present+  in the bytecode since the fully abstract case is impractical:++  - initcode has concrete code, followed by an abstract data "section"+  - runtimecode has a fixed length, but may contain fixed size symbolic regions (due to immutable)++  hopefully we do not have to deal with dynamic immutable before we get a real data section...+-}+data ContractCode+  = InitCode ByteString (Expr Buf) -- ^ "Constructor" code, during contract creation+  | RuntimeCode RuntimeCode -- ^ "Instance" code, after contract creation+  deriving (Show, Ord)++-- | We have two variants here to optimize the fully concrete case.+-- ConcreteRuntimeCode just wraps a ByteString+-- SymbolicRuntimeCode is a fixed length vector of potentially symbolic bytes, which lets us handle symbolic pushdata (e.g. from immutable variables in solidity).+data RuntimeCode+  = ConcreteRuntimeCode ByteString+  | SymbolicRuntimeCode (V.Vector (Expr Byte))+  deriving (Show, Eq, Ord)++-- runtime err when used for symbolic code+instance Eq ContractCode where+  InitCode a b  == InitCode c d  = a == c && b == d+  RuntimeCode x == RuntimeCode y = x == y+  _ == _ = False++-- | The state of a contract+data Contract = Contract+  { contractcode :: ContractCode+  , balance      :: W256+  , nonce        :: W256+  , codehash     :: Expr EWord+  , opIxMap      :: Vector Int+  , codeOps      :: RegularVector.Vector (Int, Op)+  , external     :: Bool+  }+  deriving (Show)++-- | Various environmental data+data Env = Env+  { contracts    :: Map Addr Contract+  , chainId      :: W256+  , storage      :: Expr Storage+  , origStorage  :: Map W256 (Map W256 W256)+  , sha3Crack    :: Map W256 ByteString+  }+  deriving (Show, Generic)+++-- | Data about the block+data Block = Block+  { coinbase    :: Addr+  , timestamp   :: Expr EWord+  , number      :: W256+  , prevRandao  :: W256+  , gaslimit    :: Word64+  , baseFee     :: W256+  , maxCodeSize :: W256+  , schedule    :: FeeSchedule Word64+  } deriving (Show, Generic)+++makeFieldLabelsNoPrefix ''VM+makeFieldLabelsNoPrefix ''FrameState+makeFieldLabelsNoPrefix ''TxState+makeFieldLabelsNoPrefix ''SubState+makeFieldLabelsNoPrefix ''Cache+makeFieldLabelsNoPrefix ''Trace+makeFieldLabelsNoPrefix ''VMOpts+makeFieldLabelsNoPrefix ''Frame+makeFieldLabelsNoPrefix ''FrameContext+makeFieldLabelsNoPrefix ''Contract+makeFieldLabelsNoPrefix ''Env+makeFieldLabelsNoPrefix ''Block++blankState :: FrameState+blankState = FrameState+  { contract     = 0+  , codeContract = 0+  , code         = RuntimeCode (ConcreteRuntimeCode "")+  , pc           = 0+  , stack        = mempty+  , memory       = mempty+  , memorySize   = 0+  , calldata     = mempty+  , callvalue    = Lit 0+  , caller       = Lit 0+  , gas          = 0+  , returndata   = mempty+  , static       = False+  }++-- | An "external" view of a contract's bytecode, appropriate for+-- e.g. @EXTCODEHASH@.+bytecode :: Getter Contract (Expr Buf)+bytecode = #contractcode % to f+  where f (InitCode _ _) = mempty+        f (RuntimeCode (ConcreteRuntimeCode bs)) = ConcreteBuf bs+        f (RuntimeCode (SymbolicRuntimeCode ops)) = Expr.fromList ops++instance Semigroup Cache where+  a <> b = Cache+    { fetchedContracts = Map.unionWith unifyCachedContract a.fetchedContracts b.fetchedContracts+    , fetchedStorage = Map.unionWith unifyCachedStorage a.fetchedStorage b.fetchedStorage+    , path = mappend a.path b.path+    }++unifyCachedStorage :: Map W256 W256 -> Map W256 W256 -> Map W256 W256+unifyCachedStorage _ _ = undefined++-- only intended for use in Cache merges, where we expect+-- everything to be Concrete+unifyCachedContract :: Contract -> Contract -> Contract+unifyCachedContract _ _ = undefined+  {-+unifyCachedContract a b = a & set storage merged+  where merged = case (view storage a, view storage b) of+                   (ConcreteStore sa, ConcreteStore sb) ->+                     ConcreteStore (mappend sa sb)+                   _ ->+                     view storage a+   -}++instance Monoid Cache where+  mempty = Cache { fetchedContracts = mempty,+                   fetchedStorage = mempty,+                   path = mempty+                 }++-- * Data accessors++currentContract :: VM -> Maybe Contract+currentContract vm =+  Map.lookup vm.state.codeContract vm.env.contracts++-- * Data constructors++makeVm :: VMOpts -> VM+makeVm o =+  let txaccessList = o.txAccessList+      txorigin = o.origin+      txtoAddr = o.address+      initialAccessedAddrs = fromList $ [txorigin, txtoAddr] ++ [1..9] ++ (Map.keys txaccessList)+      initialAccessedStorageKeys = fromList $ foldMap (uncurry (map . (,))) (Map.toList txaccessList)+      touched = if o.create then [txorigin] else [txorigin, txtoAddr]+  in+  VM+  { result = Nothing+  , frames = mempty+  , tx = TxState+    { gasprice = o.gasprice+    , gaslimit = o.gaslimit+    , priorityFee = o.priorityFee+    , origin = txorigin+    , toAddr = txtoAddr+    , value = o.value+    , substate = SubState mempty touched initialAccessedAddrs initialAccessedStorageKeys mempty+    --, _accessList = txaccessList+    , isCreate = o.create+    , txReversion = Map.fromList+      [(o.address , o.contract )]+    }+  , logs = []+  , traces = Zipper.fromForest []+  , block = Block+    { coinbase = o.coinbase+    , timestamp = o.timestamp+    , number = o.number+    , prevRandao = o.prevRandao+    , maxCodeSize = o.maxCodeSize+    , gaslimit = o.blockGaslimit+    , baseFee = o.baseFee+    , schedule = o.schedule+    }+  , state = FrameState+    { pc = 0+    , stack = mempty+    , memory = mempty+    , memorySize = 0+    , code = o.contract.contractcode+    , contract = o.address+    , codeContract = o.address+    , calldata = fst o.calldata+    , callvalue = o.value+    , caller = o.caller+    , gas = o.gas+    , returndata = mempty+    , static = False+    }+  , env = Env+    { sha3Crack = mempty+    , chainId = o.chainId+    , storage = o.initialStorage+    , origStorage = mempty+    , contracts = Map.fromList+      [(o.address, o.contract )]+    }+  , cache = Cache mempty mempty mempty+  , burned = 0+  , constraints = snd o.calldata+  , keccakEqs = mempty+  , iterations = mempty+  , allowFFI = o.allowFFI+  , overrideCaller = Nothing+  }++-- | Initialize empty contract with given code+initialContract :: ContractCode -> Contract+initialContract contractCode = Contract+  { contractcode = contractCode+  , codehash = hashcode contractCode+  , balance  = 0+  , nonce    = if creation then 1 else 0+  , opIxMap  = mkOpIxMap contractCode+  , codeOps  = mkCodeOps contractCode+  , external = False+  } where+      creation = case contractCode of+        InitCode _ _  -> True+        RuntimeCode _ -> False++-- * Opcode dispatch (exec1)++-- | Update program counter+next :: (?op :: Word8) => EVM ()+next = modifying (#state % #pc) (+ (opSize ?op))++-- | Executes the EVM one step+exec1 :: EVM ()+exec1 = do+  vm <- get++  let+    -- Convenient aliases+    mem  = vm.state.memory+    stk  = vm.state.stack+    self = vm.state.contract+    this = fromMaybe (error "internal error: state contract") (Map.lookup self vm.env.contracts)++    fees@FeeSchedule {..} = vm.block.schedule++    doStop = finishFrame (FrameReturned mempty)++  if self > 0x0 && self <= 0x9 then do+    -- call to precompile+    let ?op = 0x00 -- dummy value+    case bufLength vm.state.calldata of+      Lit calldatasize -> do+          copyBytesToMemory vm.state.calldata (Lit calldatasize) (Lit 0) (Lit 0)+          executePrecompile self vm.state.gas 0 calldatasize 0 0 []+          vmx <- get+          case vmx.state.stack of+            x:_ -> case x of+              Lit 0 ->+                fetchAccount self $ \_ -> do+                  touchAccount self+                  vmError PrecompileFailure+              Lit _ ->+                fetchAccount self $ \_ -> do+                  touchAccount self+                  out <- use (#state % #returndata)+                  finishFrame (FrameReturned out)+              e -> vmError $+                UnexpectedSymbolicArg vmx.state.pc "precompile returned a symbolic value" [e]+            _ ->+              underrun+      e -> vmError $ UnexpectedSymbolicArg vm.state.pc "cannot call precompiles with symbolic data" [e]++  else if vm.state.pc >= opslen vm.state.code+    then doStop++    else do+      let ?op = case vm.state.code of+                  InitCode conc _ -> BS.index conc vm.state.pc+                  RuntimeCode (ConcreteRuntimeCode bs) -> BS.index bs vm.state.pc+                  RuntimeCode (SymbolicRuntimeCode ops) ->+                    fromMaybe (error "could not analyze symbolic code") $+                      unlitByte $ ops V.! vm.state.pc++      case getOp(?op) of++        OpPush n' -> do+          let n = fromIntegral n'+              !xs = case vm.state.code of+                InitCode conc _ -> Lit $ word $ padRight n $ BS.take n (BS.drop (1 + vm.state.pc) conc)+                RuntimeCode (ConcreteRuntimeCode bs) -> Lit $ word $ BS.take n $ BS.drop (1 + vm.state.pc) bs+                RuntimeCode (SymbolicRuntimeCode ops) ->+                  let bytes = V.take n $ V.drop (1 + vm.state.pc) ops+                  in readWord (Lit 0) $ Expr.fromList $ padLeft' 32 bytes+          limitStack 1 $+            burn g_verylow $ do+              next+              pushSym xs++        OpDup i ->+          case preview (ix (fromIntegral i - 1)) stk of+            Nothing -> underrun+            Just y ->+              limitStack 1 $+                burn g_verylow $ do+                  next+                  pushSym y++        OpSwap i ->+          if length stk < (fromIntegral i) + 1+            then underrun+            else+              burn g_verylow $ do+                next+                zoom (#state % #stack) $ do+                  assign (ix 0) (stk ^?! ix (fromIntegral i))+                  assign (ix (fromIntegral i)) (stk ^?! ix 0)++        OpLog n ->+          notStatic $+          case stk of+            (xOffset':xSize':xs) ->+              if length xs < (fromIntegral n)+              then underrun+              else+                forceConcrete2 (xOffset', xSize') "LOG" $ \(xOffset, xSize) -> do+                    let (topics, xs') = splitAt (fromIntegral n) xs+                        bytes         = readMemory xOffset' xSize' vm+                        logs'         = (LogEntry (litAddr self) bytes topics) : vm.logs+                    burn (g_log + g_logdata * (num xSize) + num n * g_logtopic) $+                      accessMemoryRange xOffset xSize $ do+                        traceTopLog logs'+                        next+                        assign (#state % #stack) xs'+                        assign #logs logs'+            _ ->+              underrun++        OpStop -> doStop++        OpAdd -> stackOp2 g_verylow (uncurry Expr.add)+        OpMul -> stackOp2 g_low (uncurry Expr.mul)+        OpSub -> stackOp2 g_verylow (uncurry Expr.sub)++        OpDiv -> stackOp2 g_low (uncurry Expr.div)++        OpSdiv -> stackOp2 g_low (uncurry Expr.sdiv)++        OpMod -> stackOp2 g_low (uncurry Expr.mod)++        OpSmod -> stackOp2 g_low (uncurry Expr.smod)+        OpAddmod -> stackOp3 g_mid (uncurryN Expr.addmod)+        OpMulmod -> stackOp3 g_mid (uncurryN Expr.mulmod)++        OpLt -> stackOp2 g_verylow (uncurry Expr.lt)+        OpGt -> stackOp2 g_verylow (uncurry Expr.gt)+        OpSlt -> stackOp2 g_verylow (uncurry Expr.slt)+        OpSgt -> stackOp2 g_verylow (uncurry Expr.sgt)++        OpEq -> stackOp2 g_verylow (uncurry Expr.eq)+        OpIszero -> stackOp1 g_verylow Expr.iszero++        OpAnd -> stackOp2 g_verylow (uncurry Expr.and)+        OpOr -> stackOp2 g_verylow (uncurry Expr.or)+        OpXor -> stackOp2 g_verylow (uncurry Expr.xor)+        OpNot -> stackOp1 g_verylow Expr.not++        OpByte -> stackOp2 g_verylow (\(i, w) -> Expr.padByte $ Expr.indexWord i w)++        OpShl -> stackOp2 g_verylow (uncurry Expr.shl)+        OpShr -> stackOp2 g_verylow (uncurry Expr.shr)+        OpSar -> stackOp2 g_verylow (uncurry Expr.sar)++        -- more accurately refered to as KECCAK+        OpSha3 ->+          case stk of+            xOffset':xSize':xs ->+              forceConcrete xOffset' "sha3 offset must be concrete" $+                \xOffset -> forceConcrete xSize' "sha3 size must be concrete" $ \xSize ->+                  burn (g_sha3 + g_sha3word * ceilDiv (num xSize) 32) $+                    accessMemoryRange xOffset xSize $ do+                      (hash, invMap) <- case readMemory xOffset' xSize' vm of+                                          ConcreteBuf bs -> do+                                            let hash' = keccak' bs+                                            eqs <- use #keccakEqs+                                            assign #keccakEqs $+                                              PEq (Lit hash') (Keccak (ConcreteBuf bs)):eqs+                                            pure (Lit hash', Map.singleton hash' bs)+                                          buf -> pure (Keccak buf, mempty)+                      next+                      assign (#state % #stack) (hash : xs)+                      modifying (#env % #sha3Crack) ((<>) invMap)+            _ -> underrun++        OpAddress ->+          limitStack 1 $+            burn g_base (next >> push (num self))++        OpBalance ->+          case stk of+            x':xs -> forceConcrete x' "BALANCE" $ \x ->+              accessAndBurn (num x) $+                fetchAccount (num x) $ \c -> do+                  next+                  assign (#state % #stack) xs+                  push (num c.balance)+            [] ->+              underrun++        OpOrigin ->+          limitStack 1 . burn g_base $+            next >> push (num vm.tx.origin)++        OpCaller ->+          limitStack 1 . burn g_base $+            next >> pushSym vm.state.caller++        OpCallvalue ->+          limitStack 1 . burn g_base $+            next >> pushSym vm.state.callvalue++        OpCalldataload -> stackOp1 g_verylow $+          \ind -> Expr.readWord ind vm.state.calldata++        OpCalldatasize ->+          limitStack 1 . burn g_base $+            next >> pushSym (bufLength vm.state.calldata)++        OpCalldatacopy ->+          case stk of+            xTo':xFrom:xSize':xs ->+              forceConcrete2 (xTo', xSize') "CALLDATACOPY" $+                \(xTo, xSize) ->+                  burn (g_verylow + g_copy * ceilDiv (num xSize) 32) $+                    accessMemoryRange xTo xSize $ do+                      next+                      assign (#state % #stack) xs+                      copyBytesToMemory vm.state.calldata xSize' xFrom xTo'+            _ -> underrun++        OpCodesize ->+          limitStack 1 . burn g_base $+            next >> pushSym (codelen vm.state.code)++        OpCodecopy ->+          case stk of+            memOffset':codeOffset:n':xs ->+              forceConcrete2 (memOffset', n') "CODECOPY" $+                \(memOffset,n) -> do+                  case toWord64 n of+                    Nothing -> vmError IllegalOverflow+                    Just n'' ->+                      if n'' <= ( (maxBound :: Word64) - g_verylow ) `div` g_copy * 32 then+                        burn (g_verylow + g_copy * ceilDiv (num n) 32) $+                          accessMemoryRange memOffset n $ do+                            next+                            assign (#state % #stack) xs+                            copyBytesToMemory (toBuf vm.state.code) n' codeOffset memOffset'+                      else vmError IllegalOverflow+            _ -> underrun++        OpGasprice ->+          limitStack 1 . burn g_base $+            next >> push vm.tx.gasprice++        OpExtcodesize ->+          case stk of+            x':xs -> case x' of+              Lit x -> if x == num cheatCode+                then do+                  next+                  assign (#state % #stack) xs+                  pushSym (Lit 1)+                else+                  accessAndBurn (num x) $+                    fetchAccount (num x) $ \c -> do+                      next+                      assign (#state % #stack) xs+                      pushSym (bufLength (view bytecode c))+              _ -> do+                assign (#state % #stack) xs+                pushSym (CodeSize x')+                next+            [] ->+              underrun++        OpExtcodecopy ->+          case stk of+            extAccount':memOffset':codeOffset:codeSize':xs ->+              forceConcrete3 (extAccount', memOffset', codeSize') "EXTCODECOPY" $+                \(extAccount, memOffset, codeSize) -> do+                  acc <- accessAccountForGas (num extAccount)+                  let cost = if acc then g_warm_storage_read else g_cold_account_access+                  burn (cost + g_copy * ceilDiv (num codeSize) 32) $+                    accessMemoryRange memOffset codeSize $+                      fetchAccount (num extAccount) $ \c -> do+                        next+                        assign (#state % #stack) xs+                        copyBytesToMemory (view bytecode c) codeSize' codeOffset memOffset'+            _ -> underrun++        OpReturndatasize ->+          limitStack 1 . burn g_base $+            next >> pushSym (bufLength vm.state.returndata)++        OpReturndatacopy ->+          case stk of+            xTo':xFrom:xSize':xs -> forceConcrete2 (xTo', xSize') "RETURNDATACOPY" $+              \(xTo, xSize) ->+                burn (g_verylow + g_copy * ceilDiv (num xSize) 32) $+                  accessMemoryRange xTo xSize $ do+                    next+                    assign (#state % #stack) xs++                    let jump True = vmError EVM.ReturnDataOutOfBounds+                        jump False = copyBytesToMemory vm.state.returndata xSize' xFrom xTo'++                    case (xFrom, bufLength vm.state.returndata) of+                      (Lit f, Lit l) ->+                        jump $ l < f + xSize || f + xSize < f+                      _ -> do+                        let oob = Expr.lt (bufLength vm.state.returndata) (Expr.add xFrom xSize')+                            overflow = Expr.lt (Expr.add xFrom xSize') (xFrom)+                        loc <- codeloc+                        branch loc (Expr.or oob overflow) jump+            _ -> underrun++        OpExtcodehash ->+          case stk of+            x':xs -> forceConcrete x' "EXTCODEHASH" $ \x ->+              accessAndBurn (num x) $ do+                next+                assign (#state % #stack) xs+                fetchAccount (num x) $ \c ->+                   if accountEmpty c+                     then push (num (0 :: Int))+                     else pushSym $ keccak (view bytecode c)+            [] ->+              underrun++        OpBlockhash -> do+          -- We adopt the fake block hash scheme of the VMTests,+          -- so that blockhash(i) is the hash of i as decimal ASCII.+          stackOp1 g_blockhash $ \case+            Lit i -> if i + 256 < vm.block.number || i >= vm.block.number+                     then Lit 0+                     else (num i :: Integer) & show & Char8.pack & keccak' & Lit+            i -> BlockHash i++        OpCoinbase ->+          limitStack 1 . burn g_base $+            next >> push (num vm.block.coinbase)++        OpTimestamp ->+          limitStack 1 . burn g_base $+            next >> pushSym vm.block.timestamp++        OpNumber ->+          limitStack 1 . burn g_base $+            next >> push vm.block.number++        OpPrevRandao -> do+          limitStack 1 . burn g_base $+            next >> push vm.block.prevRandao++        OpGaslimit ->+          limitStack 1 . burn g_base $+            next >> push (num vm.block.gaslimit)++        OpChainid ->+          limitStack 1 . burn g_base $+            next >> push vm.env.chainId++        OpSelfbalance ->+          limitStack 1 . burn g_low $+            next >> push this.balance++        OpBaseFee ->+          limitStack 1 . burn g_base $+            next >> push vm.block.baseFee++        OpPop ->+          case stk of+            _:xs -> burn g_base (next >> assign (#state % #stack) xs)+            _    -> underrun++        OpMload ->+          case stk of+            x':xs -> forceConcrete x' "MLOAD" $ \x ->+              burn g_verylow $+                accessMemoryWord x $ do+                  next+                  assign (#state % #stack) (readWord (Lit x) mem : xs)+            _ -> underrun++        OpMstore ->+          case stk of+            x':y:xs -> forceConcrete x' "MSTORE index" $ \x ->+              burn g_verylow $+                accessMemoryWord x $ do+                  next+                  assign (#state % #memory) (writeWord (Lit x) y mem)+                  assign (#state % #stack) xs+            _ -> underrun++        OpMstore8 ->+          case stk of+            x':y:xs -> forceConcrete x' "MSTORE8" $ \x ->+              burn g_verylow $+                accessMemoryRange x 1 $ do+                  let yByte = indexWord (Lit 31) y+                  next+                  modifying (#state % #memory) (writeByte (Lit x) yByte)+                  assign (#state % #stack) xs+            _ -> underrun++        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)+            _ -> underrun++        OpSstore ->+          notStatic $+          case stk of+            x:new:xs ->+              accessStorage self x $ \current -> do+                availableGas <- use (#state % #gas)++                if num availableGas <= g_callstipend then+                  finishFrame (FrameErrored (OutOfGas availableGas (num g_callstipend)))+                else do+                  let+                    original =+                      case readStorage (litAddr self) x (ConcreteStore vm.env.origStorage) of+                        Just (Lit v) -> v+                        _ -> 0+                    storage_cost =+                      case (maybeLitWord current, maybeLitWord 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++                  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 % #storage) (writeStorage (litAddr self) x new)++                    case (maybeLitWord current, maybeLitWord 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 new' == 0+                                then refund (g_sreset + g_access_list_storage_key)+                                else unRefund (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+            _ -> underrun++        OpJump ->+          case stk of+            x:xs ->+              burn g_mid $ forceConcrete x "JUMP: symbolic jumpdest" $ \x' ->+                case toInt x' of+                  Nothing -> vmError EVM.BadJumpDestination+                  Just i -> checkJump i xs+            _ -> underrun++        OpJumpi -> do+          case stk of+            (x:y:xs) -> forceConcrete x "JUMPI: symbolic jumpdest" $ \x' ->+                burn g_high $+                  let jump :: Bool -> EVM ()+                      jump False = assign (#state % #stack) xs >> next+                      jump _    = case toInt x' of+                        Nothing -> vmError EVM.BadJumpDestination+                        Just i -> checkJump i xs+                  in case maybeLitWord y of+                    Just y' -> jump (0 /= y')+                    -- if the jump condition is symbolic, we explore both sides+                    Nothing -> do+                      loc <- codeloc+                      branch loc y jump+            _ -> underrun++        OpPc ->+          limitStack 1 . burn g_base $+            next >> push (num vm.state.pc)++        OpMsize ->+          limitStack 1 . burn g_base $+            next >> push (num vm.state.memorySize)++        OpGas ->+          limitStack 1 . burn g_base $+            next >> push (num (vm.state.gas - g_base))++        OpJumpdest -> burn g_jumpdest next++        OpExp ->+          -- NOTE: this can be done symbolically using unrolling like this:+          --       https://hackage.haskell.org/package/sbv-9.0/docs/src/Data.SBV.Core.Model.html#.%5E+          --       However, it requires symbolic gas, since the gas depends on the exponent+          case stk of+            base:exponent':xs -> forceConcrete exponent' "EXP: symbolic exponent" $ \exponent ->+              let cost = if exponent == 0+                         then g_exp+                         else g_exp + g_expbyte * num (ceilDiv (1 + log2 exponent) 8)+              in burn cost $ do+                next+                (#state % #stack) .= Expr.exp base exponent' : xs+            _ -> underrun++        OpSignextend -> stackOp2 g_low (uncurry Expr.sex)++        OpCreate ->+          notStatic $+          case stk of+            xValue':xOffset':xSize':xs -> forceConcrete3 (xValue', xOffset', xSize') "CREATE" $+              \(xValue, xOffset, xSize) -> do+                accessMemoryRange xOffset xSize $ do+                  availableGas <- use (#state % #gas)+                  let+                    newAddr = createAddress self this.nonce+                    (cost, gas') = costOfCreate fees availableGas 0+                  _ <- accessAccountForGas newAddr+                  burn (cost - gas') $ do+                    -- unfortunately we have to apply some (pretty hacky)+                    -- heuristics here to parse the unstructured buffer read+                    -- from memory into a code and data section+                    let initCode = readMemory xOffset' xSize' vm+                    create self this (num gas') xValue xs newAddr initCode+            _ -> underrun++        OpCall ->+          case stk of+            xGas':xTo:xValue':xInOffset':xInSize':xOutOffset':xOutSize':xs ->+              forceConcrete6 (xGas', xValue', xInOffset', xInSize', xOutOffset', xOutSize') "CALL" $+              \(xGas, xValue, xInOffset, xInSize, xOutOffset, xOutSize) ->+                (if xValue > 0 then notStatic else id) $+                  delegateCall this (num xGas) xTo xTo xValue xInOffset xInSize xOutOffset xOutSize xs $ \callee -> do+                    let from' = fromMaybe self vm.overrideCaller+                    zoom #state $ do+                      assign #callvalue (Lit xValue)+                      assign #caller (litAddr from')+                      assign #contract callee+                    assign #overrideCaller Nothing+                    transfer from' callee xValue+                    touchAccount self+                    touchAccount callee+            _ ->+              underrun++        OpCallcode ->+          case stk of+            xGas':xTo:xValue':xInOffset':xInSize':xOutOffset':xOutSize':xs ->+              forceConcrete6 (xGas', xValue', xInOffset', xInSize', xOutOffset', xOutSize') "CALLCODE" $+              \(xGas, xValue, xInOffset, xInSize, xOutOffset, xOutSize) ->+                delegateCall this (num xGas) xTo (litAddr self) xValue xInOffset xInSize xOutOffset xOutSize xs $ \_ -> do+                  zoom #state $ do+                    assign #callvalue (Lit xValue)+                    assign #caller $ litAddr $ fromMaybe self vm.overrideCaller+                  assign #overrideCaller Nothing+                  touchAccount self+            _ ->+              underrun++        OpReturn ->+          case stk of+            xOffset':xSize':_ -> forceConcrete2 (xOffset', xSize') "RETURN" $ \(xOffset, xSize) ->+              accessMemoryRange xOffset xSize $ do+                let+                  output = readMemory xOffset' xSize' vm+                  codesize = fromMaybe (error "RETURN: cannot return dynamically sized abstract data")+                               . unlit . bufLength $ output+                  maxsize = vm.block.maxCodeSize+                  creation = case vm.frames of+                    [] -> vm.tx.isCreate+                    frame:_ -> case frame.context of+                       CreationContext {} -> True+                       CallContext {} -> False+                if creation+                then+                  if codesize > maxsize+                  then+                    finishFrame (FrameErrored (MaxCodeSizeExceeded maxsize codesize))+                  else do+                    let frameReturned = burn (g_codedeposit * num codesize) $+                                          finishFrame (FrameReturned output)+                        frameErrored = finishFrame $ FrameErrored InvalidFormat+                    case readByte (Lit 0) output of+                      LitByte 0xef -> frameErrored+                      LitByte _ -> frameReturned+                      y -> do+                        loc <- codeloc+                        branch loc (Expr.eqByte y (LitByte 0xef)) $ \case+                          True -> frameErrored+                          False -> frameReturned+                else+                   finishFrame (FrameReturned output)+            _ -> underrun++        OpDelegatecall ->+          case stk of+            xGas':xTo:xInOffset':xInSize':xOutOffset':xOutSize':xs ->+              forceConcrete5 (xGas', xInOffset', xInSize', xOutOffset', xOutSize') "DELEGATECALL" $+              \(xGas, xInOffset, xInSize, xOutOffset, xOutSize) ->+                delegateCall this (num xGas) xTo (litAddr self) 0 xInOffset xInSize xOutOffset xOutSize xs $ \_ -> do+                  touchAccount self+            _ -> underrun++        OpCreate2 -> notStatic $+          case stk of+            xValue':xOffset':xSize':xSalt':xs ->+              forceConcrete4 (xValue', xOffset', xSize', xSalt') "CREATE2" $+              \(xValue, xOffset, xSize, xSalt) ->+                accessMemoryRange xOffset xSize $ do+                  availableGas <- use (#state % #gas)++                  forceConcreteBuf (readMemory xOffset' xSize' vm) "CREATE2" $+                    \initCode -> do+                      let+                        newAddr  = create2Address self xSalt initCode+                        (cost, gas') = costOfCreate fees availableGas xSize+                      _ <- accessAccountForGas newAddr+                      burn (cost - gas') $ create self this gas' xValue xs newAddr (ConcreteBuf initCode)+            _ -> underrun++        OpStaticcall ->+          case stk of+            xGas':xTo:xInOffset':xInSize':xOutOffset':xOutSize':xs ->+              forceConcrete5 (xGas', xInOffset', xInSize', xOutOffset', xOutSize') "STATICCALL" $+              \(xGas, xInOffset, xInSize, xOutOffset, xOutSize) -> do+                delegateCall this (num xGas) xTo xTo 0 xInOffset xInSize xOutOffset xOutSize xs $ \callee -> do+                  zoom #state $ do+                    assign #callvalue (Lit 0)+                    assign #caller $ litAddr $ fromMaybe self (vm.overrideCaller)+                    assign #contract callee+                    assign #static True+                  assign #overrideCaller Nothing+                  touchAccount self+                  touchAccount callee+            _ ->+              underrun++        OpSelfdestruct ->+          notStatic $+          case stk of+            [] -> underrun+            (xTo':_) -> forceConcrete xTo' "SELFDESTRUCT" $ \(num -> xTo) -> do+              acc <- accessAccountForGas (num xTo)+              let cost = if acc then 0 else g_cold_account_access+                  funds = this.balance+                  recipientExists = accountExists xTo vm+                  c_new = if not recipientExists && funds /= 0+                          then g_selfdestruct_newaccount+                          else 0+              burn (g_selfdestruct + c_new + cost) $ do+                   selfdestruct self+                   touchAccount xTo++                   if funds /= 0+                   then fetchAccount xTo $ \_ -> do+                          #env % #contracts % ix xTo % #balance %= (+ funds)+                          assign (#env % #contracts % ix self % #balance) 0+                          doStop+                   else doStop++        OpRevert ->+          case stk of+            xOffset':xSize':_ -> forceConcrete2 (xOffset', xSize') "REVERT" $ \(xOffset, xSize) ->+              accessMemoryRange xOffset xSize $ do+                let output = readMemory xOffset' xSize' vm+                finishFrame (FrameReverted output)+            _ -> underrun++        OpUnknown xxx ->+          vmError (UnrecognizedOpcode xxx)++transfer :: Addr -> Addr -> W256 -> EVM ()+transfer xFrom xTo xValue =+  zoom (#env % #contracts) $ do+    (ix xFrom % #balance) %= (subtract xValue)+    (ix xTo % #balance) %= (+ xValue)++-- | Checks a *CALL for failure; OOG, too many callframes, memory access etc.+callChecks+  :: (?op :: Word8)+  => Contract -> Word64 -> Addr -> Addr -> W256 -> W256 -> W256 -> W256 -> W256 -> [Expr EWord]+   -- continuation with gas available for call+  -> (Word64 -> EVM ())+  -> EVM ()+callChecks this xGas xContext xTo xValue xInOffset xInSize xOutOffset xOutSize xs continue = do+  vm <- get+  let fees = vm.block.schedule+  accessMemoryRange xInOffset xInSize $+    accessMemoryRange xOutOffset xOutSize $ do+      availableGas <- use (#state % #gas)+      let recipientExists = accountExists xContext vm+      (cost, gas') <- costOfCall fees recipientExists xValue availableGas xGas xTo+      burn (cost - gas') $ do+        if xValue > num this.balance+        then do+          assign (#state % #stack) (Lit 0 : xs)+          assign (#state % #returndata) mempty+          pushTrace $ ErrorTrace $ BalanceTooLow xValue this.balance+          next+        else if length vm.frames >= 1024+             then do+               assign (#state % #stack) (Lit 0 : xs)+               assign (#state % #returndata) mempty+               pushTrace $ ErrorTrace CallDepthLimitReached+               next+             else continue gas'++precompiledContract+  :: (?op :: Word8)+  => Contract+  -> Word64+  -> Addr+  -> Addr+  -> W256+  -> W256 -> W256 -> W256 -> W256+  -> [Expr EWord]+  -> EVM ()+precompiledContract this xGas precompileAddr recipient xValue inOffset inSize outOffset outSize xs =+  callChecks this xGas recipient precompileAddr xValue inOffset inSize outOffset outSize xs $ \gas' ->+  do+    executePrecompile precompileAddr gas' inOffset inSize outOffset outSize xs+    self <- use (#state % #contract)+    stk <- use (#state % #stack)+    pc' <- use (#state % #pc)+    result' <- use #result+    case result' of+      Nothing -> case stk of+        x:_ -> case maybeLitWord x of+          Just 0 ->+            pure ()+          Just 1 ->+            fetchAccount recipient $ \_ -> do+              transfer self recipient xValue+              touchAccount self+              touchAccount recipient+          _ -> vmError $ UnexpectedSymbolicArg pc' "unexpected return value from precompile" [x]+        _ -> underrun+      _ -> pure ()++executePrecompile+  :: (?op :: Word8)+  => Addr+  -> Word64 -> W256 -> W256 -> W256 -> W256 -> [Expr EWord]+  -> EVM ()+executePrecompile preCompileAddr gasCap inOffset inSize outOffset outSize xs  = do+  vm <- get+  let input = readMemory (Lit inOffset) (Lit inSize) vm+      fees = vm.block.schedule+      cost = costOfPrecompile fees preCompileAddr input+      notImplemented = error $ "precompile at address " <> show preCompileAddr <> " not yet implemented"+      precompileFail = burn (gasCap - cost) $ do+                         assign (#state % #stack) (Lit 0 : xs)+                         pushTrace $ ErrorTrace PrecompileFailure+                         next+  if cost > gasCap then+    burn gasCap $ do+      assign (#state % #stack) (Lit 0 : xs)+      next+  else burn cost $+    case preCompileAddr of+      -- ECRECOVER+      0x1 ->+        -- TODO: support symbolic variant+        forceConcreteBuf input "ECRECOVER" $ \input' -> do+          case EVM.Precompiled.execute 0x1 (truncpadlit 128 input') 32 of+            Nothing -> do+              -- return no output for invalid signature+              assign (#state % #stack) (Lit 1 : xs)+              assign (#state % #returndata) mempty+              next+            Just output -> do+              assign (#state % #stack) (Lit 1 : xs)+              assign (#state % #returndata) (ConcreteBuf output)+              copyBytesToMemory (ConcreteBuf output) (Lit outSize) (Lit 0) (Lit outOffset)+              next++      -- SHA2-256+      0x2 ->+        forceConcreteBuf input "SHA2-256" $ \input' -> do+          let+            hash = sha256Buf input'+            sha256Buf x = ConcreteBuf $ BA.convert (Crypto.hash x :: Digest SHA256)+          assign (#state % #stack) (Lit 1 : xs)+          assign (#state % #returndata) hash+          copyBytesToMemory hash (Lit outSize) (Lit 0) (Lit outOffset)+          next++      -- RIPEMD-160+      0x3 ->+        -- TODO: support symbolic variant+        forceConcreteBuf input "RIPEMD160" $ \input' -> do+          let+            padding = BS.pack $ replicate 12 0+            hash' = BA.convert (Crypto.hash input' :: Digest RIPEMD160)+            hash  = ConcreteBuf $ padding <> hash'+          assign (#state % #stack) (Lit 1 : xs)+          assign (#state % #returndata) hash+          copyBytesToMemory hash (Lit outSize) (Lit 0) (Lit outOffset)+          next++      -- IDENTITY+      0x4 -> do+          assign (#state % #stack) (Lit 1 : xs)+          assign (#state % #returndata) input+          copyCallBytesToMemory input (Lit outSize) (Lit 0) (Lit outOffset)+          next++      -- MODEXP+      0x5 ->+        -- TODO: support symbolic variant+        forceConcreteBuf input "MODEXP" $ \input' -> do+          let+            (lenb, lene, lenm) = parseModexpLength input'++            output = ConcreteBuf $+              if isZero (96 + lenb + lene) lenm input'+              then truncpadlit (num lenm) (asBE (0 :: Int))+              else+                let+                  b = asInteger $ lazySlice 96 lenb input'+                  e = asInteger $ lazySlice (96 + lenb) lene input'+                  m = asInteger $ lazySlice (96 + lenb + lene) lenm input'+                in+                  padLeft (num lenm) (asBE (expFast b e m))+          assign (#state % #stack) (Lit 1 : xs)+          assign (#state % #returndata) output+          copyBytesToMemory output (Lit outSize) (Lit 0) (Lit outOffset)+          next++      -- ECADD+      0x6 ->+        -- TODO: support symbolic variant+        forceConcreteBuf input "ECADD" $ \input' ->+          case EVM.Precompiled.execute 0x6 (truncpadlit 128 input') 64 of+            Nothing -> precompileFail+            Just output -> do+              let truncpaddedOutput = ConcreteBuf $ truncpadlit 64 output+              assign (#state % #stack) (Lit 1 : xs)+              assign (#state % #returndata) truncpaddedOutput+              copyBytesToMemory truncpaddedOutput (Lit outSize) (Lit 0) (Lit outOffset)+              next++      -- ECMUL+      0x7 ->+        -- TODO: support symbolic variant+        forceConcreteBuf input "ECMUL" $ \input' ->+          case EVM.Precompiled.execute 0x7 (truncpadlit 96 input') 64 of+          Nothing -> precompileFail+          Just output -> do+            let truncpaddedOutput = ConcreteBuf $ truncpadlit 64 output+            assign (#state % #stack) (Lit 1 : xs)+            assign (#state % #returndata) truncpaddedOutput+            copyBytesToMemory truncpaddedOutput (Lit outSize) (Lit 0) (Lit outOffset)+            next++      -- ECPAIRING+      0x8 ->+        -- TODO: support symbolic variant+        forceConcreteBuf input "ECPAIR" $ \input' ->+          case EVM.Precompiled.execute 0x8 input' 32 of+          Nothing -> precompileFail+          Just output -> do+            let truncpaddedOutput = ConcreteBuf $ truncpadlit 32 output+            assign (#state % #stack) (Lit 1 : xs)+            assign (#state % #returndata) truncpaddedOutput+            copyBytesToMemory truncpaddedOutput (Lit outSize) (Lit 0) (Lit outOffset)+            next++      -- BLAKE2+      0x9 ->+        -- TODO: support symbolic variant+        forceConcreteBuf input "BLAKE2" $ \input' -> do+          case (BS.length input', 1 >= BS.last input') of+            (213, True) -> case EVM.Precompiled.execute 0x9 input' 64 of+              Just output -> do+                let truncpaddedOutput = ConcreteBuf $ truncpadlit 64 output+                assign (#state % #stack) (Lit 1 : xs)+                assign (#state % #returndata) truncpaddedOutput+                copyBytesToMemory truncpaddedOutput (Lit outSize) (Lit 0) (Lit outOffset)+                next+              Nothing -> precompileFail+            _ -> precompileFail++      _ -> notImplemented++truncpadlit :: Int -> ByteString -> ByteString+truncpadlit n xs = if m > n then BS.take n xs+                   else BS.append xs (BS.replicate (n - m) 0)+  where m = BS.length xs++lazySlice :: W256 -> W256 -> ByteString -> LS.ByteString+lazySlice offset size bs =+  let bs' = LS.take (num size) (LS.drop (num offset) (fromStrict bs))+  in bs' <> LS.replicate ((num size) - LS.length bs') 0++parseModexpLength :: ByteString -> (W256, W256, W256)+parseModexpLength input =+  let lenb = word $ LS.toStrict $ lazySlice  0 32 input+      lene = word $ LS.toStrict $ lazySlice 32 64 input+      lenm = word $ LS.toStrict $ lazySlice 64 96 input+  in (lenb, lene, lenm)++--- checks if a range of ByteString bs starting at offset and length size is all zeros.+isZero :: W256 -> W256 -> ByteString -> Bool+isZero offset size bs =+  LS.all (== 0) $+    LS.take (num size) $+      LS.drop (num offset) $+        fromStrict bs++asInteger :: LS.ByteString -> Integer+asInteger xs = if xs == mempty then 0+  else 256 * asInteger (LS.init xs)+      + num (LS.last xs)++-- * Opcode helper actions++noop :: Monad m => m ()+noop = pure ()++pushTo :: MonadState s m => Lens s s [a] [a] -> a -> m ()+pushTo f x = f %= (x :)++pushToSequence :: MonadState s m => Setter s s (Seq a) (Seq a) -> a -> m ()+pushToSequence f x = f %= (Seq.|> x)++getCodeLocation :: VM -> CodeLocation+getCodeLocation vm = (vm.state.contract, vm.state.pc)++branch :: CodeLocation -> Expr EWord -> (Bool -> EVM ()) -> EVM ()+branch loc cond continue = do+  pathconds <- use #constraints+  assign #result . Just . VMFailure . Query $ PleaseAskSMT cond pathconds choosePath+  where+    choosePath (Case v) = do+      assign #result Nothing+      pushTo #constraints $ if v then (cond ./= Lit 0) else (cond .== Lit 0)+      iteration <- use (#iterations % at loc % non 0)+      assign (#cache % #path % at (loc, iteration)) (Just v)+      assign (#iterations % at loc) (Just (iteration + 1))+      continue v+    -- Both paths are possible; we ask for more input+    choosePath Unknown =+      assign #result . Just . VMFailure . Choose . PleaseChoosePath cond $ choosePath . Case+    -- None of the paths are possible; fail this branch+    choosePath Inconsistent = vmError DeadPath+++-- | Construct RPC Query and halt execution until resolved+fetchAccount :: Addr -> (Contract -> EVM ()) -> EVM ()+fetchAccount addr continue =+  use (#env % #contracts % at addr) >>= \case+    Just c -> continue c+    Nothing ->+      use (#cache % #fetchedContracts % at addr) >>= \case+        Just c -> do+          assign (#env % #contracts % at addr) (Just c)+          continue c+        Nothing -> do+          assign (#result) . Just . VMFailure $ Query $+            PleaseFetchContract addr+              (\c -> do assign (#cache % #fetchedContracts % at addr) (Just c)+                        assign (#env % #contracts % at addr) (Just c)+                        assign #result Nothing+                        continue c)++accessStorage+  :: Addr+  -> Expr EWord+  -> (Expr EWord -> EVM ())+  -> EVM ()+accessStorage addr slot continue = do+  store <- (.env.storage) <$> get+  use (#env % #contracts % at addr) >>= \case+    Just c ->+      case readStorage (litAddr addr) slot store of+        -- Notice that if storage is symbolic, we always continue straight away+        Just x ->+          continue x+        Nothing ->+          if c.external then+            forceConcrete slot "cannot read symbolic slots via RPC" $ \litSlot -> do+              -- check if the slot is cached+              cachedStore <- (.cache.fetchedStorage) <$> get+              case Map.lookup (num addr) cachedStore >>= Map.lookup litSlot of+                Nothing -> mkQuery litSlot+                Just val -> continue (Lit val)+          else do+            -- TODO: is this actually needed?+            modifying (#env % #storage) (writeStorage (litAddr addr) slot (Lit 0))+            continue $ Lit 0+    Nothing ->+      fetchAccount addr $ \_ ->+        accessStorage addr slot continue+  where+      mkQuery s = assign #result . Just . VMFailure . Query $+                    PleaseFetchSlot addr s+                      (\x -> do+                          modifying (#cache % #fetchedStorage % ix (num addr)) (Map.insert s x)+                          modifying (#env % #storage) (writeStorage (litAddr addr) slot (Lit x))+                          assign #result Nothing+                          continue (Lit x))++accountExists :: Addr -> VM -> Bool+accountExists addr vm =+  case Map.lookup addr vm.env.contracts of+    Just c -> not (accountEmpty c)+    Nothing -> False++-- EIP 161+accountEmpty :: Contract -> Bool+accountEmpty c =+  case c.contractcode of+    RuntimeCode (ConcreteRuntimeCode "") -> True+    RuntimeCode (SymbolicRuntimeCode b) -> null b+    _ -> False+  && c.nonce == 0+  && c.balance  == 0++-- * How to finalize a transaction+finalize :: EVM ()+finalize = do+  let+    revertContracts  = use (#tx % #txReversion) >>= assign (#env % #contracts)+    revertSubstate   = assign (#tx % #substate) (SubState mempty mempty mempty mempty mempty)++  use #result >>= \case+    Nothing ->+      error "Finalising an unfinished tx."+    Just (VMFailure (EVM.Revert _)) -> do+      revertContracts+      revertSubstate+    Just (VMFailure _) -> do+      -- burn remaining gas+      assign (#state % #gas) 0+      revertContracts+      revertSubstate+    Just (VMSuccess output) -> do+      -- deposit the code from a creation tx+      pc' <- use (#state % #pc)+      creation <- use (#tx % #isCreate)+      createe  <- use (#state % #contract)+      createeExists <- (Map.member createe) <$> use (#env % #contracts)+      let onContractCode contractCode =+            when (creation && createeExists) $ replaceCode createe contractCode+      case output of+        ConcreteBuf bs ->+          onContractCode $ RuntimeCode (ConcreteRuntimeCode bs)+        _ ->+          case Expr.toList output of+            Nothing ->+              vmError $ UnexpectedSymbolicArg pc' "runtime code cannot have an abstract lentgh" [output]+            Just ops ->+              onContractCode $ RuntimeCode (SymbolicRuntimeCode ops)++  -- compute and pay the refund to the caller and the+  -- corresponding payment to the miner+  block        <- use #block+  tx           <- use #tx+  gasRemaining <- use (#state % #gas)++  let+    sumRefunds   = sum (snd <$> tx.substate.refunds)+    blockReward  = num (block.schedule.r_block)+    gasUsed      = tx.gaslimit - gasRemaining+    cappedRefund = min (quot gasUsed 5) (num sumRefunds)+    originPay    = (num $ gasRemaining + cappedRefund) * tx.gasprice+    minerPay     = tx.priorityFee * (num gasUsed)++  modifying (#env % #contracts)+     (Map.adjust (over #balance (+ originPay)) tx.origin)+  modifying (#env % #contracts)+     (Map.adjust (over #balance (+ minerPay)) block.coinbase)+  touchAccount block.coinbase++  -- pay out the block reward, recreating the miner if necessary+  preuse (#env % #contracts % ix block.coinbase) >>= \case+    Nothing -> modifying (#env % #contracts)+      (Map.insert block.coinbase (initialContract (EVM.RuntimeCode (ConcreteRuntimeCode ""))))+    Just _  -> noop+  modifying (#env % #contracts)+    (Map.adjust (over #balance (+ blockReward)) block.coinbase)++  -- perform state trie clearing (EIP 161), of selfdestructs+  -- and touched accounts. addresses are cleared if they have+  --    a) selfdestructed, or+  --    b) been touched and+  --    c) are empty.+  -- (see Yellow Paper "Accrued Substate")+  --+  -- remove any destructed addresses+  destroyedAddresses <- use (#tx % #substate % #selfdestructs)+  modifying (#env % #contracts)+    (Map.filterWithKey (\k _ -> (k `notElem` destroyedAddresses)))+  -- then, clear any remaining empty and touched addresses+  touchedAddresses <- use (#tx % #substate % #touchedAccounts)+  modifying (#env % #contracts)+    (Map.filterWithKey+      (\k a -> not ((k `elem` touchedAddresses) && accountEmpty a)))++-- | Loads the selected contract as the current contract to execute+loadContract :: Addr -> EVM ()+loadContract target =+  preuse (#env % #contracts % ix target % #contractcode) >>=+    \case+      Nothing ->+        error "Call target doesn't exist"+      Just targetCode -> do+        assign (#state % #contract) target+        assign (#state % #code)     targetCode+        assign (#state % #codeContract) target++limitStack :: Int -> EVM () -> EVM ()+limitStack n continue = do+  stk <- use (#state % #stack)+  if length stk + n > 1024+    then vmError EVM.StackLimitExceeded+    else continue++notStatic :: EVM () -> EVM ()+notStatic continue = do+  bad <- use (#state % #static)+  if bad+    then vmError StateChangeWhileStatic+    else continue++-- | Burn gas, failing if insufficient gas is available+burn :: Word64 -> EVM () -> EVM ()+burn n continue = do+  available <- use (#state % #gas)+  if n <= available+    then do+      #state % #gas %= (subtract n)+      #burned %= (+ n)+      continue+    else+      vmError (OutOfGas available n)++forceConcrete :: Expr EWord -> String -> (W256 -> EVM ()) -> EVM ()+forceConcrete n msg continue = case maybeLitWord n of+  Nothing -> do+    vm <- get+    vmError $ UnexpectedSymbolicArg vm.state.pc msg [n]+  Just c -> continue c++forceConcrete2 :: (Expr EWord, Expr EWord) -> String -> ((W256, W256) -> EVM ()) -> EVM ()+forceConcrete2 (n,m) msg continue = case (maybeLitWord n, maybeLitWord m) of+  (Just c, Just d) -> continue (c, d)+  _ -> do+    vm <- get+    vmError $ UnexpectedSymbolicArg vm.state.pc msg [n, m]++forceConcrete3 :: (Expr EWord, Expr EWord, Expr EWord) -> String -> ((W256, W256, W256) -> EVM ()) -> EVM ()+forceConcrete3 (k,n,m) msg continue = case (maybeLitWord k, maybeLitWord n, maybeLitWord m) of+  (Just c, Just d, Just f) -> continue (c, d, f)+  _ -> do+    vm <- get+    vmError $ UnexpectedSymbolicArg vm.state.pc msg [k, n, m]++forceConcrete4 :: (Expr EWord, Expr EWord, Expr EWord, Expr EWord) -> String -> ((W256, W256, W256, W256) -> EVM ()) -> EVM ()+forceConcrete4 (k,l,n,m) msg continue = case (maybeLitWord k, maybeLitWord l, maybeLitWord n, maybeLitWord m) of+  (Just b, Just c, Just d, Just f) -> continue (b, c, d, f)+  _ -> do+    vm <- get+    vmError $ UnexpectedSymbolicArg vm.state.pc msg [k, l, n, m]++forceConcrete5 :: (Expr EWord, Expr EWord, Expr EWord, Expr EWord, Expr EWord) -> String -> ((W256, W256, W256, W256, W256) -> EVM ()) -> EVM ()+forceConcrete5 (k,l,m,n,o) msg continue = case (maybeLitWord k, maybeLitWord l, maybeLitWord m, maybeLitWord n, maybeLitWord o) of+  (Just a, Just b, Just c, Just d, Just e) -> continue (a, b, c, d, e)+  _ -> do+    vm <- get+    vmError $ UnexpectedSymbolicArg vm.state.pc msg [k, l, m, n, o]++forceConcrete6 :: (Expr EWord, Expr EWord, Expr EWord, Expr EWord, Expr EWord, Expr EWord) -> String -> ((W256, W256, W256, W256, W256, W256) -> EVM ()) -> EVM ()+forceConcrete6 (k,l,m,n,o,p) msg continue = case (maybeLitWord k, maybeLitWord l, maybeLitWord m, maybeLitWord n, maybeLitWord o, maybeLitWord p) of+  (Just a, Just b, Just c, Just d, Just e, Just f) -> continue (a, b, c, d, e, f)+  _ -> do+    vm <- get+    vmError $ UnexpectedSymbolicArg vm.state.pc msg [k, l, m, n, o, p]++forceConcreteBuf :: Expr Buf -> String -> (ByteString -> EVM ()) -> EVM ()+forceConcreteBuf (ConcreteBuf b) _ continue = continue b+forceConcreteBuf b msg _ = do+    vm <- get+    vmError $ UnexpectedSymbolicArg vm.state.pc msg [b]++-- * Substate manipulation+refund :: Word64 -> EVM ()+refund n = do+  self <- use (#state % #contract)+  pushTo (#tx % #substate % #refunds) (self, n)++unRefund :: Word64 -> EVM ()+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 :: Addr -> EVM()+touchAccount = pushTo ((#tx % #substate) % #touchedAccounts)++selfdestruct :: Addr -> EVM()+selfdestruct = pushTo ((#tx % #substate) % #selfdestructs)++accessAndBurn :: Addr -> EVM () -> EVM ()+accessAndBurn x cont = do+  FeeSchedule {..} <- use (#block % #schedule)+  acc <- accessAccountForGas x+  let cost = if acc then g_warm_storage_read else g_cold_account_access+  burn cost cont++-- | 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 :: Addr -> EVM Bool+accessAccountForGas addr = do+  accessedAddrs <- use (#tx % #substate % #accessedAddresses)+  let accessed = member addr accessedAddrs+  assign (#tx % #substate % #accessedAddresses) (insert addr accessedAddrs)+  pure accessed++-- | 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 :: Addr -> Expr EWord -> EVM Bool+accessStorageForGas addr key = do+  accessedStrkeys <- use (#tx % #substate % #accessedStorageKeys)+  case maybeLitWord key of+    Just litword -> do+      let accessed = member (addr, litword) accessedStrkeys+      assign (#tx % #substate % #accessedStorageKeys) (insert (addr, litword) accessedStrkeys)+      pure accessed+    _ -> return False++-- * Cheat codes++-- The cheat code is 7109709ecfa91a80626ff3989d68f67f5b1dd12d.+-- Call this address using one of the cheatActions below to do+-- special things, e.g. changing the block timestamp. Beware that+-- these are necessarily hevm specific.+cheatCode :: Addr+cheatCode = num (keccak' "hevm cheat code")++cheat+  :: (?op :: Word8)+  => (W256, W256) -> (W256, W256)+  -> EVM ()+cheat (inOffset, inSize) (outOffset, outSize) = do+  mem <- use (#state % #memory)+  vm <- get+  let+    abi = readBytes 4 (Lit inOffset) mem+    input = readMemory (Lit $ inOffset + 4) (Lit $ inSize - 4) vm+  case maybeLitWord abi of+    Nothing -> vmError $ UnexpectedSymbolicArg vm.state.pc "symbolic cheatcode selector" [abi]+    Just (fromIntegral -> abi') ->+      case Map.lookup abi' cheatActions of+        Nothing ->+          vmError (BadCheatCode abi')+        Just action -> do+            action (Lit outOffset) (Lit outSize) input+            next+            push 1++type CheatAction = Expr EWord -> Expr EWord -> Expr Buf -> EVM ()++cheatActions :: Map FunctionSelector CheatAction+cheatActions =+  Map.fromList+    [ action "ffi(string[])" $+        \sig outOffset outSize input -> do+          vm <- get+          if vm.allowFFI then+            case decodeBuf [AbiArrayDynamicType AbiStringType] input of+              CAbi valsArr -> case valsArr of+                [AbiArrayDynamic AbiStringType strsV] ->+                  let+                    cmd = fmap+                            (\case+                              (AbiString a) -> unpack $ decodeUtf8 a+                              _ -> "")+                            (V.toList strsV)+                    cont bs = do+                      let encoded = ConcreteBuf bs+                      assign (#state % #returndata) encoded+                      copyBytesToMemory encoded outSize (Lit 0) outOffset+                      assign #result Nothing+                  in assign #result (Just . VMFailure . Query $ (PleaseDoFFI cmd cont))+                _ -> vmError (BadCheatCode sig)+              _ -> vmError (BadCheatCode sig)+          else+            let msg = encodeUtf8 "ffi disabled: run again with --ffi if you want to allow tests to call external scripts"+            in vmError . EVM.Revert . ConcreteBuf $+              abiMethod "Error(string)" (AbiTuple . V.fromList $ [AbiString msg]),++      action "warp(uint256)" $+        \sig _ _ input -> case decodeStaticArgs 0 1 input of+          [x]  -> assign (#block % #timestamp) x+          _ -> vmError (BadCheatCode sig),++      action "roll(uint256)" $+        \sig _ _ input -> case decodeStaticArgs 0 1 input of+          [x] -> forceConcrete x "cannot roll to a symbolic block number" (assign (#block % #number))+          _ -> vmError (BadCheatCode sig),++      action "store(address,bytes32,bytes32)" $+        \sig _ _ input -> case decodeStaticArgs 0 3 input of+          [a, slot, new] ->+            forceConcrete a "cannot store at a symbolic address" $ \(num -> a') ->+              fetchAccount a' $ \_ -> do+                modifying (#env % #storage) (writeStorage (litAddr a') slot new)+          _ -> vmError (BadCheatCode sig),++      action "load(address,bytes32)" $+        \sig outOffset _ input -> case decodeStaticArgs 0 2 input of+          [a, slot] ->+            forceConcrete a "cannot load from a symbolic address" $ \(num -> a') ->+              accessStorage a' slot $ \res -> do+                assign (#state % #returndata % word256At (Lit 0)) res+                assign (#state % #memory % word256At outOffset) res+          _ -> vmError (BadCheatCode sig),++      action "sign(uint256,bytes32)" $+        \sig outOffset _ input -> case decodeStaticArgs 0 2 input of+          [sk, hash] ->+            forceConcrete2 (sk, hash) "cannot sign symbolic data" $ \(sk', hash') -> do+              let (v,r,s) = EVM.Sign.sign hash' (toInteger sk')+                  encoded = encodeAbiValue $+                    AbiTuple (RegularVector.fromList+                      [ AbiUInt 8 $ num v+                      , AbiBytes 32 (word256Bytes r)+                      , AbiBytes 32 (word256Bytes s)+                      ])+              assign (#state % #returndata) (ConcreteBuf encoded)+              copyBytesToMemory (ConcreteBuf encoded) (Lit . num . BS.length $ encoded) (Lit 0) outOffset+          _ -> vmError (BadCheatCode sig),++      action "addr(uint256)" $+        \sig outOffset _ input -> case decodeStaticArgs 0 1 input of+          [sk] -> forceConcrete sk "cannot derive address for a symbolic key" $ \sk' -> do+            let a = EVM.Sign.deriveAddr $ num sk'+            case a of+              Nothing -> vmError (BadCheatCode sig)+              Just address -> do+                let expAddr = litAddr address+                assign (#state % #returndata % word256At (Lit 0)) expAddr+                assign (#state % #memory % word256At outOffset) expAddr+          _ -> vmError (BadCheatCode sig),++      action "prank(address)" $+        \sig _ _ input -> case decodeStaticArgs 0 1 input of+          [addr]  -> assign #overrideCaller (Expr.exprToAddr addr)+          _ -> vmError (BadCheatCode sig)++    ]+  where+    action s f = (abiKeccak s, f (abiKeccak s))++-- * General call implementation ("delegateCall")+-- note that the continuation is ignored in the precompile case+delegateCall+  :: (?op :: Word8)+  => Contract -> Word64 -> Expr EWord -> Expr EWord -> W256 -> W256 -> W256 -> W256 -> W256+  -> [Expr EWord]+  -> (Addr -> EVM ())+  -> EVM ()+delegateCall this gasGiven xTo xContext xValue xInOffset xInSize xOutOffset xOutSize xs continue =+  forceConcrete2 (xTo, xContext) "cannot delegateCall with symbolic target or context" $+    \((num -> xTo'), (num -> xContext')) ->+      if xTo' > 0 && xTo' <= 9+      then precompiledContract this gasGiven xTo' xContext' xValue xInOffset xInSize xOutOffset xOutSize xs+      else if xTo' == cheatCode then+        do+          assign (#state % #stack) xs+          cheat (xInOffset, xInSize) (xOutOffset, xOutSize)+      else+        callChecks this gasGiven xContext' xTo' xValue xInOffset xInSize xOutOffset xOutSize xs $+        \xGas -> do+          vm0 <- get+          fetchAccount xTo' $ \target ->+                burn xGas $ do+                  let newContext = CallContext+                                    { target    = xTo'+                                    , context   = xContext'+                                    , offset    = xOutOffset+                                    , size      = xOutSize+                                    , codehash  = target.codehash+                                    , callreversion = (vm0.env.contracts, vm0.env.storage)+                                    , subState  = vm0.tx.substate+                                    , abi =+                                        if xInSize >= 4+                                        then case unlit $ readBytes 4 (Lit xInOffset) vm0.state.memory+                                             of Nothing -> Nothing+                                                Just abi -> Just $ num abi+                                        else Nothing+                                    , calldata = (readMemory (Lit xInOffset) (Lit xInSize) vm0)+                                    }++                  pushTrace (FrameTrace newContext)+                  next+                  vm1 <- get++                  pushTo #frames $ Frame+                    { state = vm1.state { stack = xs }+                    , context = newContext+                    }++                  let clearInitCode = \case+                        (InitCode _ _) -> InitCode mempty mempty+                        a -> a++                  zoom #state $ do+                    assign #gas (num xGas)+                    assign #pc 0+                    assign #code (clearInitCode target.contractcode)+                    assign #codeContract xTo'+                    assign #stack mempty+                    assign #memory mempty+                    assign #memorySize 0+                    assign #returndata mempty+                    assign #calldata (copySlice (Lit xInOffset) (Lit 0) (Lit xInSize) vm0.state.memory mempty)++                  continue xTo'++-- -- * Contract creation++-- EIP 684+collision :: Maybe Contract -> Bool+collision c' = case c' of+  Just c -> c.nonce /= 0 || case c.contractcode of+    RuntimeCode (ConcreteRuntimeCode "") -> False+    RuntimeCode (SymbolicRuntimeCode b) -> not $ null b+    _ -> True+  Nothing -> False++create :: (?op :: Word8)+  => Addr -> Contract+  -> Word64 -> W256 -> [Expr EWord] -> Addr -> Expr Buf -> EVM ()+create self this xGas' xValue xs newAddr initCode = do+  vm0 <- get+  let xGas = num xGas'+  if this.nonce == num (maxBound :: Word64)+  then do+    assign (#state % #stack) (Lit 0 : xs)+    assign (#state % #returndata) mempty+    pushTrace $ ErrorTrace NonceOverflow+    next+  else if xValue > this.balance+  then do+    assign (#state % #stack) (Lit 0 : xs)+    assign (#state % #returndata) mempty+    pushTrace $ ErrorTrace $ BalanceTooLow xValue this.balance+    next+  else if length vm0.frames >= 1024+  then do+    assign (#state % #stack) (Lit 0 : xs)+    assign (#state % #returndata) mempty+    pushTrace $ ErrorTrace CallDepthLimitReached+    next+  else if collision $ Map.lookup newAddr vm0.env.contracts+  then burn xGas $ do+    assign (#state % #stack) (Lit 0 : xs)+    assign (#state % #returndata) mempty+    modifying (#env % #contracts % ix self % #nonce) succ+    next+  else burn xGas $ do+    touchAccount self+    touchAccount newAddr+    let+    -- unfortunately we have to apply some (pretty hacky)+    -- heuristics here to parse the unstructured buffer read+    -- from memory into a code and data section+    -- TODO: comment explaining whats going on here+    let contract' = do+          prefixLen <- Expr.concPrefix initCode+          prefix <- Expr.toList $ Expr.take (num prefixLen) initCode+          let sym = Expr.drop (num prefixLen) initCode+          conc <- mapM unlitByte prefix+          pure $ InitCode (BS.pack $ V.toList conc) sym+    case contract' of+      Nothing ->+        vmError $ UnexpectedSymbolicArg vm0.state.pc "initcode must have a concrete prefix" []+      Just c -> do+        let+          newContract = initialContract c+          newContext  =+            CreationContext { address   = newAddr+                            , codehash  = newContract.codehash+                            , createreversion = vm0.env.contracts+                            , substate  = vm0.tx.substate+                            }++        zoom (#env % #contracts) $ do+          oldAcc <- use (at newAddr)+          let oldBal = maybe 0 (.balance) oldAcc++          assign (at newAddr) (Just (newContract & #balance .~ oldBal))+          modifying (ix self % #nonce) succ++        let resetStorage = \case+              ConcreteStore s -> ConcreteStore (Map.delete (num newAddr) s)+              AbstractStore -> AbstractStore+              EmptyStore -> EmptyStore+              SStore {} -> error "trying to reset symbolic storage with writes in create"+              GVar _  -> error "unexpected global variable"++        modifying (#env % #storage) resetStorage+        modifying (#env % #origStorage) (Map.delete (num newAddr))++        transfer self newAddr xValue++        pushTrace (FrameTrace newContext)+        next+        vm1 <- get+        pushTo #frames $ Frame+          { context = newContext+          , state   = vm1.state { stack = xs }+          }++        assign #state $+          blankState+            & set #contract     newAddr+            & set #codeContract newAddr+            & set #code         c+            & set #callvalue    (Lit xValue)+            & set #caller       (litAddr self)+            & set #gas          xGas'++-- | Replace a contract's code, like when CREATE returns+-- from the constructor code.+replaceCode :: Addr -> ContractCode -> EVM ()+replaceCode target newCode =+  zoom (#env % #contracts % at target) $+    get >>= \case+      Just now -> case now.contractcode of+        InitCode _ _ ->+          put . Just $+            (initialContract newCode)+              { balance = now.balance+              , nonce = now.nonce+              }+        RuntimeCode _ ->+          error ("internal error: can't replace code of deployed contract " <> show target)+      Nothing ->+        error "internal error: can't replace code of nonexistent contract"++replaceCodeOfSelf :: ContractCode -> EVM ()+replaceCodeOfSelf newCode = do+  vm <- get+  replaceCode vm.state.contract newCode++resetState :: EVM ()+resetState =+  modify' $ \vm -> vm { result = Nothing+                      , frames = []+                      , state  = blankState }++-- * VM error implementation++vmError :: Error -> EVM ()+vmError e = finishFrame (FrameErrored e)++underrun :: EVM ()+underrun = vmError EVM.StackUnderrun++-- | A stack frame can be popped in three ways.+data FrameResult+  = FrameReturned (Expr Buf) -- ^ STOP, RETURN, or no more code+  | FrameReverted (Expr Buf) -- ^ REVERT+  | FrameErrored Error -- ^ Any other error+  deriving Show++-- | This function defines how to pop the current stack frame in either of+-- the ways specified by 'FrameResult'.+--+-- 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 :: FrameResult -> EVM ()+finishFrame how = do+  oldVm <- get++  case oldVm.frames of+    -- Is the current frame the only one?+    [] -> do+      case how of+          FrameReturned output -> assign #result . Just $ VMSuccess output+          FrameReverted buffer -> assign #result . Just $ VMFailure (EVM.Revert buffer)+          FrameErrored e       -> assign #result . Just $ VMFailure e+      finalize++    -- Are there some remaining frames?+    nextFrame : remainingFrames -> do++      -- Insert a debug trace.+      insertTrace $+        case how of+          FrameErrored e ->+            ErrorTrace e+          FrameReverted e ->+            ErrorTrace (EVM.Revert e)+          FrameReturned output ->+            ReturnTrace output nextFrame.context+      -- Pop to the previous level of the debug trace stack.+      popTrace++      -- Pop the top frame.+      assign #frames remainingFrames+      -- Install the state of the frame to which we shall return.+      assign #state nextFrame.state++      -- When entering a call, the gas allowance is counted as burned+      -- in advance; this unburns the remainder and adds it to the+      -- parent frame.+      let remainingGas = oldVm.state.gas+          reclaimRemainingGasAllowance = do+            modifying #burned (subtract remainingGas)+            modifying (#state % #gas) (+ remainingGas)++      -- Now dispatch on whether we were creating or calling,+      -- and whether we shall return, revert, or error (six cases).+      case nextFrame.context of++        -- Were we calling?+        CallContext _ _ (Lit -> outOffset) (Lit -> outSize) _ _ _ reversion substate' -> do++          -- Excerpt K.1. from the yellow paper:+          -- K.1. Deletion of an Account Despite Out-of-gas.+          -- At block 2675119, in the transaction 0xcf416c536ec1a19ed1fb89e4ec7ffb3cf73aa413b3aa9b77d60e4fd81a4296ba,+          -- an account at address 0x03 was called and an out-of-gas occurred during the call.+          -- Against the equation (197), this added 0x03 in the set of touched addresses, and this transaction turned σ[0x03] into ∅.++          -- In other words, we special case address 0x03 and keep it in the set of touched accounts during revert+          touched <- use (#tx % #substate % #touchedAccounts)++          let+            substate'' = over #touchedAccounts (maybe id cons (find (3 ==) touched)) substate'+            (contractsReversion, storageReversion) = reversion+            revertContracts = assign (#env % #contracts) contractsReversion+            revertStorage = assign (#env % #storage) storageReversion+            revertSubstate  = assign (#tx % #substate) substate''++          case how of+            -- Case 1: Returning from a call?+            FrameReturned output -> do+              assign (#state % #returndata) output+              copyCallBytesToMemory output outSize (Lit 0) outOffset+              reclaimRemainingGasAllowance+              push 1++            -- Case 2: Reverting during a call?+            FrameReverted output -> do+              revertContracts+              revertStorage+              revertSubstate+              assign (#state % #returndata) output+              copyCallBytesToMemory output outSize (Lit 0) outOffset+              reclaimRemainingGasAllowance+              push 0++            -- Case 3: Error during a call?+            FrameErrored _ -> do+              revertContracts+              revertStorage+              revertSubstate+              assign (#state % #returndata) mempty+              push 0+        -- Or were we creating?+        CreationContext _ _ reversion substate' -> do+          creator <- use (#state % #contract)+          let+            createe = oldVm.state.contract+            revertContracts = assign (#env % #contracts) reversion'+            revertSubstate  = assign (#tx % #substate) substate'++            -- persist the nonce through the reversion+            reversion' = (Map.adjust (over #nonce (+ 1)) creator) reversion++          case how of+            -- Case 4: Returning during a creation?+            FrameReturned output -> do+              let onContractCode contractCode = do+                    replaceCode createe contractCode+                    assign (#state % #returndata) mempty+                    reclaimRemainingGasAllowance+                    push (num createe)+              case output of+                ConcreteBuf bs ->+                  onContractCode $ RuntimeCode (ConcreteRuntimeCode bs)+                _ ->+                  case Expr.toList output of+                    Nothing -> vmError $+                      UnexpectedSymbolicArg+                        oldVm.state.pc+                        "runtime code cannot have an abstract length"+                        [output]+                    Just newCode -> do+                      onContractCode $ RuntimeCode (SymbolicRuntimeCode newCode)++            -- Case 5: Reverting during a creation?+            FrameReverted output -> do+              revertContracts+              revertSubstate+              assign (#state % #returndata) output+              reclaimRemainingGasAllowance+              push 0++            -- Case 6: Error during a creation?+            FrameErrored _ -> do+              revertContracts+              revertSubstate+              assign (#state % #returndata) mempty+              push 0+++-- * Memory helpers++accessUnboundedMemoryRange+  :: Word64+  -> Word64+  -> EVM ()+  -> EVM ()+accessUnboundedMemoryRange _ 0 continue = continue+accessUnboundedMemoryRange f l continue = do+  m0 <- num <$> use (#state % #memorySize)+  fees <- gets (.block.schedule)+  let m1 = 32 * ceilDiv (max m0 (f + l)) 32+  burn (memoryCost fees m1 - memoryCost fees m0) $ do+    assign (#state % #memorySize) m1+    continue++accessMemoryRange+  :: W256+  -> W256+  -> EVM ()+  -> EVM ()+accessMemoryRange _ 0 continue = continue+accessMemoryRange f l continue =+  case (,) <$> toWord64 f <*> toWord64 l of+    Nothing -> vmError IllegalOverflow+    Just (f64, l64) ->+      if f64 + l64 < l64+        then vmError IllegalOverflow+        else accessUnboundedMemoryRange f64 l64 continue++accessMemoryWord+  :: W256 -> EVM () -> EVM ()+accessMemoryWord x = accessMemoryRange x 32++copyBytesToMemory+  :: Expr Buf -> Expr EWord -> Expr EWord -> Expr EWord -> EVM ()+copyBytesToMemory bs size xOffset yOffset =+  if size == Lit 0 then noop+  else do+    mem <- use (#state % #memory)+    assign (#state % #memory) $+      copySlice xOffset yOffset size bs mem++copyCallBytesToMemory+  :: Expr Buf -> Expr EWord -> Expr EWord -> Expr EWord -> EVM ()+copyCallBytesToMemory bs size xOffset yOffset =+  if size == Lit 0 then noop+  else do+    mem <- use (#state % #memory)+    assign (#state % #memory) $+      copySlice xOffset yOffset (Expr.min size (bufLength bs)) bs mem++readMemory :: Expr EWord -> Expr EWord -> VM -> Expr Buf+readMemory offset size vm = copySlice offset (Lit 0) size vm.state.memory mempty++-- * Tracing++withTraceLocation :: TraceData -> EVM Trace+withTraceLocation x = do+  vm <- get+  let this = fromJust $ currentContract vm+  pure Trace+    { tracedata = x+    , contract = this+    , opIx = fromMaybe 0 $ this.opIxMap Vector.!? vm.state.pc+    }++pushTrace :: TraceData -> EVM ()+pushTrace x = do+  trace <- withTraceLocation x+  modifying #traces $+    \t -> Zipper.children $ Zipper.insert (Node trace []) t++insertTrace :: TraceData -> EVM ()+insertTrace x = do+  trace <- withTraceLocation x+  modifying #traces $+    \t -> Zipper.nextSpace $ Zipper.insert (Node trace []) t++popTrace :: EVM ()+popTrace =+  modifying #traces $+    \t -> case Zipper.parent t of+            Nothing -> error "internal error (trace root)"+            Just t' -> Zipper.nextSpace t'++zipperRootForest :: Zipper.TreePos Zipper.Empty a -> Forest a+zipperRootForest z =+  case Zipper.parent z of+    Nothing -> Zipper.toForest z+    Just z' -> zipperRootForest (Zipper.nextSpace z')++traceForest :: VM -> Forest Trace+traceForest vm = zipperRootForest vm.traces++traceTopLog :: [Expr Log] -> EVM ()+traceTopLog [] = noop+traceTopLog ((LogEntry addr bytes topics) : _) = do+  trace <- withTraceLocation (EventTrace addr bytes topics)+  modifying #traces $+    \t -> Zipper.nextSpace (Zipper.insert (Node trace []) t)+traceTopLog ((GVar _) : _) = error "unexpected global variable"++-- * Stack manipulation++push :: W256 -> EVM ()+push = pushSym . Lit++pushSym :: Expr EWord -> EVM ()+pushSym x = #state % #stack %= (x :)++stackOp1+  :: (?op :: Word8)+  => Word64+  -> ((Expr EWord) -> (Expr EWord))+  -> EVM ()+stackOp1 cost f =+  use (#state % #stack) >>= \case+    x:xs ->+      burn cost $ do+        next+        let !y = f x+        (#state % #stack) .= y : xs+    _ ->+      underrun++stackOp2+  :: (?op :: Word8)+  => Word64+  -> (((Expr EWord), (Expr EWord)) -> (Expr EWord))+  -> EVM ()+stackOp2 cost f =+  use (#state % #stack) >>= \case+    x:y:xs ->+      burn cost $ do+        next+        (#state % #stack) .= f (x, y) : xs+    _ ->+      underrun++stackOp3+  :: (?op :: Word8)+  => Word64+  -> (((Expr EWord), (Expr EWord), (Expr EWord)) -> (Expr EWord))+  -> EVM ()+stackOp3 cost f =+  use (#state % #stack) >>= \case+    x:y:z:xs ->+      burn cost $ do+      next+      (#state % #stack) .= f (x, y, z) : xs+    _ ->+      underrun++-- * Bytecode data functions++use' :: (VM -> a) -> EVM a+use' f = do+  vm <- get+  pure (f vm)++checkJump :: Int -> [Expr EWord] -> EVM ()+checkJump x xs = do+  theCode <- use (#state % #code)+  self <- use (#state % #codeContract)+  codeOps <- preuse (#env % #contracts % ix self % #codeOps)+  opIxMap <- preuse (#env % #contracts % ix self % #opIxMap)+  case (codeOps, opIxMap) of+    (Just co, Just opMap) -> do+      let op = case theCode of+            InitCode ops _ -> BS.indexMaybe ops x+            RuntimeCode (ConcreteRuntimeCode ops) -> BS.indexMaybe ops x+            RuntimeCode (SymbolicRuntimeCode ops) -> ops V.!? x >>= unlitByte+      case op of+        Nothing -> vmError EVM.BadJumpDestination+        Just b ->+          if 0x5b == b && OpJumpdest == snd (co RegularVector.! (opMap Vector.! num x))+             then do+               #state % #stack .= xs+               #state % #pc .= num x+             else+               vmError EVM.BadJumpDestination+    (_, _) -> error "Internal Error: self not found in current contracts"+++opSize :: Word8 -> Int+opSize x | x >= 0x60 && x <= 0x7f = num x - 0x60 + 2+opSize _                          = 1++--  i of the resulting vector contains the operation index for+-- the program counter value i.  This is needed because source map+-- entries are per operation, not per byte.+mkOpIxMap :: ContractCode -> Vector Int+mkOpIxMap (InitCode conc _)+  = Vector.create $ Vector.new (BS.length conc) >>= \v ->+      -- Loop over the byte string accumulating a vector-mutating action.+      -- This is somewhat obfuscated, but should be fast.+      let (_, _, _, m) = BS.foldl' (go v) (0 :: Word8, 0, 0, pure ()) conc+      in m >> pure v+      where+        -- concrete case+        go v (0, !i, !j, !m) x | x >= 0x60 && x <= 0x7f =+          {- Start of PUSH op. -} (x - 0x60 + 1, i + 1, j,     m >> Vector.write v i j)+        go v (1, !i, !j, !m) _ =+          {- End of PUSH op. -}   (0,            i + 1, j + 1, m >> Vector.write v i j)+        go v (0, !i, !j, !m) _ =+          {- Other op. -}         (0,            i + 1, j + 1, m >> Vector.write v i j)+        go v (n, !i, !j, !m) _ =+          {- PUSH data. -}        (n - 1,        i + 1, j,     m >> Vector.write v i j)++mkOpIxMap (RuntimeCode (ConcreteRuntimeCode ops)) =+  mkOpIxMap (InitCode ops mempty) -- a bit hacky++mkOpIxMap (RuntimeCode (SymbolicRuntimeCode ops))+  = Vector.create $ Vector.new (length ops) >>= \v ->+      let (_, _, _, m) = foldl (go v) (0, 0, 0, pure ()) (stripBytecodeMetadataSym $ V.toList ops)+      in m >> pure v+      where+        go v (0, !i, !j, !m) x = case unlitByte x of+          Just x' -> if x' >= 0x60 && x' <= 0x7f+            -- start of PUSH op --+                     then (x' - 0x60 + 1, i + 1, j,     m >> Vector.write v i j)+            -- other data --+                     else (0,             i + 1, j + 1, m >> Vector.write v i j)+          _ -> error $ "cannot analyze symbolic code:\nx: " <> show x <> " i: " <> show i <> " j: " <> show j++        go v (1, !i, !j, !m) _ =+          {- End of PUSH op. -}   (0,            i + 1, j + 1, m >> Vector.write v i j)+        go v (n, !i, !j, !m) _ =+          {- PUSH data. -}        (n - 1,        i + 1, j,     m >> Vector.write v i j)+++vmOp :: VM -> Maybe Op+vmOp vm =+  let i  = vm ^. #state % #pc+      code' = vm ^. #state % #code+      (op, pushdata) = case code' of+        InitCode xs' _ ->+          (BS.index xs' i, fmap LitByte $ BS.unpack $ BS.drop i xs')+        RuntimeCode (ConcreteRuntimeCode xs') ->+          (BS.index xs' i, fmap LitByte $ BS.unpack $ BS.drop i xs')+        RuntimeCode (SymbolicRuntimeCode xs') ->+          ( fromMaybe (error "unexpected symbolic code") . unlitByte $ xs' V.! i , V.toList $ V.drop i xs')+  in if (opslen code' < i)+     then Nothing+     else Just (readOp op pushdata)++vmOpIx :: VM -> Maybe Int+vmOpIx vm =+  do self <- currentContract vm+     self.opIxMap Vector.!? vm.state.pc++-- Maps operation indicies into a pair of (bytecode index, operation)+mkCodeOps :: ContractCode -> RegularVector.Vector (Int, Op)+mkCodeOps contractCode =+  let l = case contractCode of+            InitCode bytes _ ->+              LitByte <$> (BS.unpack bytes)+            RuntimeCode (ConcreteRuntimeCode ops) ->+              LitByte <$> (BS.unpack $ stripBytecodeMetadata ops)+            RuntimeCode (SymbolicRuntimeCode ops) ->+              stripBytecodeMetadataSym $ V.toList ops+  in RegularVector.fromList . toList $ go 0 l+  where+    go !i !xs =+      case uncons xs of+        Nothing ->+          mempty+        Just (x, xs') ->+          let x' = fromMaybe (error "unexpected symbolic code argument") $ unlitByte x+              j = opSize x'+          in (i, readOp x' xs') Seq.<| go (i + j) (drop j xs)++-- * Gas cost calculation helpers++-- Gas cost function for CALL, transliterated from the Yellow Paper.+costOfCall+  :: FeeSchedule Word64+  -> Bool -> W256 -> Word64 -> Word64 -> Addr+  -> EVM (Word64, Word64)+costOfCall (FeeSchedule {..}) recipientExists xValue availableGas xGas target = do+  acc <- accessAccountForGas target+  let call_base_gas = if acc then g_warm_storage_read else g_cold_account_access+      c_new = if not recipientExists && xValue /= 0+            then g_newaccount+            else 0+      c_xfer = if xValue /= 0  then num g_callvalue else 0+      c_extra = call_base_gas + c_xfer + c_new+      c_gascap =  if availableGas >= c_extra+                  then min xGas (allButOne64th (availableGas - c_extra))+                  else xGas+      c_callgas = if xValue /= 0 then c_gascap + g_callstipend else c_gascap+  pure (c_gascap + c_extra, c_callgas)++-- Gas cost of create, including hash cost if needed+costOfCreate+  :: FeeSchedule Word64+  -> Word64 -> W256 -> (Word64, Word64)+costOfCreate (FeeSchedule {..}) availableGas hashSize =+  (createCost + initGas, initGas)+  where+    createCost = g_create + hashCost+    hashCost   = g_sha3word * ceilDiv (num hashSize) 32+    initGas    = allButOne64th (availableGas - createCost)++concreteModexpGasFee :: ByteString -> Word64+concreteModexpGasFee input =+  if lenb < num (maxBound :: Word32) &&+     (lene < num (maxBound :: Word32) || (lenb == 0 && lenm == 0)) &&+     lenm < num (maxBound :: Word64)+  then+    max 200 ((multiplicationComplexity * iterCount) `div` 3)+  else+    maxBound -- TODO: this is not 100% correct, return Nothing on overflow+  where+    (lenb, lene, lenm) = parseModexpLength input+    ez = isZero (96 + lenb) lene input+    e' = word $ LS.toStrict $+      lazySlice (96 + lenb) (min 32 lene) input+    nwords :: Word64+    nwords = ceilDiv (num $ max lenb lenm) 8+    multiplicationComplexity = nwords * nwords+    iterCount' :: Word64+    iterCount' | lene <= 32 && ez = 0+               | lene <= 32 = num (log2 e')+               | e' == 0 = 8 * (num lene - 32)+               | otherwise = num (log2 e') + 8 * (num lene - 32)+    iterCount = max iterCount' 1++-- Gas cost of precompiles+costOfPrecompile :: FeeSchedule Word64 -> Addr -> Expr Buf -> Word64+costOfPrecompile (FeeSchedule {..}) precompileAddr input =+  let errorDynamicSize = error "precompile input cannot have a dynamic size"+      inputLen = case input of+                   ConcreteBuf bs -> fromIntegral $ BS.length bs+                   AbstractBuf _ -> errorDynamicSize+                   buf -> case bufLength buf of+                            Lit l -> num l -- TODO: overflow+                            _ -> errorDynamicSize+  in case precompileAddr of+    -- ECRECOVER+    0x1 -> 3000+    -- SHA2-256+    0x2 -> num $ (((inputLen + 31) `div` 32) * 12) + 60+    -- RIPEMD-160+    0x3 -> num $ (((inputLen + 31) `div` 32) * 120) + 600+    -- IDENTITY+    0x4 -> num $ (((inputLen + 31) `div` 32) * 3) + 15+    -- MODEXP+    0x5 -> case input of+             ConcreteBuf i -> concreteModexpGasFee i+             _ -> error "Unsupported symbolic modexp gas calc "+    -- ECADD+    0x6 -> g_ecadd+    -- ECMUL+    0x7 -> g_ecmul+    -- ECPAIRING+    0x8 -> (inputLen `div` 192) * g_pairing_point + g_pairing_base+    -- BLAKE2+    0x9 -> case input of+             ConcreteBuf i -> g_fround * (num $ asInteger $ lazySlice 0 4 i)+             _ -> error "Unsupported symbolic blake2 gas calc"+    _ -> error ("unimplemented precompiled contract " ++ show precompileAddr)++-- Gas cost of memory expansion+memoryCost :: FeeSchedule Word64 -> Word64 -> Word64+memoryCost FeeSchedule{..} byteCount =+  let+    wordCount = ceilDiv byteCount 32+    linearCost = g_memory * wordCount+    quadraticCost = div (wordCount * wordCount) 512+  in+    linearCost + quadraticCost++hashcode :: ContractCode -> Expr EWord+hashcode (InitCode ops args) = keccak $ (ConcreteBuf ops) <> args+hashcode (RuntimeCode (ConcreteRuntimeCode ops)) = keccak (ConcreteBuf ops)+hashcode (RuntimeCode (SymbolicRuntimeCode ops)) = keccak . Expr.fromList $ ops++-- | The length of the code ignoring any constructor args.+-- This represents the region that can contain executable opcodes+opslen :: ContractCode -> Int+opslen (InitCode ops _) = BS.length ops+opslen (RuntimeCode (ConcreteRuntimeCode ops)) = BS.length ops+opslen (RuntimeCode (SymbolicRuntimeCode ops)) = length ops++-- | The length of the code including any constructor args.+-- This can return an abstract value+codelen :: ContractCode -> Expr EWord+codelen c@(InitCode {}) = bufLength $ toBuf c+codelen (RuntimeCode (ConcreteRuntimeCode ops)) = Lit . num $ BS.length ops+codelen (RuntimeCode (SymbolicRuntimeCode ops)) = Lit . num $ length ops++toBuf :: ContractCode -> Expr Buf+toBuf (InitCode ops args) = ConcreteBuf ops <> args+toBuf (RuntimeCode (ConcreteRuntimeCode ops)) = ConcreteBuf ops+toBuf (RuntimeCode (SymbolicRuntimeCode ops)) = Expr.fromList ops++codeloc :: EVM CodeLocation+codeloc = do+  vm <- get+  pure (vm.state.contract, vm.state.pc)++-- * Arithmetic++ceilDiv :: (Num a, Integral a) => a -> a -> a+ceilDiv m n = div (m + n - 1) n++allButOne64th :: (Num a, Integral a) => a -> a+allButOne64th n = n - div n 64++log2 :: FiniteBits b => b -> Int+log2 x = finiteBitSize x - 1 - countLeadingZeros x
src/EVM/ABI.hs view
@@ -343,11 +343,12 @@ decodeAbiValue = runGet . getAbi  selector :: Text -> BS.ByteString-selector s = BSLazy.toStrict . runPut $ putWord32be (abiKeccak (encodeUtf8 s))+selector s = BSLazy.toStrict . runPut $+  putWord32be (abiKeccak (encodeUtf8 s)).unFunctionSelector  abiMethod :: Text -> AbiValue -> BS.ByteString abiMethod s args = BSLazy.toStrict . runPut $ do-  putWord32be (abiKeccak (encodeUtf8 s))+  putWord32be (abiKeccak (encodeUtf8 s)).unFunctionSelector   putAbi args  parseTypeName :: Vector AbiType -> Text -> Maybe AbiType
src/EVM/Concrete.hs view
@@ -5,9 +5,8 @@ import EVM.RLP import EVM.Types -import Control.Lens    ((^?), ix) import Data.Bits       (Bits (..), shiftR)-import Data.ByteString (ByteString)+import Data.ByteString (ByteString, (!?)) import Data.Maybe      (fromMaybe) import Data.Word       (Word8) @@ -18,7 +17,7 @@   word (padRight 32 (BS.drop i bs))  readByteOrZero :: Int -> ByteString -> Word8-readByteOrZero i bs = fromMaybe 0 (bs ^? ix i)+readByteOrZero i bs = fromMaybe 0 (bs !? i)  byteStringSliceWithDefaultZeroes :: Int -> Int -> ByteString -> ByteString byteStringSliceWithDefaultZeroes offset size bs =
src/EVM/Dapp.hs view
@@ -5,7 +5,7 @@ import EVM.Concrete import EVM.Debug (srcMapCodePos) import EVM.Solidity-import EVM.Types (W256, abiKeccak, keccak', Addr, regexMatches, unlit, unlitByte)+import EVM.Types (W256, abiKeccak, keccak', Addr, regexMatches, unlit, unlitByte, FunctionSelector)  import Control.Arrow ((>>>)) import Data.Aeson (Value)@@ -20,7 +20,6 @@ import Data.Text (Text, isPrefixOf, pack, unpack) import Data.Text.Encoding (encodeUtf8) import Data.Vector qualified as V-import Data.Word (Word32)  data DappInfo = DappInfo   { root       :: FilePath@@ -29,7 +28,7 @@   , solcByCode :: [(Code, SolcContract)] -- for contracts with `immutable` vars.   , sources    :: SourceCache   , unitTests  :: [(Text, [(Test, [AbiType])])]-  , abiMap     :: Map Word32 Method+  , abiMap     :: Map FunctionSelector Method   , eventMap   :: Map W256 Event   , errorMap   :: Map W256 SolError   , astIdMap   :: Map Int Value@@ -98,7 +97,7 @@ -- Tests beginning with "test" are interpreted as concrete tests, whereas -- tests beginning with "prove" are interpreted as symbolic tests. -unitTestMarkerAbi :: Word32+unitTestMarkerAbi :: FunctionSelector unitTestMarkerAbi = abiKeccak (encodeUtf8 "IS_TEST()")  findAllUnitTests :: [SolcContract] -> [(Text, [(Test, [AbiType])])]@@ -141,12 +140,12 @@ extractSig (InvariantTest sig) = sig  traceSrcMap :: DappInfo -> Trace -> Maybe SrcMap-traceSrcMap dapp trace = srcMap dapp trace._traceContract trace._traceOpIx+traceSrcMap dapp trace = srcMap dapp trace.contract trace.opIx  srcMap :: DappInfo -> Contract -> Int -> Maybe SrcMap srcMap dapp contr opIndex = do   sol <- findSrc contr dapp-  case contr._contractcode of+  case contr.contractcode of     (InitCode _ _) ->       Seq.lookup opIndex sol.creationSrcmap     (RuntimeCode _) ->@@ -154,10 +153,10 @@  findSrc :: Contract -> DappInfo -> Maybe SolcContract findSrc c dapp = do-  hash <- unlit c._codehash+  hash <- unlit c.codehash   case Map.lookup hash dapp.solcByHash of     Just (_, v) -> Just v-    Nothing -> lookupCode c._contractcode dapp+    Nothing -> lookupCode c.contractcode dapp   lookupCode :: ContractCode -> DappInfo -> Maybe SolcContract
src/EVM/Debug.hs view
@@ -2,13 +2,13 @@  module EVM.Debug where -import EVM          (Contract, nonce, balance, bytecode, codehash)-import EVM.Solidity (SrcMap, srcMapFile, srcMapOffset, srcMapLength, SourceCache(..))+import EVM          (Contract, bytecode)+import EVM.Solidity (SrcMap(..), SourceCache(..)) import EVM.Types    (Addr) import EVM.Expr     (bufLength)  import Control.Arrow   (second)-import Control.Lens+import Optics.Core import Data.ByteString (ByteString) import Data.Map        (Map) import Data.Text       (Text)@@ -32,9 +32,9 @@ prettyContract c =   object     [ (text "codesize", text . show $ (bufLength (c ^. bytecode)))-    , (text "codehash", text (show (c ^. codehash)))-    , (text "balance", int (fromIntegral (c ^. balance)))-    , (text "nonce", int (fromIntegral (c ^. nonce)))+    , (text "codehash", text (show (c ^. #codehash)))+    , (text "balance", int (fromIntegral (c ^. #balance)))+    , (text "nonce", int (fromIntegral (c ^. #nonce)))     ]  prettyContracts :: Map Addr Contract -> Doc@@ -45,12 +45,12 @@  srcMapCodePos :: SourceCache -> SrcMap -> Maybe (Text, Int) srcMapCodePos cache sm =-  fmap (second f) $ cache.files ^? ix sm.srcMapFile+  fmap (second f) $ cache.files ^? ix sm.file   where-    f v = ByteString.count 0xa (ByteString.take (sm.srcMapOffset - 1) v) + 1+    f v = ByteString.count 0xa (ByteString.take sm.offset v) + 1  srcMapCode :: SourceCache -> SrcMap -> Maybe ByteString srcMapCode cache sm =-  fmap f $ cache.files ^? ix sm.srcMapFile+  fmap f $ cache.files ^? ix sm.file   where-    f (_, v) = ByteString.take (min 80 sm.srcMapLength) (ByteString.drop sm.srcMapOffset v)+    f (_, v) = ByteString.take (min 80 sm.length) (ByteString.drop sm.offset v)
− src/EVM/Demand.hs
@@ -1,13 +0,0 @@-module EVM.Demand (demand) where--import Control.DeepSeq (NFData, force)-import Control.Exception.Base (evaluate)-import Control.Monad.IO.Class (MonadIO, liftIO)---- | This is an easy way to force full evaluation of a value inside of--- the IO monad, being essentially just the composition of @evaluate@--- and @force@.-demand :: (MonadIO m, NFData a) => a -> m ()-demand x = do-  _ <- liftIO (evaluate (force x))-  return ()
src/EVM/Dev.hs view
@@ -365,44 +365,44 @@   where     contractCode = RuntimeCode (ConcreteRuntimeCode bs)     c = Contract-      { _contractcode = contractCode-      , _balance      = 0-      , _nonce        = 0-      , _codehash     = keccak (ConcreteBuf bs)-      , _opIxMap      = mkOpIxMap contractCode-      , _codeOps      = mkCodeOps contractCode-      , _external     = False+      { contractcode = contractCode+      , balance      = 0+      , nonce        = 0+      , codehash     = keccak (ConcreteBuf bs)+      , opIxMap      = mkOpIxMap contractCode+      , codeOps      = mkCodeOps contractCode+      , external     = False       }     vm = makeVm $ VMOpts-      { EVM.vmoptContract      = c-      , EVM.vmoptCalldata      = (AbstractBuf "txdata", [])-      , EVM.vmoptValue         = CallValue 0-      , EVM.vmoptAddress       = Addr 0xffffffffffffffff-      , EVM.vmoptCaller        = Lit 0-      , EVM.vmoptOrigin        = Addr 0xffffffffffffffff-      , EVM.vmoptGas           = 0xffffffffffffffff-      , EVM.vmoptGaslimit      = 0xffffffffffffffff-      , EVM.vmoptStorageBase   = Symbolic-      , EVM.vmoptBaseFee       = 0-      , EVM.vmoptPriorityFee   = 0-      , EVM.vmoptCoinbase      = 0-      , EVM.vmoptNumber        = 0-      , EVM.vmoptTimestamp     = Var "timestamp"-      , EVM.vmoptBlockGaslimit = 0-      , EVM.vmoptGasprice      = 0-      , EVM.vmoptMaxCodeSize   = 0xffffffff-      , EVM.vmoptPrevRandao    = 420-      , EVM.vmoptSchedule      = FeeSchedule.berlin-      , EVM.vmoptChainId       = 1-      , EVM.vmoptCreate        = False-      , EVM.vmoptTxAccessList  = mempty-      , EVM.vmoptAllowFFI      = False+      { contract       = c+      , calldata       = (AbstractBuf "txdata", [])+      , value          = CallValue 0+      , address        = Addr 0xffffffffffffffff+      , caller         = Lit 0+      , origin         = Addr 0xffffffffffffffff+      , gas            = 0xffffffffffffffff+      , gaslimit       = 0xffffffffffffffff+      , initialStorage = AbstractStore+      , baseFee        = 0+      , priorityFee    = 0+      , coinbase       = 0+      , number         = 0+      , timestamp      = Var "timestamp"+      , blockGaslimit  = 0+      , gasprice       = 0+      , maxCodeSize    = 0xffffffff+      , prevRandao     = 420+      , schedule       = FeeSchedule.berlin+      , chainId        = 1+      , create         = False+      , txAccessList   = mempty+      , allowFFI       = False       }   -- | Builds the Expr for the given evm bytecode object buildExpr :: SolverGroup -> ByteString -> IO (Expr End)-buildExpr solvers bs = evalStateT (interpret (Fetch.oracle solvers Nothing) Nothing Nothing runExpr) (initVm bs)+buildExpr solvers bs = interpret (Fetch.oracle solvers Nothing) Nothing Nothing (initVm bs) runExpr  dai :: IO ByteString dai = do
src/EVM/Exec.hs view
@@ -7,7 +7,7 @@  import qualified EVM.FeeSchedule as FeeSchedule -import Control.Lens+import Optics.Core import Control.Monad.Trans.State.Strict (get, State) import Data.ByteString (ByteString) import Data.Maybe (isNothing)@@ -19,43 +19,43 @@ vmForEthrunCreation :: ByteString -> VM vmForEthrunCreation creationCode =   (makeVm $ VMOpts-    { vmoptContract = initialContract (InitCode creationCode mempty)-    , vmoptCalldata = mempty-    , vmoptValue = (Lit 0)-    , vmoptStorageBase = Concrete-    , vmoptAddress = createAddress ethrunAddress 1-    , vmoptCaller = litAddr ethrunAddress-    , vmoptOrigin = ethrunAddress-    , vmoptCoinbase = 0-    , vmoptNumber = 0-    , vmoptTimestamp = (Lit 0)-    , vmoptBlockGaslimit = 0-    , vmoptGasprice = 0-    , vmoptPrevRandao = 42069-    , vmoptGas = 0xffffffffffffffff-    , vmoptGaslimit = 0xffffffffffffffff-    , vmoptBaseFee = 0-    , vmoptPriorityFee = 0-    , vmoptMaxCodeSize = 0xffffffff-    , vmoptSchedule = FeeSchedule.berlin-    , vmoptChainId = 1-    , vmoptCreate = False-    , vmoptTxAccessList = mempty-    , vmoptAllowFFI = False-    }) & set (env . contracts . at ethrunAddress)+    { contract = initialContract (InitCode creationCode mempty)+    , calldata = mempty+    , value = (Lit 0)+    , initialStorage = EmptyStore+    , address = createAddress ethrunAddress 1+    , caller = litAddr ethrunAddress+    , origin = ethrunAddress+    , coinbase = 0+    , number = 0+    , timestamp = (Lit 0)+    , blockGaslimit = 0+    , gasprice = 0+    , prevRandao = 42069+    , gas = 0xffffffffffffffff+    , gaslimit = 0xffffffffffffffff+    , baseFee = 0+    , priorityFee = 0+    , maxCodeSize = 0xffffffff+    , schedule = FeeSchedule.berlin+    , chainId = 1+    , create = False+    , txAccessList = mempty+    , allowFFI = False+    }) & set (#env % #contracts % at ethrunAddress)              (Just (initialContract (RuntimeCode (ConcreteRuntimeCode ""))))  exec :: State VM VMResult exec = do   vm <- get-  case vm._result of+  case vm.result of     Nothing -> exec1 >> exec     Just r -> pure r  run :: State VM VM run = do   vm <- get-  case vm._result of+  case vm.result of     Nothing -> exec1 >> run     Just _ -> pure vm @@ -64,7 +64,7 @@   where     go i = do       vm <- get-      if p vm && isNothing vm._result+      if p vm && isNothing vm.result         then do           go $! (i + 1)       else
src/EVM/Expr.hs view
@@ -15,7 +15,7 @@ import Data.Maybe import Data.List -import Control.Lens (lens)+import Optics.Core  import EVM.Types import EVM.Traversals@@ -215,19 +215,18 @@     then val     else readByte i src readByte i@(Lit x) (WriteWord (Lit idx) val src)-  = if idx <= x && x <= idx + 31+  = if x - idx < 32     then case val of            (Lit _) -> indexWord (Lit $ x - idx) val            _ -> IndexWord (Lit $ x - idx) val     else readByte i src readByte i@(Lit x) (CopySlice (Lit srcOffset) (Lit dstOffset) (Lit size) src dst)-  = if dstOffset <= x && x < (dstOffset + size)+  = if x - dstOffset < size     then readByte (Lit $ x - (dstOffset - srcOffset)) src     else readByte i dst readByte i@(Lit x) buf@(CopySlice _ (Lit dstOffset) (Lit size) _ dst)-  -- the byte we are trying to read is compeletely outside of the sliced reegion-  -- we check that there is no overflow and that addresses do not wrap around-  = if (x < dstOffset || x >= dstOffset + size) && (dstOffset <= dstOffset + size)+  -- the byte we are trying to read is compeletely outside of the sliced region+  = if x - dstOffset >= size     then readByte i dst     else ReadByte (Lit x) buf @@ -249,7 +248,7 @@   | idx == idx' = val   | otherwise = case (idx, idx') of     (Lit i, Lit i') ->-      if i >= i' + 32 || i + 32 <= i'+      if i' - i >= 32 && i' - i <= (maxBound :: W256) - 31       -- the region we are trying to read is completely outside of the WriteWord       then readWord idx buf       -- the region we are trying to read partially overlaps the WriteWord@@ -259,10 +258,9 @@     _ -> readWordFromBytes idx b readWord (Lit idx) b@(CopySlice (Lit srcOff) (Lit dstOff) (Lit size) src dst)   -- the region we are trying to read is enclosed in the sliced region-  | idx >= dstOff && idx + 32 <= dstOff + size = readWord (Lit $ srcOff + (idx - dstOff)) src-  -- the region we are trying to read is compeletely outside of the sliced reegion-  -- we check that there is no overflow and that addresses do not wrap around-  | (idx >= dstOff + size || idx + 32 <= dstOff) && (dstOff<= dstOff + size) = readWord (Lit idx) dst+  | (idx - dstOff) < size && 32 <= size - (idx - dstOff) = readWord (Lit $ srcOff + (idx - dstOff)) src+  -- the region we are trying to read is compeletely outside of the sliced region+  | (idx - dstOff) >= size && (idx - dstOff) <= (maxBound :: W256) - 31 = readWord (Lit idx) dst   -- the region we are trying to read partially overlaps the sliced region   | otherwise = readWordFromBytes (Lit idx) b readWord i b = readWordFromBytes i b@@ -468,15 +466,11 @@       b <- Map.lookup a bufEnv       go l b -word256At-  :: Functor f-  => Expr EWord -> (Expr EWord -> f (Expr EWord))-  -> Expr Buf -> f (Expr Buf)+word256At :: Expr EWord -> Lens (Expr Buf) (Expr Buf) (Expr EWord) (Expr EWord) word256At i = lens getter setter where   getter = readWord i   setter m x = writeWord i x m - -- | Returns the first n bytes of buf take :: W256 -> Expr Buf -> Expr Buf take n = slice (Lit 0) (Lit n)@@ -530,34 +524,36 @@ -- | Removes any irrelevant writes when reading from a buffer simplifyReads :: Expr a -> Expr a simplifyReads = \case-  ReadWord (Lit idx) b -> readWord (Lit idx) (stripWrites idx (idx + 31) b)-  ReadByte (Lit idx) b -> readByte (Lit idx) (stripWrites idx idx b)+  ReadWord (Lit idx) b -> readWord (Lit idx) (stripWrites idx 32 b)+  ReadByte (Lit idx) b -> readByte (Lit idx) (stripWrites idx 1 b)   a -> a  -- | Strips writes from the buffer that can be statically determined to be out of range -- TODO: are the bounds here correct? I think there might be some off by one mistakes... stripWrites :: W256 -> W256 -> Expr Buf -> Expr Buf-stripWrites bottom top = \case+stripWrites off size = \case   AbstractBuf s -> AbstractBuf s-  ConcreteBuf b -> ConcreteBuf $ BS.take (num top+1) b+  ConcreteBuf b -> ConcreteBuf $ if off <= off + size+                                 then BS.take (num $ off+size) b+                                 else b   WriteByte (Lit idx) v prev-    -> if idx < bottom || idx > top-       then stripWrites bottom top prev-       else WriteByte (Lit idx) v (stripWrites bottom top prev)+    -> if idx - off >= size+       then stripWrites off size prev+       else WriteByte (Lit idx) v (stripWrites off size prev)   -- TODO: handle partial overlaps   WriteWord (Lit idx) v prev-    -> if idx + 31 < bottom || idx > top-       then stripWrites bottom top prev-       else WriteWord (Lit idx) v (stripWrites bottom top prev)-  CopySlice (Lit srcOff) (Lit dstOff) (Lit size) src dst-    -> if dstOff + size < bottom || dstOff > top-       then stripWrites bottom top dst-       else CopySlice (Lit srcOff) (Lit dstOff) (Lit size)-                      (stripWrites srcOff (srcOff + size) src)-                      (stripWrites bottom top dst)-  WriteByte i v prev -> WriteByte i v (stripWrites bottom top prev)-  WriteWord i v prev -> WriteWord i v (stripWrites bottom top prev)-  CopySlice srcOff dstOff size src dst -> CopySlice srcOff dstOff size src dst+    -> if idx - off >= size && idx - off <= (maxBound :: W256) - 31+       then stripWrites off size prev+       else WriteWord (Lit idx) v (stripWrites off size prev)+  CopySlice (Lit srcOff) (Lit dstOff) (Lit size') src dst+    -> if dstOff - off >= size && dstOff - off <= (maxBound :: W256) - size' - 1+       then stripWrites off size dst+       else CopySlice (Lit srcOff) (Lit dstOff) (Lit size')+                      (stripWrites srcOff size' src)+                      (stripWrites off size dst)+  WriteByte i v prev -> WriteByte i v (stripWrites off size prev)+  WriteWord i v prev -> WriteWord i v (stripWrites off size prev)+  CopySlice srcOff dstOff size' src dst -> CopySlice srcOff dstOff size' src dst   GVar _ ->  error "unexpected GVar in stripWrites"  @@ -792,8 +788,14 @@     -- Double NOT is a no-op, since it's a bitwise inversion     go (EVM.Types.Not (EVM.Types.Not a)) = a +    -- Some trivial min / max eliminations     go (Max (Lit 0) a) = a     go (Min (Lit 0) _) = Lit 0++    -- 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 a = a 
src/EVM/Facts.hs view
@@ -33,7 +33,7 @@   ) where  import EVM          (VM, Contract, Cache)-import EVM          (balance, nonce, storage, bytecode, env, contracts, cache, fetchedStorage, fetchedContracts)+import EVM          (bytecode) import EVM.Types    (Addr, W256, Expr(..), num) import EVM.Expr     (writeStorage, litAddr) @@ -41,7 +41,9 @@  import Prelude hiding (Word) -import Control.Lens    (view, set, at, ix, (&), over, assign)+import Optics.Core+import Optics.State+ import Control.Monad.State.Strict (execState, when) import Data.ByteString (ByteString) import Data.Ord        (comparing)@@ -112,15 +114,15 @@ contractFacts a x store = case view bytecode x of   ConcreteBuf b ->     storageFacts a store ++-    [ BalanceFact a x._balance-    , NonceFact   a x._nonce+    [ BalanceFact a x.balance+    , NonceFact   a x.nonce     , CodeFact    a b     ]   _ ->     -- here simply ignore storing the bytecode     storageFacts a store ++-    [ BalanceFact a x._balance-    , NonceFact   a x._nonce+    [ BalanceFact a x.balance+    , NonceFact   a x.nonce     ]  @@ -136,13 +138,13 @@  cacheFacts :: Cache -> Set Fact cacheFacts c = Set.fromList $ do-  (k, v) <- Map.toList c._fetchedContracts-  contractFacts k v c._fetchedStorage+  (k, v) <- Map.toList c.fetchedContracts+  contractFacts k v c.fetchedStorage  vmFacts :: VM -> Set Fact vmFacts vm = Set.fromList $ do-  (k, v) <- Map.toList vm._env._contracts-  case vm._env._storage of+  (k, v) <- Map.toList vm.env.contracts+  case vm.env.storage of     EmptyStore -> contractFacts k v Map.empty     ConcreteStore s -> contractFacts k v s     _ -> error "cannot serialize an abstract store"@@ -158,30 +160,30 @@ apply1 vm fact =   case fact of     CodeFact    {..} -> flip execState vm $ do-      assign (env . contracts . at addr) (Just (EVM.initialContract (EVM.RuntimeCode (EVM.ConcreteRuntimeCode blob))))-      when (vm._state._contract == addr) $ EVM.loadContract addr+      assign (#env % #contracts % at addr) (Just (EVM.initialContract (EVM.RuntimeCode (EVM.ConcreteRuntimeCode blob))))+      when (vm.state.contract == addr) $ EVM.loadContract addr     StorageFact {..} ->-      vm & over (env . storage) (writeStorage (litAddr addr) (Lit which) (Lit what))+      vm & over (#env % #storage) (writeStorage (litAddr addr) (Lit which) (Lit what))     BalanceFact {..} ->-      vm & set (env . contracts . ix addr . balance) what+      vm & set (#env % #contracts % ix addr % #balance) what     NonceFact   {..} ->-      vm & set (env . contracts . ix addr . nonce) what+      vm & set (#env % #contracts % ix addr % #nonce) what  apply2 :: VM -> Fact -> VM apply2 vm fact =   case fact of     CodeFact    {..} -> flip execState vm $ do-      assign (cache . fetchedContracts . at addr) (Just (EVM.initialContract (EVM.RuntimeCode (EVM.ConcreteRuntimeCode blob))))-      when (vm._state._contract == addr) $ EVM.loadContract addr+      assign (#cache % #fetchedContracts % at addr) (Just (EVM.initialContract (EVM.RuntimeCode (EVM.ConcreteRuntimeCode blob))))+      when (vm.state.contract == addr) $ EVM.loadContract addr     StorageFact {..} -> let-        store = vm._cache._fetchedStorage+        store = vm.cache.fetchedStorage         ctrct = Map.findWithDefault Map.empty (num addr) store       in-        vm & set (cache . fetchedStorage) (Map.insert (num addr) (Map.insert which what ctrct) store)+        vm & set (#cache % #fetchedStorage) (Map.insert (num addr) (Map.insert which what ctrct) store)     BalanceFact {..} ->-      vm & set (cache . fetchedContracts . ix addr . balance) what+      vm & set (#cache % #fetchedContracts % ix addr % #balance) what     NonceFact   {..} ->-      vm & set (cache . fetchedContracts . ix addr . nonce) what+      vm & set (#cache % #fetchedContracts % ix addr % #nonce) what  -- Sort facts in the right order for `apply1` to work. instance Ord Fact where
src/EVM/Facts/Git.hs view
@@ -10,7 +10,7 @@  import EVM.Facts (Fact (..), File (..), Path (..), Data (..), fileToFact, factToFile) -import Control.Lens+import Optics.Core import Data.Set   (Set) import Data.Maybe (catMaybes) @@ -45,5 +45,5 @@ loadFacts :: RepoAt -> IO (Set Fact) loadFacts (RepoAt src) =   fmap-    (prune . Set.map (fileToFact . view (from fileRepr)))+    (prune . Set.map (fileToFact . review fileRepr))     (Git.load src)
src/EVM/Fetch.hs view
@@ -9,15 +9,16 @@ import EVM.Types    (Addr, W256, hexText, Expr(Lit), Expr(..), Prop(..), (.&&), (./=)) import EVM.SMT import EVM.Solvers-import EVM          (EVM, Contract, Block, initialContract, nonce, balance, external)+import EVM          (EVM, Contract, Block, initialContract) import qualified EVM.FeeSchedule as FeeSchedule  import qualified EVM -import Control.Lens hiding ((.=))+import Optics.Core+ import Control.Monad.Trans.Maybe import Data.Aeson hiding (Error)-import Data.Aeson.Lens+import Data.Aeson.Optics import qualified Data.ByteString as BS import Data.Text (Text, unpack, pack) import Data.Maybe (fromMaybe)@@ -85,39 +86,49 @@   x <- case q of     QueryCode addr -> do         m <- f (rpc "eth_getCode" [toRPC addr, toRPC n])-        return $ hexText . view _String <$> m+        pure $ do+          t <- preview _String <$> m+          hexText <$> t     QueryNonce addr -> do         m <- f (rpc "eth_getTransactionCount" [toRPC addr, toRPC n])-        return $ readText . view _String <$> m+        pure $ do+          t <- preview _String <$> m+          readText <$> t     QueryBlock -> do       m <- f (rpc "eth_getBlockByNumber" [toRPC n, toRPC False])       return $ m >>= parseBlock     QueryBalance addr -> do         m <- f (rpc "eth_getBalance" [toRPC addr, toRPC n])-        return $ readText . view _String <$> m+        pure $ do+          t <- preview _String <$> m+          readText <$> t     QuerySlot addr slot -> do         m <- f (rpc "eth_getStorageAt" [toRPC addr, toRPC slot, toRPC n])-        return $ readText . view _String <$> m+        pure $ do+          t <- preview _String <$> m+          readText <$> t     QueryChainId -> do         m <- f (rpc "eth_chainId" [toRPC n])-        return $ readText . view _String <$> m+        pure $ do+          t <- preview _String <$> m+          readText <$> t   return x   parseBlock :: (AsValue s, Show s) => s -> Maybe EVM.Block parseBlock j = do-  coinbase   <- readText <$> j ^? key "miner" . _String-  timestamp  <- Lit . readText <$> j ^? key "timestamp" . _String-  number     <- readText <$> j ^? key "number" . _String-  gasLimit   <- readText <$> j ^? key "gasLimit" . _String+  coinbase   <- readText <$> j ^? key "miner" % _String+  timestamp  <- Lit . readText <$> j ^? key "timestamp" % _String+  number     <- readText <$> j ^? key "number" % _String+  gasLimit   <- readText <$> j ^? key "gasLimit" % _String   let-   baseFee = readText <$> j ^? key "baseFeePerGas" . _String+   baseFee = readText <$> j ^? key "baseFeePerGas" % _String    -- It seems unclear as to whether this field should still be called mixHash or renamed to prevRandao    -- According to https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4399.md it should be renamed    -- but alchemy is still returning mixHash-   mixhash = readText <$> j ^? key "mixHash" . _String-   prevRandao = readText <$> j ^? key "prevRandao" . _String-   difficulty = readText <$> j ^? key "difficulty" . _String+   mixhash = readText <$> j ^? key "mixHash" % _String+   prevRandao = readText <$> j ^? key "prevRandao" % _String+   difficulty = readText <$> j ^? key "difficulty" % _String    prd = case (prevRandao, mixhash, difficulty) of      (Just p, _, _) -> p      (Nothing, Just mh, Just 0x0) -> mh@@ -129,7 +140,7 @@ fetchWithSession :: Text -> Session -> Value -> IO (Maybe Value) fetchWithSession url sess x = do   r <- asValue =<< Session.post sess (unpack url) x-  return (r ^? responseBody . key "result")+  return (r ^? (lensVL responseBody) % key "result")  fetchContractWithSession   :: BlockNumber -> Text -> Addr -> Session -> IO (Maybe Contract)@@ -144,9 +155,9 @@    return $     initialContract (EVM.RuntimeCode (EVM.ConcreteRuntimeCode theCode))-      & set nonce    theNonce-      & set balance  theBalance-      & set external True+      & set #nonce    theNonce+      & set #balance  theBalance+      & set #external True  fetchSlotWithSession   :: BlockNumber -> Text -> Session -> Addr -> W256 -> IO (Maybe W256)@@ -159,19 +170,24 @@   fetchQuery n (fetchWithSession url sess) QueryBlock  fetchBlockFrom :: BlockNumber -> Text -> IO (Maybe Block)-fetchBlockFrom n url =-  Session.withAPISession-    (fetchBlockWithSession n url)+fetchBlockFrom n url = do+  sess <- Session.newAPISession+  fetchBlockWithSession n url sess  fetchContractFrom :: BlockNumber -> Text -> Addr -> IO (Maybe Contract)-fetchContractFrom n url addr =-  Session.withAPISession-    (fetchContractWithSession n url addr)+fetchContractFrom n url addr = do+  sess <- Session.newAPISession+  fetchContractWithSession n url addr sess  fetchSlotFrom :: BlockNumber -> Text -> Addr -> W256 -> IO (Maybe W256)-fetchSlotFrom n url addr slot =-  Session.withAPISession-    (\s -> fetchSlotWithSession n url s addr slot)+fetchSlotFrom n url addr slot = do+  sess <- Session.newAPISession+  fetchSlotWithSession n url sess addr slot++fetchChainIdFrom :: Text -> IO (Maybe W256)+fetchChainIdFrom url = do+  sess <- Session.newAPISession+  fetchQuery Latest (fetchWithSession url sess) QueryChainId  http :: Natural -> Maybe Natural -> BlockNumber -> Text -> Fetcher http smtjobs smttimeout n url q =
src/EVM/Format.hs view
@@ -35,10 +35,10 @@ import EVM.Hexdump (prettyHex) import EVM.Solidity (SolcContract(..), Method(..), contractName, abiMap) import EVM.Types (maybeLitWord, W256(..),num, word, Expr(..), EType(..), Addr,-  ByteStringS(..), Error(..))+  ByteStringS(..), Error(..), FunctionSelector)  import Control.Arrow ((>>>))-import Control.Lens (preview, ix, _2)+import Optics.Core import Data.Binary.Get (runGetOrFail) import Data.Bits (shiftR) import Data.ByteString (ByteString)@@ -48,7 +48,6 @@ import Data.Char qualified as Char import Data.DoubleWord (signedWord) import Data.Foldable (toList)-import Data.Functor ((<&>)) import Data.Map qualified as Map import Data.Maybe (catMaybes, fromMaybe, fromJust) import Data.Text (Text, pack, unpack, intercalate, dropEnd, splitOn)@@ -56,7 +55,6 @@ import Data.Text.Encoding (decodeUtf8, decodeUtf8') import Data.Tree.View (showTree) import Data.Vector (Vector)-import Data.Word (Word32) import Numeric (showHex)  data Signedness = Signed | Unsigned@@ -107,9 +105,9 @@       name = case Map.lookup addr contracts of         Nothing -> ""         Just contract ->-          let hash = maybeLitWord contract._codehash+          let hash = maybeLitWord contract.codehash           in case hash of-               Just h -> maybeContractName' (preview (ix h . _2) dappinfo.solcByHash)+               Just h -> maybeContractName' (preview (ix h % _2) dappinfo.solcByHash)                Nothing -> ""   in     name <> "@" <> (pack $ show addr)@@ -192,14 +190,14 @@  showTrace :: DappInfo -> VM -> Trace -> Text showTrace dapp vm trace =-  let ?context = DappContext { info = dapp, env = vm._env._contracts }+  let ?context = DappContext { info = dapp, env = vm.env.contracts }   in let     pos =       case showTraceLocation dapp trace of         Left x -> " \x1b[1m" <> x <> "\x1b[0m"         Right x -> " \x1b[1m(" <> x <> ")\x1b[0m"     fullAbiMap = dapp.abiMap-  in case trace._traceData of+  in case trace.tracedata of     EventTrace _ bytes topics ->       let logn = mconcat             [ "\x1b[36m"@@ -241,7 +239,7 @@                       --     bytes             data                       -- ) anonymous;                       let-                        sig = fromIntegral $ shiftR topic 224 :: Word32+                        sig = fromIntegral $ shiftR topic 224 :: FunctionSelector                         usr = case maybeLitWord t2 of                           Just w ->                             pack $ show (fromIntegral w :: Addr)@@ -298,7 +296,7 @@       t     FrameTrace (CreationContext addr (Lit hash) _ _ ) -> -- FIXME: irrefutable pattern       "create "-      <> maybeContractName (preview (ix hash . _2) dapp.solcByHash)+      <> maybeContractName (preview (ix hash % _2) dapp.solcByHash)       <> "@" <> pack (show addr)       <> pos     FrameTrace (CreationContext addr _ _ _ ) ->@@ -311,7 +309,7 @@                      then "call "                      else "delegatecall "           hash' = fromJust $ maybeLitWord hash-      in case preview (ix hash' . _2) dapp.solcByHash of+      in case preview (ix hash' % _2) dapp.solcByHash of         Nothing ->           calltype             <> pack (show target)
src/EVM/SMT.hs view
@@ -48,11 +48,11 @@  -- variable names in SMT that we want to get values for data CexVars = CexVars-  { calldataV :: [Text]-  , buffersV :: Map Text (Expr EWord) -- buffers and guesses at their maximum size-  , storeReads :: [(Expr EWord, Expr EWord)] -- a list of relevant store reads-  , blockContextV :: [Text]-  , txContextV :: [Text]+  { calldata     :: [Text]+  , buffers      :: Map Text (Expr EWord) -- buffers and guesses at their maximum size+  , storeReads   :: [(Expr EWord, Expr EWord)] -- a list of relevant store reads+  , blockContext :: [Text]+  , txContext    :: [Text]   }   deriving (Eq, Show) @@ -61,11 +61,11 @@  instance Monoid CexVars where     mempty = CexVars-      { calldataV = mempty-      , buffersV = mempty+      { calldata = mempty+      , buffers = mempty       , storeReads = mempty-      , blockContextV = mempty-      , txContextV = mempty+      , blockContext = mempty+      , txContext = mempty       }  -- | A model for a buffer, either in it's compressed form (for storing parsed@@ -97,7 +97,7 @@ flattenBufs :: SMTCex -> Maybe SMTCex flattenBufs cex = do   bs <- mapM collapse cex.buffers-  pure $ cex { buffers = bs}+  pure $ cex{ buffers = bs }  -- | Attemps to collapse a compressed buffer representation down to a flattened one collapse :: BufModel -> Maybe BufModel@@ -161,7 +161,7 @@   <> readAssumes   <> SMT2 [""] mempty   <> SMT2 (fmap (\p -> "(assert " <> p <> ")") encs) mempty-  <> SMT2 [] mempty{storeReads = storageReads}+  <> SMT2 [] mempty{ storeReads = storageReads }    where     (ps_elim, bufs, stores) = eliminateProps ps@@ -319,8 +319,8 @@ declareBufs :: [Prop] -> BufEnv -> StoreEnv -> SMT2 declareBufs props bufEnv storeEnv = SMT2 ("; buffers" : fmap declareBuf allBufs <> ("; buffer lengths" : fmap declareLength allBufs)) cexvars   where-    cexvars = mempty{buffersV = discoverMaxReads props bufEnv storeEnv}-    allBufs = fmap fromLazyText $ Map.keys cexvars.buffersV+    cexvars = (mempty :: CexVars){ buffers = discoverMaxReads props bufEnv storeEnv }+    allBufs = fmap fromLazyText $ Map.keys cexvars.buffers     declareBuf n = "(declare-const " <> n <> " (Array (_ BitVec 256) (_ BitVec 8)))"     declareLength n = "(declare-const " <> n <> "_length" <> " (_ BitVec 256))" @@ -329,21 +329,21 @@ declareVars names = SMT2 (["; variables"] <> fmap declare names) cexvars   where     declare n = "(declare-const " <> n <> " (_ BitVec 256))"-    cexvars = mempty{calldataV = fmap toLazyText names}+    cexvars = mempty{ calldata = fmap toLazyText names }   declareFrameContext :: [Builder] -> SMT2 declareFrameContext names = SMT2 (["; frame context"] <> fmap declare names) cexvars   where     declare n = "(declare-const " <> n <> " (_ BitVec 256))"-    cexvars = mempty{txContextV = fmap toLazyText names}+    cexvars = (mempty :: CexVars){ txContext = fmap toLazyText names }   declareBlockContext :: [Builder] -> SMT2 declareBlockContext names = SMT2 (["; block context"] <> fmap declare names) cexvars   where     declare n = "(declare-const " <> n <> " (_ BitVec 256))"-    cexvars = mempty{blockContextV = fmap toLazyText names}+    cexvars = (mempty :: CexVars){ blockContext = fmap toLazyText names }   prelude :: SMT2
src/EVM/Solidity.hs view
@@ -42,12 +42,14 @@ import EVM.ABI import EVM.Types +import Optics.Core+import Optics.Operators.Unsafe+ import Control.Applicative-import Control.Lens hiding (Indexed, (.=)) import Control.Monad import Data.Aeson hiding (json) import Data.Aeson.Types-import Data.Aeson.Lens+import Data.Aeson.Optics import Data.Aeson.Key qualified as Key import Data.Aeson.KeyMap qualified as KeyMap import Data.Scientific@@ -73,7 +75,7 @@ import Data.Text.IO (readFile, writeFile) import Data.Vector (Vector) import Data.Vector qualified as Vector-import Data.Word (Word8, Word32)+import Data.Word (Word8) import GHC.Generics (Generic) import Prelude hiding (readFile, writeFile) import System.IO hiding (readFile, writeFile)@@ -125,7 +127,7 @@   , creationCode     :: ByteString   , contractName     :: Text   , constructorInputs :: [(Text, AbiType)]-  , abiMap           :: Map Word32 Method+  , abiMap           :: Map FunctionSelector Method   , eventMap         :: Map W256 Event   , errorMap         :: Map W256 SolError   , immutableReferences :: Map W256 [Reference]@@ -177,11 +179,11 @@   deriving (Show, Eq, Ord, Generic)  data SrcMap = SM {-  srcMapOffset :: {-# UNPACK #-} !Int,-  srcMapLength :: {-# UNPACK #-} !Int,-  srcMapFile   :: {-# UNPACK #-} !Int,-  srcMapJump   :: JumpType,-  srcMapModifierDepth :: {-# UNPACK #-} !Int+  offset        :: {-# UNPACK #-} !Int,+  length        :: {-# UNPACK #-} !Int,+  file          :: {-# UNPACK #-} !Int,+  jump          :: JumpType,+  modifierDepth :: {-# UNPACK #-} !Int } deriving (Show, Eq, Ord, Generic)  data SrcMapParseState@@ -281,7 +283,7 @@   (json, path) <- yul' src   let f = (json ^?! key "contracts") ^?! key (Key.fromText path)       c = f ^?! key (Key.fromText $ if Text.null contract then "object" else contract)-      bytecode = c ^?! key "evm" ^?! key "bytecode" ^?! key "object" . _String+      bytecode = c ^?! key "evm" ^?! key "bytecode" ^?! key "object" % _String   pure $ toCode <$> (Just bytecode)  yulRuntime :: Text -> Text -> IO (Maybe ByteString)@@ -289,7 +291,7 @@   (json, path) <- yul' src   let f = (json ^?! key "contracts") ^?! key (Key.fromText path)       c = f ^?! key (Key.fromText $ if Text.null contract then "object" else contract)-      bytecode = c ^?! key "evm" ^?! key "deployedBytecode" ^?! key "object" . _String+      bytecode = c ^?! key "evm" ^?! key "deployedBytecode" ^?! key "object" % _String   pure $ toCode <$> (Just bytecode)  solidity :: Text -> Text -> IO (Maybe ByteString)@@ -323,26 +325,26 @@ -- deprecate me soon readCombinedJSON :: Text -> Maybe (Map Text SolcContract, Map Text Value, [(Text, Maybe ByteString)]) readCombinedJSON json = do-  contracts <- f . KeyMap.toHashMapText <$> (json ^? key "contracts" . _Object)-  sources <- toList . fmap (view _String) <$> json ^? key "sourceList" . _Array-  return (contracts, Map.fromList (HMap.toList asts), [ (x, Nothing) | x <- sources])+  contracts <- f . KeyMap.toHashMapText <$> (json ^? key "contracts" % _Object)+  sources <- toList . fmap (preview _String) <$> json ^? key "sourceList" % _Array+  return (contracts, Map.fromList (HMap.toList asts), [ (x, Nothing) | Just x <- sources])   where-    asts = KeyMap.toHashMapText $ fromMaybe (error "JSON lacks abstract syntax trees.") (json ^? key "sources" . _Object)+    asts = KeyMap.toHashMapText $ fromMaybe (error "JSON lacks abstract syntax trees.") (json ^? key "sources" % _Object)     f x = Map.fromList . HMap.toList $ HMap.mapWithKey g x     g s x =       let-        theRuntimeCode = toCode (x ^?! key "bin-runtime" . _String)-        theCreationCode = toCode (x ^?! key "bin" . _String)+        theRuntimeCode = toCode (x ^?! key "bin-runtime" % _String)+        theCreationCode = toCode (x ^?! key "bin" % _String)         abis = toList $ case (x ^?! key "abi") ^? _Array of                  Just v -> v                                       -- solc >= 0.8-                 Nothing -> (x ^?! key "abi" . _String) ^?! _Array -- solc <  0.8+                 Nothing -> (x ^?! key "abi" % _String) ^?! _Array -- solc <  0.8       in SolcContract {         runtimeCode      = theRuntimeCode,         creationCode     = theCreationCode,         runtimeCodehash  = keccak' (stripBytecodeMetadata theRuntimeCode),         creationCodehash = keccak' (stripBytecodeMetadata theCreationCode),-        runtimeSrcmap    = force "internal error: srcmap-runtime" (makeSrcMaps (x ^?! key "srcmap-runtime" . _String)),-        creationSrcmap   = force "internal error: srcmap" (makeSrcMaps (x ^?! key "srcmap" . _String)),+        runtimeSrcmap    = force "internal error: srcmap-runtime" (makeSrcMaps (x ^?! key "srcmap-runtime" % _String)),+        creationSrcmap   = force "internal error: srcmap" (makeSrcMaps (x ^?! key "srcmap" % _String)),         contractName = s,         constructorInputs = mkConstructor abis,         abiMap       = mkAbiMap abis,@@ -354,9 +356,9 @@  readStdJSON :: Text -> Maybe (Map Text SolcContract, Map Text Value, [(Text, Maybe ByteString)]) readStdJSON json = do-  contracts <- KeyMap.toHashMapText <$> json ^? key "contracts" . _Object+  contracts <- KeyMap.toHashMapText <$> json ^? key "contracts" % _Object   -- TODO: support the general case of "urls" and "content" in the standard json-  sources <- KeyMap.toHashMapText <$>  json ^? key "sources" . _Object+  sources <- KeyMap.toHashMapText <$>  json ^? key "sources" % _Object   let asts = force "JSON lacks abstract syntax trees." . preview (key "ast") <$> sources       contractMap = f contracts       contents src = (src, encodeUtf8 <$> HMap.lookup src (mconcat $ Map.elems $ snd <$> contractMap))@@ -364,28 +366,30 @@   where     f :: (AsValue s) => HMap.HashMap Text s -> (Map Text (SolcContract, (HMap.HashMap Text Text)))     f x = Map.fromList . (concatMap g) . HMap.toList $ x-    g (s, x) = h s <$> HMap.toList (KeyMap.toHashMapText (view _Object x))+    g (s, x) = h s <$> HMap.toList (KeyMap.toHashMapText (fromMaybe (error "Could not parse json object") (preview _Object x)))     h :: Text -> (Text, Value) -> (Text, (SolcContract, HMap.HashMap Text Text))     h s (c, x) =       let         evmstuff = x ^?! key "evm"         runtime = evmstuff ^?! key "deployedBytecode"         creation =  evmstuff ^?! key "bytecode"-        theRuntimeCode = toCode $ fromMaybe "" $ runtime ^? key "object" . _String-        theCreationCode = toCode $ fromMaybe "" $ creation ^? key "object" . _String+        theRuntimeCode = toCode $ fromMaybe "" $ runtime ^? key "object" % _String+        theCreationCode = toCode $ fromMaybe "" $ creation ^? key "object" % _String         srcContents :: Maybe (HMap.HashMap Text Text)-        srcContents = do metadata <- x ^? key "metadata" . _String-                         srcs <- KeyMap.toHashMapText <$> metadata ^? key "sources" . _Object-                         return $ (view (key "content" . _String)) <$> (HMap.filter (isJust . preview (key "content")) srcs)+        srcContents = do metadata <- x ^? key "metadata" % _String+                         srcs <- KeyMap.toHashMapText <$> metadata ^? key "sources" % _Object+                         return $ fmap+                           (fromMaybe (error "Internal Error: could not parse contents field into a string") . preview (key "content" % _String))+                           (HMap.filter (isJust . preview (key "content")) srcs)         abis = force ("abi key not found in " <> show x) $-          toList <$> x ^? key "abi" . _Array+          toList <$> x ^? key "abi" % _Array       in (s <> ":" <> c, (SolcContract {         runtimeCode      = theRuntimeCode,         creationCode     = theCreationCode,         runtimeCodehash  = keccak' (stripBytecodeMetadata theRuntimeCode),         creationCodehash = keccak' (stripBytecodeMetadata theCreationCode),-        runtimeSrcmap    = force "internal error: srcmap-runtime" (makeSrcMaps (runtime ^?! key "sourceMap" . _String)),-        creationSrcmap   = force "internal error: srcmap" (makeSrcMaps (creation ^?! key "sourceMap" . _String)),+        runtimeSrcmap    = force "internal error: srcmap-runtime" (makeSrcMaps (runtime ^?! key "sourceMap" % _String)),+        creationSrcmap   = force "internal error: srcmap" (makeSrcMaps (creation ^?! key "sourceMap" % _String)),         contractName = s <> ":" <> c,         constructorInputs = mkConstructor abis,         abiMap        = mkAbiMap abis,@@ -399,55 +403,55 @@                _ -> Nothing       }, fromMaybe mempty srcContents)) -mkAbiMap :: [Value] -> Map Word32 Method+mkAbiMap :: [Value] -> Map FunctionSelector Method mkAbiMap abis = Map.fromList $   let-    relevant = filter (\y -> "function" == y ^?! key "type" . _String) abis+    relevant = filter (\y -> "function" == y ^?! key "type" % _String) abis     f abi =       (abiKeccak (encodeUtf8 (signature abi)),-       Method { name = abi ^?! key "name" . _String+       Method { name = abi ^?! key "name" % _String               , methodSignature = signature abi               , inputs = map parseMethodInput-                 (toList (abi ^?! key "inputs" . _Array))+                 (toList (abi ^?! key "inputs" % _Array))               , output = map parseMethodInput-                 (toList (abi ^?! key "outputs" . _Array))+                 (toList (abi ^?! key "outputs" % _Array))               , mutability = parseMutability-                 (abi ^?! key "stateMutability" . _String)+                 (abi ^?! key "stateMutability" % _String)               })   in f <$> relevant  mkEventMap :: [Value] -> Map W256 Event mkEventMap abis = Map.fromList $   let-    relevant = filter (\y -> "event" == y ^?! key "type" . _String) abis+    relevant = filter (\y -> "event" == y ^?! key "type" % _String) abis     f abi =      ( keccak' (encodeUtf8 (signature abi))      , Event-       (abi ^?! key "name" . _String)-       (case abi ^?! key "anonymous" . _Bool of+       (abi ^?! key "name" % _String)+       (case abi ^?! key "anonymous" % _Bool of          True -> Anonymous          False -> NotAnonymous)        (map (\y ->-        ( y ^?! key "name" . _String+        ( y ^?! key "name" % _String         , force "internal error: type" (parseTypeName' y)-        , if y ^?! key "indexed" . _Bool+        , if y ^?! key "indexed" % _Bool           then Indexed           else NotIndexed         ))-       (toList $ abi ^?! key "inputs" . _Array))+       (toList $ abi ^?! key "inputs" % _Array))      )   in f <$> relevant  mkErrorMap :: [Value] -> Map W256 SolError mkErrorMap abis = Map.fromList $   let-    relevant = filter (\y -> "error" == y ^?! key "type" . _String) abis+    relevant = filter (\y -> "error" == y ^?! key "type" % _String) abis     f abi =      ( stripKeccak $ keccak' (encodeUtf8 (signature abi))      , SolError-       (abi ^?! key "name" . _String)+       (abi ^?! key "name" % _String)        (map (force "internal error: type" . parseTypeName')-       (toList $ abi ^?! key "inputs" . _Array))+       (toList $ abi ^?! key "inputs" % _Array))      )   in f <$> relevant   where@@ -458,24 +462,24 @@ mkConstructor abis =   let     isConstructor y =-      "constructor" == y ^?! key "type" . _String+      "constructor" == y ^?! key "type" % _String   in     case filter isConstructor abis of-      [abi] -> map parseMethodInput (toList (abi ^?! key "inputs" . _Array))+      [abi] -> map parseMethodInput (toList (abi ^?! key "inputs" % _Array))       [] -> [] -- default constructor has zero inputs       _  -> error "strange: contract has multiple constructors"  mkStorageLayout :: Maybe Value -> Maybe (Map Text StorageItem) mkStorageLayout Nothing = Nothing mkStorageLayout (Just json) = do-  items <- json ^? key "storage" . _Array+  items <- json ^? key "storage" % _Array   types <- json ^? key "types"   fmap Map.fromList (forM (Vector.toList items) $ \item ->-    do name <- item ^? key "label" . _String-       offset <- item ^? key "offset" . _Number >>= toBoundedInteger-       slot <- item ^? key "slot" . _String-       typ <- Key.fromText <$> item ^? key "type" . _String-       slotType <- types ^?! key typ ^? key "label" . _String+    do name <- item ^? key "label" % _String+       offset <- item ^? key "offset" % _Number >>= toBoundedInteger+       slot <- item ^? key "slot" % _String+       typ <- Key.fromText <$> item ^? key "type" % _String+       slotType <- types ^?! key typ ^? key "label" % _String        return (name, StorageItem (read $ Text.unpack slotType) offset (read $ Text.unpack slot)))  signature :: AsValue s => s -> Text@@ -484,10 +488,10 @@     "fallback" -> "<fallback>"     _ ->       fold [-        fromMaybe "<constructor>" (abi ^? key "name" . _String), "(",+        fromMaybe "<constructor>" (abi ^? key "name" % _String), "(",         intercalate ","-          (map (\x -> x ^?! key "type" . _String)-            (toList $ abi ^?! key "inputs" . _Array)),+          (map (\x -> x ^?! key "type" % _String)+            (toList $ abi ^?! key "inputs" % _Array)),         ")"       ] @@ -495,8 +499,8 @@ parseTypeName' :: AsValue s => s -> Maybe AbiType parseTypeName' x =   parseTypeName-    (fromMaybe mempty $ x ^? key "components" . _Array . to parseComponents)-    (x ^?! key "type" . _String)+    (fromMaybe mempty $ x ^? key "components" % _Array % to parseComponents)+    (x ^?! key "type" % _String)   where parseComponents = fmap $ snd . parseMethodInput  parseMutability :: Text -> Mutability@@ -509,7 +513,7 @@ -- This actually can also parse a method output! :O parseMethodInput :: AsValue s => s -> (Text, AbiType) parseMethodInput x =-  ( x ^?! key "name" . _String+  ( x ^?! key "name" % _String   , force "internal error: method type" (parseTypeName' x)   ) @@ -707,7 +711,7 @@        Map.fromList       . mapMaybe         (\v -> do-          src <- preview (key "src" . _String) v+          src <- preview (key "src" % _String) v           [i, n, f] <- mapM (readMaybe . Text.unpack) (Text.split (== ':') src)           return ((i, n, f), v)         )
src/EVM/Solvers.hs view
@@ -18,8 +18,8 @@ import Control.Concurrent (forkIO, killThread) import Control.Monad.State.Strict import Data.Char (isSpace)- import Data.Maybe (fromMaybe)+ import Data.Text.Lazy (Text) import Data.Map (Map) import qualified Data.Map as Map@@ -48,11 +48,11 @@  -- | A running solver instance data SolverInstance = SolverInstance-  { _type :: Solver-  , _stdin :: Handle-  , _stdout :: Handle-  , _stderr :: Handle-  , _process :: ProcessHandle+  { solvertype :: Solver+  , stdin      :: Handle+  , stdout     :: Handle+  , stderr     :: Handle+  , process    :: ProcessHandle   }  -- | A channel representing a group of solvers@@ -145,7 +145,7 @@   -- get an initial version of the model from the solver   initialModel <- getRaw   -- get concrete values for each buffers max read index-  hints <- capHints <$> queryMaxReads (getValue inst) cexvars.buffersV+  hints <- capHints <$> queryMaxReads (getValue inst) cexvars.buffers   -- check the sizes of buffer models and shrink if needed   if bufsUsable initialModel   then do@@ -154,11 +154,11 @@   where     getRaw :: IO SMTCex     getRaw = do-      vars <- getVars parseVar (getValue inst) (fmap T.toStrict cexvars.calldataV)-      buffers <- getBufs (getValue inst) (Map.keys cexvars.buffersV)+      vars <- getVars parseVar (getValue inst) (fmap T.toStrict cexvars.calldata)+      buffers <- getBufs (getValue inst) (Map.keys cexvars.buffers)       storage <- getStore (getValue inst) cexvars.storeReads-      blockctx <- getVars parseBlockCtx (getValue inst) (fmap T.toStrict cexvars.blockContextV)-      txctx <- getVars parseFrameCtx (getValue inst) (fmap T.toStrict cexvars.txContextV)+      blockctx <- getVars parseBlockCtx (getValue inst) (fmap T.toStrict cexvars.blockContext)+      txctx <- getVars parseFrameCtx (getValue inst) (fmap T.toStrict cexvars.txContext)       pure $ SMTCex vars buffers storage blockctx txctx      -- sometimes the solver might give us back a model for the max read index@@ -218,9 +218,13 @@           -- TODO: do I need to check the write idx here?           (Write _ idx next) -> idx <= 1024 && go (Comp next) +mkTimeout :: Maybe Natural -> Text+mkTimeout t = T.pack $ show $ (1000 *)$ case t of+  Nothing -> 300 :: Natural+  Just t' -> t'  -- | Arguments used when spawing a solver instance-solverArgs :: Solver -> Maybe (Natural) -> [Text]+solverArgs :: Solver -> Maybe Natural -> [Text] solverArgs solver timeout = case solver of   Bitwuzla -> error "TODO: Bitwuzla args"   Z3 ->@@ -229,7 +233,7 @@     [ "--lang=smt"     , "--no-interactive"     , "--produce-models"-    , "--tlimit-per=" <> T.pack (show (1000 * fromMaybe 10 timeout))+    , "--tlimit-per=" <> mkTimeout timeout     ]   Custom _ -> [] @@ -240,13 +244,11 @@   (Just stdin, Just stdout, Just stderr, process) <- createProcess cmd   hSetBuffering stdin (BlockBuffering (Just 1000000))   let solverInstance = SolverInstance solver stdin stdout stderr process-  case timeout of-    Nothing -> pure solverInstance-    Just t -> case solver of-        CVC5 -> pure solverInstance-        _ -> do-          _ <- sendLine' solverInstance $ "(set-option :timeout " <> T.pack (show t) <> ")"-          pure solverInstance+  case solver of+    CVC5 -> pure solverInstance+    _ -> do+      _ <- sendLine' solverInstance $ "(set-option :timeout " <> mkTimeout timeout <> ")"+      pure solverInstance  -- | Cleanly shutdown a running solver instnace stopSolver :: SolverInstance -> IO ()
src/EVM/Stepper.hs view
@@ -1,4 +1,3 @@-{-# Language GADTs #-} {-# Language DataKinds #-}  module EVM.Stepper@@ -24,28 +23,24 @@ -- The implementation uses the operational monad pattern -- as the framework for monadic interpretation. -import Prelude hiding (fail)--import Control.Monad.Operational (Program, singleton, view, ProgramViewT(..), ProgramView)-import Control.Monad.State.Strict (runState, liftIO, StateT)-import qualified Control.Monad.State.Class as State-import qualified EVM.Exec+import Control.Monad.Operational (Program, ProgramViewT(..), ProgramView, singleton, view)+import Control.Monad.State.Strict (StateT, execState, runState, runStateT) import Data.Text (Text)-import EVM.Types (Expr, EType(..))  import EVM (EVM, VM, VMResult (VMFailure, VMSuccess), Error (Query, Choose), Query, Choose)-import qualified EVM--import qualified EVM.Fetch as Fetch+import EVM qualified+import EVM.Exec qualified+import EVM.Fetch qualified as Fetch+import EVM.Types (Expr, EType(..))  -- | The instruction type of the operational monad data Action a where    -- | Keep executing until an intermediate result is reached-  Exec ::           Action VMResult+  Exec :: Action VMResult    -- | Keep executing until an intermediate state is reached-  Run ::             Action VM+  Run :: Action VM    -- | Wait for a query to be resolved   Wait :: Query -> Action ()@@ -99,7 +94,7 @@ runFully :: Stepper EVM.VM runFully = do   vm <- run-  case vm._result of+  case vm.result of     Nothing -> error "should not occur"     Just (VMFailure (Query q)) ->       wait q >> runFully@@ -118,31 +113,28 @@ enter :: Text -> Stepper () enter t = evm (EVM.pushTrace (EVM.EntryTrace t)) -interpret :: Fetch.Fetcher -> Stepper a -> StateT VM IO a-interpret fetcher =-  eval . view-+interpret :: Fetch.Fetcher -> VM -> Stepper a -> IO a+interpret fetcher vm = eval . view   where-    eval-      :: ProgramView Action a-      -> StateT VM IO a--    eval (Return x) =-      pure x--    eval (action :>>= k) =-      case action of-        Exec ->-          (State.state . runState) EVM.Exec.exec >>= interpret fetcher . k-        Run ->-          (State.state . runState) EVM.Exec.run >>= interpret fetcher . k-        Wait q ->-          do m <- liftIO (fetcher q)-             State.state (runState m) >> interpret fetcher (k ())-        Ask _ ->-          error "cannot make choices with this interpreter"-        IOAct m ->-          do m >>= interpret fetcher . k-        EVM m -> do-          r <- State.state (runState m)-          interpret fetcher (k r)+  eval :: ProgramView Action a -> IO a+  eval (Return x) = pure x+  eval (action :>>= k) =+    case action of+      Exec ->+        let (r, vm') = runState EVM.Exec.exec vm+        in interpret fetcher vm' (k r)+      Run ->+        let vm' = execState EVM.Exec.run vm+        in interpret fetcher vm' (k vm')+      Wait q -> do+        m <- fetcher q+        let vm' = execState m vm+        interpret fetcher vm' (k ())+      Ask _ ->+        error "cannot make choices with this interpreter"+      IOAct m -> do+        (r, vm') <- runStateT m vm+        interpret fetcher vm' (k r)+      EVM m ->+        let (r, vm') = runState m vm+        in interpret fetcher vm' (k r)
src/EVM/StorageLayout.hs view
@@ -6,9 +6,9 @@ import EVM.Solidity (SolcContract, creationSrcmap, SlotType(..)) import EVM.ABI (AbiType (..), parseTypeName) -import Control.Lens+import Optics.Core import Data.Aeson (Value (..))-import Data.Aeson.Lens+import Data.Aeson.Optics import Data.Foldable (toList) import Data.List.NonEmpty qualified as NonEmpty import Data.Map qualified as Map@@ -44,8 +44,8 @@         (findContractDefinition dapp solc)   in     case preview ( key "attributes"-                 . key "linearizedBaseContracts"-                 . _Array+                 % key "linearizedBaseContracts"+                 % _Array                  ) root of       Nothing ->         []@@ -60,15 +60,15 @@  storageVariablesForContract :: Value -> Maybe [Text] storageVariablesForContract node = do-  name <- preview (ix "attributes" . key "name" . _String) node+  name <- preview (ix "attributes" % key "name" % _String) node   vars <-     fmap       (filter isStorageVariableDeclaration . toList)-      (preview (ix "children" . _Array) node)+      (preview (ix "children" % _Array) node)    pure . flip map vars $     \x ->-      case preview (key "attributes" . key "name" . _String) x of+      case preview (key "attributes" % key "name" % _String) x of         Just variableName ->           mconcat             [ variableName@@ -85,16 +85,16 @@     isSourceNode =       isJust (preview (key "src") x)     hasRightName =-      Just t == preview (key "name" . _String) x+      Just t == preview (key "name" % _String) x  isStorageVariableDeclaration :: Value -> Bool isStorageVariableDeclaration x =   nodeIs "VariableDeclaration" x-    && preview (key "attributes" . key "constant" . _Bool) x /= Just True+    && preview (key "attributes" % key "constant" % _Bool) x /= Just True  slotTypeForDeclaration :: Value -> SlotType slotTypeForDeclaration node =-  case toList <$> preview (key "children" . _Array) node of+  case toList <$> preview (key "children" % _Array) node of     Just (x:_) ->       grokDeclarationType x     _ ->@@ -102,9 +102,9 @@  grokDeclarationType :: Value -> SlotType grokDeclarationType x =-  case preview (key "name" . _String) x of+  case preview (key "name" % _String) x of     Just "Mapping" ->-      case preview (key "children" . _Array) x of+      case preview (key "children" % _Array) x of         Just (toList -> xs) ->           grokMappingType xs         _ ->@@ -128,9 +128,9 @@  grokValueType :: Value -> AbiType grokValueType x =-  case ( preview (key "name" . _String) x-       , preview (key "children" . _Array) x-       , preview (key "attributes" . key "type" . _String) x+  case ( preview (key "name" % _String) x+       , preview (key "children" % _Array) x+       , preview (key "attributes" % key "type" % _String) x        ) of     (Just "ElementaryTypeName", _, Just typeName) ->       fromMaybe (error ("ungrokked value type: " ++ show typeName))@@ -140,8 +140,8 @@     (Just "ArrayTypeName", fmap toList -> Just [t], _)->       AbiArrayDynamicType (grokValueType t)     (Just "ArrayTypeName", fmap toList -> Just [t, n], _)->-      case ( preview (key "name" . _String) n-           , preview (key "attributes" . key "value" . _String) n+      case ( preview (key "name" % _String) n+           , preview (key "attributes" % key "value" % _String) n            ) of         (Just "Literal", Just ((read . unpack) -> i)) ->           AbiArrayType i (grokValueType t)
src/EVM/SymExec.hs view
@@ -1,51 +1,47 @@-{-# Language TupleSections #-} {-# Language DataKinds #-}  module EVM.SymExec where -import Prelude hiding (Word)-+import Control.Concurrent.Async (concurrently, mapConcurrently)+import Control.Concurrent.Spawn (parMapIO, pool)+import Control.Concurrent.STM (atomically, TVar, readTVarIO, readTVar, newTVarIO, writeTVar)+import Control.Monad.Operational qualified as Operational+import Control.Monad.State.Strict+import Data.Bifunctor (second)+import Data.ByteString (ByteString)+import Data.ByteString qualified as BS+import Data.DoubleWord (Word256)+import Data.List (foldl', sortBy)+import Data.Map (Map)+import Data.Map qualified as Map+import Data.Maybe+import Data.Set (Set, isSubsetOf, size)+import Data.Set qualified as Set+import Data.Text (Text)+import Data.Text qualified as T+import Data.Text.IO qualified as T+import Data.Text.Lazy qualified as TL+import Data.Text.Lazy.IO qualified as TL import Data.Tuple (swap)-import Control.Lens hiding (pre)-import EVM hiding (Query, Revert, push, bytecode, cache)-import qualified EVM-import EVM.Exec-import qualified EVM.Fetch as Fetch+import GHC.Conc (getNumProcessors)+import Optics.Core++import EVM hiding (Query, Revert, bytecode)+import EVM qualified import EVM.ABI+import EVM.Concrete (createAddress)+import EVM.Exec+import EVM.Expr qualified as Expr+import EVM.FeeSchedule qualified as FeeSchedule+import EVM.Fetch qualified as Fetch+import EVM.Format (formatExpr, indent, formatBinary) import EVM.SMT (SMTCex(..), SMT2(..), assertProps, formatSMT2)-import qualified EVM.SMT as SMT+import EVM.SMT qualified as SMT import EVM.Solvers-import EVM.Traversals-import qualified EVM.Expr as Expr import EVM.Stepper (Stepper)-import qualified EVM.Stepper as Stepper-import qualified Control.Monad.Operational as Operational-import Control.Monad.State.Strict hiding (state)+import EVM.Stepper qualified as Stepper+import EVM.Traversals import EVM.Types-import EVM.Concrete (createAddress)-import qualified EVM.FeeSchedule as FeeSchedule-import Data.DoubleWord (Word256)-import Control.Concurrent.Async-import Data.Maybe-import Data.List (foldl', sortBy)-import Data.ByteString (ByteString)-import qualified Data.ByteString as BS-import qualified Control.Monad.State.Class as State-import Data.Bifunctor (first, second)-import Data.Text (Text)-import Data.Map (Map)-import qualified Data.Map as Map-import qualified Data.Text as T-import qualified Data.Text.IO as T-import qualified Data.Text.Lazy as TL-import qualified Data.Text.Lazy.IO as TL-import EVM.Format (formatExpr)-import Data.Set (Set, isSubsetOf, size)-import qualified Data.Set as Set-import Control.Concurrent.STM (atomically, TVar, readTVarIO, readTVar, newTVarIO, writeTVar)-import Control.Concurrent.Spawn-import GHC.Conc (getNumProcessors)-import EVM.Format (indent, formatBinary)  -- | A method name, and the (ordered) types of it's arguments data Sig = Sig Text [AbiType]@@ -115,11 +111,12 @@     else error "bad type"   AbiBoolType -> let v = Var name in St [bool v] v   AbiAddressType -> let v = Var name in St [inRange 160 v] v-  AbiBytesType n-    -> if n > 0 && n <= 32-       then let v = Var name in St [inRange (n * 8) v] v-       else error "bad type"-  AbiArrayType sz tp -> Comp $ fmap (\n -> symAbiArg (name <> n) tp) [T.pack (show n) | n <- [0..sz-1]]+  AbiBytesType n ->+    if n > 0 && n <= 32+    then let v = Var name in St [inRange (n * 8) v] v+    else error "bad type"+  AbiArrayType sz tp ->+    Comp $ fmap (\n -> symAbiArg (name <> n) tp) [T.pack (show n) | n <- [0..sz-1]]   t -> error $ "TODO: symbolic abi encoding for " <> show t  data CalldataFragment@@ -134,22 +131,23 @@ -- kept symbolic. symCalldata :: Text -> [AbiType] -> [String] -> Expr Buf -> (Expr Buf, [Prop]) symCalldata sig typesignature concreteArgs base =-  let args = concreteArgs <> replicate (length typesignature - length concreteArgs)  "<symbolic>"-      mkArg :: AbiType -> String -> Int -> CalldataFragment-      mkArg typ "<symbolic>" n = symAbiArg (T.pack $ "arg" <> show n) typ-      mkArg typ arg _ = let v = makeAbiValue typ arg-                        in case v of-                             AbiUInt _ w -> St [] . Lit . num $ w-                             AbiInt _ w -> St [] . Lit . num $ w-                             AbiAddress w -> St [] . Lit . num $ w-                             AbiBool w -> St [] . Lit $ if w then 1 else 0-                             _ -> error "TODO"-      calldatas = zipWith3 mkArg typesignature args [1..]-      (cdBuf, props) = combineFragments calldatas base-      withSelector = writeSelector cdBuf sig-      sizeConstraints-        = (Expr.bufLength withSelector .>= cdLen calldatas)-        .&& (Expr.bufLength withSelector .< (Lit (2 ^ (64 :: Integer))))+  let+    args = concreteArgs <> replicate (length typesignature - length concreteArgs) "<symbolic>"+    mkArg :: AbiType -> String -> Int -> CalldataFragment+    mkArg typ "<symbolic>" n = symAbiArg (T.pack $ "arg" <> show n) typ+    mkArg typ arg _ =+      case makeAbiValue typ arg of+        AbiUInt _ w -> St [] . Lit . num $ w+        AbiInt _ w -> St [] . Lit . num $ w+        AbiAddress w -> St [] . Lit . num $ w+        AbiBool w -> St [] . Lit $ if w then 1 else 0+        _ -> error "TODO"+    calldatas = zipWith3 mkArg typesignature args [1..]+    (cdBuf, props) = combineFragments calldatas base+    withSelector = writeSelector cdBuf sig+    sizeConstraints+      = (Expr.bufLength withSelector .>= cdLen calldatas)+      .&& (Expr.bufLength withSelector .< (Lit (2 ^ (64 :: Integer))))   in (withSelector, sizeConstraints : props)  cdLen :: [CalldataFragment] -> Expr EWord@@ -162,7 +160,8 @@                    _ -> error "unsupported"  writeSelector :: Expr Buf -> Text -> Expr Buf-writeSelector buf sig = writeSel (Lit 0) $ writeSel (Lit 1) $ writeSel (Lit 2) $ writeSel (Lit 3) buf+writeSelector buf sig =+  writeSel (Lit 0) $ writeSel (Lit 1) $ writeSel (Lit 2) $ writeSel (Lit 3) buf   where     sel = ConcreteBuf $ selector sig     writeSel idx = Expr.writeByte idx (Expr.readByte idx sel)@@ -172,127 +171,141 @@   where     go :: Expr EWord -> [CalldataFragment] -> (Expr Buf, [Prop]) -> (Expr Buf, [Prop])     go _ [] acc = acc-    go idx (f:rest) (buf, ps) = case f of-                             St p w -> go (Expr.add idx (Lit 32)) rest (Expr.writeWord idx w buf, p <> ps)-                             s -> error $ "unsupported cd fragment: " <> show s+    go idx (f:rest) (buf, ps) =+      case f of+        St p w -> go (Expr.add idx (Lit 32)) rest (Expr.writeWord idx w buf, p <> ps)+        s -> error $ "unsupported cd fragment: " <> show s  -abstractVM :: (Expr Buf, [Prop]) -> ByteString -> Maybe Precondition -> StorageModel -> VM-abstractVM (cd, calldataProps) contractCode maybepre storagemodel = finalVm+abstractVM+  :: (Expr Buf, [Prop])+  -> ByteString+  -> Maybe Precondition+  -> Expr Storage+  -> VM+abstractVM cd contractCode maybepre store = finalVm   where-    store = case storagemodel of-              SymbolicS -> AbstractStore-              InitialS -> EmptyStore-              ConcreteS -> ConcreteStore mempty     caller' = Caller 0     value' = CallValue 0     code' = RuntimeCode (ConcreteRuntimeCode contractCode)-    vm' = loadSymVM code' store caller' value' cd calldataProps+    vm' = loadSymVM code' store caller' value' cd     precond = case maybepre of                 Nothing -> []                 Just p -> [p vm']-    finalVm = vm' & over constraints (<> precond)+    finalVm = vm' & over #constraints (<> precond) -loadSymVM :: ContractCode -> Expr Storage -> Expr EWord -> Expr EWord -> Expr Buf -> [Prop] -> VM-loadSymVM x initStore addr callvalue' calldata' calldataProps =+loadSymVM+  :: ContractCode+  -> Expr Storage+  -> Expr EWord+  -> Expr EWord+  -> (Expr Buf, [Prop])+  -> VM+loadSymVM x initStore addr callvalue' cd =   (makeVm $ VMOpts-    { vmoptContract = initialContract x-    , vmoptCalldata = (calldata', calldataProps)-    , vmoptValue = callvalue'-    , vmoptStorageBase = Symbolic-    , vmoptAddress = createAddress ethrunAddress 1-    , vmoptCaller = addr-    , vmoptOrigin = ethrunAddress --todo: generalize-    , vmoptCoinbase = 0-    , vmoptNumber = 0-    , vmoptTimestamp = (Lit 0)-    , vmoptBlockGaslimit = 0-    , vmoptGasprice = 0-    , vmoptPrevRandao = 42069-    , vmoptGas = 0xffffffffffffffff-    , vmoptGaslimit = 0xffffffffffffffff-    , vmoptBaseFee = 0-    , vmoptPriorityFee = 0-    , vmoptMaxCodeSize = 0xffffffff-    , vmoptSchedule = FeeSchedule.berlin-    , vmoptChainId = 1-    , vmoptCreate = False-    , vmoptTxAccessList = mempty-    , vmoptAllowFFI = False-    }) & set (env . contracts . at (createAddress ethrunAddress 1))+    { contract = initialContract x+    , calldata = cd+    , value = callvalue'+    , initialStorage = initStore+    , address = createAddress ethrunAddress 1+    , caller = addr+    , origin = ethrunAddress --todo: generalize+    , coinbase = 0+    , number = 0+    , timestamp = Lit 0+    , blockGaslimit = 0+    , gasprice = 0+    , prevRandao = 42069+    , gas = 0xffffffffffffffff+    , gaslimit = 0xffffffffffffffff+    , baseFee = 0+    , priorityFee = 0+    , maxCodeSize = 0xffffffff+    , schedule = FeeSchedule.berlin+    , chainId = 1+    , create = False+    , txAccessList = mempty+    , allowFFI = False+    }) & set (#env % #contracts % at (createAddress ethrunAddress 1))              (Just (initialContract x))-       & set (env . EVM.storage) initStore ---- | Interpreter which explores all paths at branching points.--- returns an Expr representing the possible executions+-- | Interpreter which explores all paths at branching points. Returns an+-- 'Expr End' representing the possible executions. interpret   :: Fetch.Fetcher   -> Maybe Integer -- max iterations   -> Maybe Integer -- ask smt iterations+  -> VM   -> Stepper (Expr End)-  -> StateT VM IO (Expr End)-interpret fetcher maxIter askSmtIters =+  -> IO (Expr End)+interpret fetcher maxIter askSmtIters vm =   eval . Operational.view-   where-    eval-      :: Operational.ProgramView Stepper.Action (Expr End)-      -> StateT VM IO (Expr End)+  eval+    :: Operational.ProgramView Stepper.Action (Expr End)+    -> IO (Expr End) -    eval (Operational.Return x) = pure x+  eval (Operational.Return x) = pure x -    eval (action Operational.:>>= k) =-      case action of-        Stepper.Exec ->-          (State.state . runState) exec >>= interpret fetcher maxIter askSmtIters . k-        Stepper.Run ->-          (State.state . runState) run >>= interpret fetcher maxIter askSmtIters . k-        Stepper.IOAct q ->-          mapStateT liftIO q >>= interpret fetcher maxIter askSmtIters . k-        Stepper.Ask (EVM.PleaseChoosePath cond continue) -> do-          assign result Nothing-          vm <- get-          case maxIterationsReached vm maxIter of-            -- TODO: parallelise-            Nothing -> do-              a <- interpret fetcher maxIter askSmtIters (Stepper.evm (continue True) >>= k)-              put vm-              b <- interpret fetcher maxIter askSmtIters (Stepper.evm (continue False) >>= k)-              return $ ITE cond a b-            Just n ->-              -- Let's escape the loop. We give no guarantees at this point-              interpret fetcher maxIter askSmtIters (Stepper.evm (continue (not n)) >>= k)-        Stepper.Wait q -> do-          let performQuery = do-                m <- liftIO (fetcher q)-                interpret fetcher maxIter askSmtIters (Stepper.evm m >>= k)+  eval (action Operational.:>>= k) =+    case action of+      Stepper.Exec -> do+        let (r, vm') = runState exec vm+        interpret fetcher maxIter askSmtIters vm' (k r)+      Stepper.Run -> do+        let vm' = execState exec vm+        interpret fetcher maxIter askSmtIters vm' (k vm')+      Stepper.IOAct q -> do+        (r, vm') <- runStateT q vm+        interpret fetcher maxIter askSmtIters vm' (k r)+      Stepper.Ask (EVM.PleaseChoosePath cond continue) ->+        case maxIterationsReached vm maxIter of+          Nothing -> do+            (a, b) <- concurrently+              (let (ra, vma) = runState (continue True) vm { result = Nothing }+               in interpret fetcher maxIter askSmtIters vma (k ra))+              (let (rb, vmb) = runState (continue False) vm { result = Nothing }+               in interpret fetcher maxIter askSmtIters vmb (k rb)) -          case q of-            PleaseAskSMT _ _ continue -> do-              codelocation <- getCodeLocation <$> get-              iteration <- num . fromMaybe 0 <$> use (iterations . at codelocation)+            pure $ ITE cond a b+          Just n -> do+            -- Let's escape the loop. We give no guarantees at this point+            let (r, vm') = runState (continue (not n)) vm { result = Nothing }+            interpret fetcher maxIter askSmtIters vm' (k r)+      Stepper.Wait q -> do+        let performQuery = do+              m <- liftIO (fetcher q)+              let (r, vm') = runState m vm+              interpret fetcher maxIter askSmtIters vm' (k r) -              -- if this is the first time we are branching at this point,-              -- explore both branches without consulting SMT.-              -- Exploring too many branches is a lot cheaper than-              -- consulting our SMT solver.-              if iteration < (fromMaybe 5 askSmtIters)-              then interpret fetcher maxIter askSmtIters (Stepper.evm (continue EVM.Unknown) >>= k)-              else performQuery+        case q of+          PleaseAskSMT _ _ continue -> do+            let+              codelocation = getCodeLocation vm+              iteration = num . fromMaybe 0 $ Map.lookup codelocation vm.iterations -            _ -> performQuery+            -- if this is the first time we are branching at this point,+            -- explore both branches without consulting SMT.+            -- Exploring too many branches is a lot cheaper than+            -- consulting our SMT solver.+            if iteration < fromMaybe 5 askSmtIters then do+              let (r, vm') = runState (continue EVM.Unknown) vm+              interpret fetcher maxIter askSmtIters vm' (k r)+            else performQuery -        Stepper.EVM m ->-          State.state (runState m) >>= interpret fetcher maxIter askSmtIters . k+          _ -> performQuery +      Stepper.EVM m -> do+        let (r, vm') = runState m vm+        interpret fetcher maxIter askSmtIters vm' (k r)+ maxIterationsReached :: VM -> Maybe Integer -> Maybe Bool maxIterationsReached _ Nothing = Nothing maxIterationsReached vm (Just maxIter) =   let codelocation = getCodeLocation vm-      iters = view (at codelocation . non 0) vm._iterations+      iters = view (at codelocation % non 0) vm.iterations   in if num maxIter <= iters-     then Map.lookup (codelocation, iters - 1) vm._cache._path+     then Map.lookup (codelocation, iters - 1) vm.cache.path      else Nothing  @@ -300,10 +313,18 @@ type Postcondition = VM -> Expr End -> Prop  -checkAssert :: SolverGroup -> [Word256] -> ByteString -> Maybe Sig -> [String] -> VeriOpts -> IO (Expr End, [VerifyResult])-checkAssert solvers errs c signature' concreteArgs opts = verifyContract solvers c signature' concreteArgs opts SymbolicS Nothing (Just $ checkAssertions errs)+checkAssert+  :: SolverGroup+  -> [Word256]+  -> ByteString+  -> Maybe Sig+  -> [String]+  -> VeriOpts+  -> IO (Expr End, [VerifyResult])+checkAssert solvers errs c signature' concreteArgs opts =+  verifyContract solvers c signature' concreteArgs opts AbstractStore Nothing (Just $ checkAssertions errs) -{- |Checks if an assertion violation has been encountered+{- | Checks if an assertion violation has been encountered    hevm recognises the following as an assertion violation: @@ -328,37 +349,48 @@   Revert _ b -> foldl' PAnd (PBool True) (fmap (PNeg . PEq b . ConcreteBuf . panicMsg) errs)   _ -> PBool True --- |By default hevm checks for all assertions except those which result from arithmetic overflow+-- | By default hevm only checks for user-defined assertions defaultPanicCodes :: [Word256]-defaultPanicCodes = [ 0x00, 0x01, 0x12, 0x21, 0x22, 0x31, 0x32, 0x41, 0x51 ]+defaultPanicCodes = [0x01]  allPanicCodes :: [Word256]-allPanicCodes = [ 0x00, 0x01, 0x11, 0x12, 0x21, 0x22, 0x31, 0x32, 0x41, 0x51 ]+allPanicCodes = [0x00, 0x01, 0x11, 0x12, 0x21, 0x22, 0x31, 0x32, 0x41, 0x51] --- |Produces the revert message for solc >=0.8 assertion violations+-- | Produces the revert message for solc >=0.8 assertion violations panicMsg :: Word256 -> ByteString-panicMsg err = (selector "Panic(uint256)") <> (encodeAbiValue $ AbiUInt 256 err)+panicMsg err = selector "Panic(uint256)" <> encodeAbiValue (AbiUInt 256 err) --- | Builds a buffer representing calldata from the provided method description and concrete arguments+-- | Builds a buffer representing calldata from the provided method description+-- and concrete arguments mkCalldata :: Maybe Sig -> [String] -> (Expr Buf, [Prop]) mkCalldata Nothing _ =-      ( AbstractBuf "txdata"-      -- assert that the length of the calldata is never more than 2^64-      -- this is way larger than would ever be allowed by the gas limit-      -- and avoids spurious counterexamples during abi decoding-      -- TODO: can we encode calldata as an array with a smaller length?-      , [Expr.bufLength (AbstractBuf "txdata") .< (Lit (2 ^ (64 :: Integer)))]-      )-mkCalldata (Just (Sig name types)) args = symCalldata name types args (AbstractBuf "txdata")+  ( AbstractBuf "txdata"+  -- assert that the length of the calldata is never more than 2^64+  -- this is way larger than would ever be allowed by the gas limit+  -- and avoids spurious counterexamples during abi decoding+  -- TODO: can we encode calldata as an array with a smaller length?+  , [Expr.bufLength (AbstractBuf "txdata") .< (Lit (2 ^ (64 :: Integer)))]+  )+mkCalldata (Just (Sig name types)) args =+  symCalldata name types args (AbstractBuf "txdata") -verifyContract :: SolverGroup -> ByteString -> Maybe Sig -> [String] -> VeriOpts -> StorageModel -> Maybe Precondition -> Maybe Postcondition -> IO (Expr End, [VerifyResult])-verifyContract solvers theCode signature concreteArgs opts storagemodel maybepre maybepost = do-  let preState = abstractVM (mkCalldata signature concreteArgs) theCode maybepre storagemodel-  verify solvers opts preState maybepost+verifyContract+  :: SolverGroup+  -> ByteString+  -> Maybe Sig+  -> [String]+  -> VeriOpts+  -> Expr Storage+  -> Maybe Precondition+  -> Maybe Postcondition+  -> IO (Expr End, [VerifyResult])+verifyContract solvers theCode signature' concreteArgs opts initStore maybepre maybepost =+  let preState = abstractVM (mkCalldata signature' concreteArgs) theCode maybepre initStore+  in verify solvers opts preState maybepost  pruneDeadPaths :: [VM] -> [VM] pruneDeadPaths =-  filter $ \vm -> case vm._result of+  filter $ \vm -> case vm.result of     Just (VMFailure DeadPath) -> False     _ -> True @@ -366,10 +398,10 @@ runExpr :: Stepper.Stepper (Expr End) runExpr = do   vm <- Stepper.runFully-  let asserts = vm._keccakEqs-  pure $ case vm._result of+  let asserts = vm.keccakEqs+  pure $ case vm.result of     Nothing -> error "Internal Error: vm in intermediate state after call to runFully"-    Just (VMSuccess buf) -> Return asserts buf vm._env._storage+    Just (VMSuccess buf) -> Return asserts buf vm.env.storage     Just (VMFailure e) -> case e of       UnrecognizedOpcode _ -> Failure asserts Invalid       SelfDestruction -> Failure asserts SelfDestruct@@ -381,18 +413,19 @@       EVM.StackUnderrun -> Failure asserts EVM.Types.StackUnderrun       e' -> Failure asserts $ EVM.Types.TmpErr (show e') --- | Converts a given top level expr into a list of final states and the associated path conditions for each state-flattenExpr :: Expr End -> [([Prop], Expr End)]+-- | 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 -> [([Prop], Expr End)]-    go pcs = \case-      ITE c t f -> go (PNeg ((PEq c (Lit 0))) : pcs) t <> go (PEq c (Lit 0) : pcs) f-      e@(Revert _ _) -> [(pcs, e)]-      e@(Return _ _ _) -> [(pcs, e)]-      Failure _ (TmpErr s) -> error s-      e@(Failure _ _) -> [(pcs, e)]-      GVar _ -> error "cannot flatten an Expr containing a GVar"+  go :: [Prop] -> Expr End -> [Expr End]+  go pcs = \case+    ITE c t f -> go (PNeg ((PEq c (Lit 0))) : pcs) t <> go (PEq c (Lit 0) : pcs) f+    Failure _ (TmpErr s) -> error s+    GVar _ -> error "cannot flatten an Expr containing a GVar"+    Revert ps msg -> [Revert (ps <> pcs) msg]+    Return ps msg store -> [Return (ps <> pcs) msg store]+    Failure ps e -> [Failure (ps <> pcs) e]  -- | Strips unreachable branches from a given expr -- Returns a list of executed SMT queries alongside the reduced expression for debugging purposes@@ -405,8 +438,8 @@ -- TODO: handle errors properly reachable :: SolverGroup -> Expr End -> IO ([SMT2], Expr End) reachable solvers e = do-    res <- go [] e-    pure $ second (fromMaybe (error "Internal Error: no reachable paths found")) res+  res <- go [] e+  pure $ second (fromMaybe (error "Internal Error: no reachable paths found")) res   where     {-        Walk down the tree and collect pcs.@@ -468,7 +501,7 @@   o -> o  --- | Extract contraints stored in  Expr End nodes+-- | Extract contraints stored in Expr End nodes extractProps :: Expr End -> [Prop] extractProps = \case   ITE _ _ _ -> []@@ -478,12 +511,18 @@   GVar _ -> error "cannot extract props from a GVar"  --- | Symbolically execute the VM and check all endstates against the postcondition, if available.-verify :: SolverGroup -> VeriOpts -> VM -> Maybe Postcondition -> IO (Expr End, [VerifyResult])+-- | Symbolically execute the VM and check all endstates against the+-- postcondition, if available.+verify+  :: SolverGroup+  -> VeriOpts+  -> VM+  -> Maybe Postcondition+  -> IO (Expr End, [VerifyResult]) verify solvers opts preState maybepost = do   putStrLn "Exploring contract" -  exprInter <- evalStateT (interpret (Fetch.oracle solvers opts.rpcInfo) opts.maxIter opts.askSmtIters runExpr) preState+  exprInter <- interpret (Fetch.oracle solvers opts.rpcInfo) opts.maxIter opts.askSmtIters preState runExpr   when opts.debug $ T.writeFile "unsimplified.expr" (formatExpr exprInter)    putStrLn "Simplifying expression"@@ -498,12 +537,15 @@       let         -- Filter out any leaves that can be statically shown to be safe         canViolate = flip filter (flattenExpr expr) $-          \(_, leaf) -> case evalProp (post preState leaf) of+          \leaf -> case evalProp (post preState leaf) of             PBool True -> False             _ -> True-        assumes = preState._constraints-        withQueries = fmap (\(pcs, leaf) -> (assertProps (PNeg (post preState leaf) : assumes <> extractProps leaf <> pcs), leaf)) canViolate-      putStrLn $ "Checking for reachability of " <> show (length withQueries) <> " potential property violation(s)"+        assumes = preState.constraints+        withQueries = canViolate <&> \leaf ->+          (assertProps (PNeg (post preState leaf) : assumes <> extractProps leaf), leaf)+      putStrLn $ "Checking for reachability of "+                   <> show (length withQueries)+                   <> " potential property violation(s)"        when opts.debug $ forM_ (zip [(1 :: Int)..] withQueries) $ \(idx, (q, leaf)) -> do         TL.writeFile@@ -526,12 +568,17 @@  type UnsatCache = TVar [Set Prop] --- | Compares two contract runtimes for trace equivalence by running two VMs and comparing the end states.+-- | Compares two contract runtimes for trace equivalence by running two VMs+-- and comparing the end states. ----- We do this by asking the solver to find a common input for each pair of endstates that satisfies the path--- conditions for both sides and produces a differing output. If we can find such an input, then we have a clear--- equivalence break, and since we run this check for every pair of end states, the check is exhaustive.-equivalenceCheck :: SolverGroup -> ByteString -> ByteString -> VeriOpts -> (Expr Buf, [Prop]) -> IO [EquivResult]+-- We do this by asking the solver to find a common input for each pair of+-- endstates that satisfies the path conditions for both sides and produces a+-- differing output. If we can find such an input, then we have a clear+-- equivalence break, and since we run this check for every pair of end states,+-- the check is exhaustive.+equivalenceCheck+  :: SolverGroup -> ByteString -> ByteString -> VeriOpts -> (Expr Buf, [Prop])+  -> IO [EquivResult] equivalenceCheck solvers bytecodeA bytecodeB opts calldata' = do   case bytecodeA == bytecodeB of     True -> do@@ -541,11 +588,11 @@       branchesA <- getBranches bytecodeA       branchesB <- getBranches bytecodeB       let allPairs = [(a,b) | a <- branchesA, b <- branchesB]-      putStrLn $ "Found " <> (show $ length allPairs) <> " total pairs of endstates"+      putStrLn $ "Found " <> show (length allPairs) <> " total pairs of endstates" -      when opts.debug $ putStrLn-                        $ "endstates in bytecodeA: " <> (show $ length branchesA)-                       <> "\nendstates in bytecodeB: " <> (show $ length branchesB)+      when opts.debug $+        putStrLn $ "endstates in bytecodeA: " <> show (length branchesA)+                   <> "\nendstates in bytecodeB: " <> show (length branchesB)        let differingEndStates = sortBySize (mapMaybe (uncurry distinct) allPairs)       putStrLn $ "Asking the SMT solver for " <> (show $ length differingEndStates) <> " pairs"@@ -572,12 +619,12 @@     subsetAny a b = foldr (\bp acc -> acc || isSubsetOf a bp) False b      -- decompiles the given bytecode into a list of branches-    getBranches :: ByteString -> IO [([Prop], Expr End)]+    getBranches :: ByteString -> IO [Expr End]     getBranches bs = do       let         bytecode = if BS.null bs then BS.pack [0] else bs-        prestate = abstractVM calldata' bytecode Nothing SymbolicS-      expr <- evalStateT (interpret (Fetch.oracle solvers Nothing) opts.maxIter opts.askSmtIters runExpr) prestate+        prestate = abstractVM calldata' bytecode Nothing AbstractStore+      expr <- interpret (Fetch.oracle solvers Nothing) opts.maxIter opts.askSmtIters prestate runExpr       let simpl = if opts.simp then (Expr.simplify expr) else expr       pure $ flattenExpr simpl @@ -594,13 +641,14 @@              else (fmap ((False),) (checkSat solvers smt))       case res of         (_, Sat x) -> pure (Cex x, False)-        (quick, Unsat) -> case quick of-                            True  -> pure (Qed (), quick)-                            False -> do-                              -- nb: we might end up with duplicates here due to a-                              -- potential race, but it doesn't matter for correctness-                              atomically $ readTVar knownUnsat >>= writeTVar knownUnsat . (props :)-                              pure (Qed (), False)+        (quick, Unsat) ->+          case quick of+            True  -> pure (Qed (), quick)+            False -> do+              -- nb: we might end up with duplicates here due to a+              -- potential race, but it doesn't matter for correctness+              atomically $ readTVar knownUnsat >>= writeTVar knownUnsat . (props :)+              pure (Qed (), False)         (_, EVM.Solvers.Unknown) -> pure (Timeout (), False)         (_, Error txt) -> error $ "Error while running solver: `" <> T.unpack txt -- <> "` SMT file was: `" <> filename <> "`" @@ -618,8 +666,8 @@     -- for a given pair of branches, equivalence is violated if there exists an     -- input that satisfies the branch conditions from both sides and produces     -- a differing result in each branch-    distinct :: ([Prop], Expr End) -> ([Prop], Expr End) -> Maybe (Set Prop)-    distinct (aProps, aEnd) (bProps, bEnd) =+    distinct :: Expr End -> Expr End -> Maybe (Set Prop)+    distinct aEnd bEnd =       let         differingResults = case (aEnd, bEnd) of           (Return _ aOut aStore, Return _ bOut bStore) ->@@ -646,11 +694,11 @@         -- if we can statically determine that the end states differ, then we         -- ask the solver to find us inputs that satisfy both sets of branch         -- conditions-        PBool True  -> Just . Set.fromList $ aProps <> bProps+        PBool True  -> Just . Set.fromList $ extractProps aEnd <> extractProps bEnd         -- if we cannot statically determine whether or not the end states         -- differ, then we ask the solver if the end states can differ if both         -- sets of path conditions are satisfiable-        _ -> Just . Set.fromList $ differingResults : aProps <> bProps+        _ -> Just . Set.fromList $ differingResults : extractProps aEnd <> extractProps bEnd  both' :: (a -> b) -> (a, a) -> (b, b) both' f (x, y) = (f x, f y)@@ -658,7 +706,7 @@ produceModels :: SolverGroup -> Expr End -> IO [(Expr End, CheckSatResult)] produceModels solvers expr = do   let flattened = flattenExpr expr-      withQueries = fmap (first assertProps) flattened+      withQueries = fmap (\e -> (assertProps . extractProps $ e, e)) flattened   results <- flip mapConcurrently withQueries $ \(query, leaf) -> do     res <- checkSat solvers query     pure (res, leaf)@@ -713,7 +761,10 @@       | Map.null store = []       | otherwise =           [ "Storage:"-          , indent 2 $ T.unlines $ Map.foldrWithKey (\key val acc -> ("Addr " <> (T.pack $ show key) <> ": " <> (T.pack $ show (Map.toList val))) : acc) mempty store+          , indent 2 $ T.unlines $ Map.foldrWithKey (\key val acc ->+              ("Addr " <> (T.pack . show . Addr . num $ key)+                <> ": " <> (T.pack $ show (Map.toList val))) : acc+            ) mempty store           , ""           ] @@ -722,7 +773,9 @@       | Map.null txContext = []       | otherwise =         [ "Transaction Context:"-        , indent 2 $ T.unlines $ Map.foldrWithKey (\key val acc -> (showTxCtx key <> ": " <> (T.pack $ show val)) : acc) mempty (filterSubCtx txContext)+        , indent 2 $ T.unlines $ Map.foldrWithKey (\key val acc ->+            (showTxCtx key <> ": " <> (T.pack $ show val)) : acc+          ) mempty (filterSubCtx txContext)         , ""         ] @@ -751,7 +804,9 @@       | Map.null blockContext = []       | otherwise =         [ "Block Context:"-        , indent 2 $ T.unlines $ Map.foldrWithKey (\key val acc -> (T.pack $ show key <> ": " <> show val) : acc) mempty txContext+        , indent 2 $ T.unlines $ Map.foldrWithKey (\key val acc ->+            (T.pack $ show key <> ": " <> show val) : acc+          ) mempty txContext         , ""         ] @@ -760,12 +815,17 @@     prettyBuf (ConcreteBuf bs) = formatBinary bs     prettyBuf _ = "Any" --- | Takes a buffer and a Cex and replaces all abstract values in the buf with concrete ones from the Cex+-- | Takes a buffer and a Cex and replaces all abstract values in the buf with+-- concrete ones from the Cex. subModel :: SMTCex -> Expr a -> Expr a-subModel c expr = subBufs (fmap forceFlattened c.buffers) . subVars c.vars . subStore c.store . subVars c.blockContext . subVars c.txContext $ expr+subModel c expr =+  subBufs (fmap forceFlattened c.buffers) . subVars c.vars . subStore c.store+  . subVars c.blockContext . subVars c.txContext $ expr   where     forceFlattened (SMT.Flat bs) = bs-    forceFlattened b@(SMT.Comp _) = forceFlattened $ fromMaybe (error $ "Internal Error: cannot flatten buffer: " <> show b) (SMT.collapse b)+    forceFlattened b@(SMT.Comp _) = forceFlattened $+      fromMaybe (error $ "Internal Error: cannot flatten buffer: " <> show b)+                (SMT.collapse b)      subVars model b = Map.foldlWithKey subVar b model     subVar :: Expr a -> Expr EWord -> W256 -> Expr a
src/EVM/TTY.hs view
@@ -1,4 +1,5 @@ {-# Language TemplateHaskell #-}+{-# Language UndecidableInstances #-} {-# Language ImplicitParams #-} {-# Language DataKinds #-} @@ -32,10 +33,13 @@ import EVM.StorageLayout import EVM.TTYCenteredList qualified as Centered -import Control.Lens hiding (List)+import Optics.Core+import Optics.State+import Optics.TH+ import Control.Monad.Operational qualified as Operational import Control.Monad.State.Strict hiding (state)-import Data.Aeson.Lens+import Data.Aeson.Optics import Data.ByteString (ByteString) import Data.ByteString qualified as BS import Data.List (sort, find)@@ -68,23 +72,23 @@ type UiWidget = Widget Name  data UiVmState = UiVmState-  { _uiVm           :: VM-  , _uiStep         :: Int-  , _uiSnapshots    :: Map Int (VM, Stepper ())-  , _uiStepper      :: Stepper ()-  , _uiShowMemory   :: Bool-  , _uiTestOpts     :: UnitTestOptions+  { vm         :: VM+  , step       :: Int+  , snapshots  :: Map Int (VM, Stepper ())+  , stepper    :: Stepper ()+  , showMemory :: Bool+  , testOpts   :: UnitTestOptions   }  data UiTestPickerState = UiTestPickerState-  { _testPickerList :: List Name (Text, Text)-  , _testPickerDapp :: DappInfo-  , _testOpts       :: UnitTestOptions+  { tests :: List Name (Text, Text)+  , dapp  :: DappInfo+  , opts  :: UnitTestOptions   }  data UiBrowserState = UiBrowserState-  { _browserContractList :: List Name (Addr, Contract)-  , _browserVm :: UiVmState+  { contracts :: List Name (Addr, Contract)+  , vm        :: UiVmState   }  data UiState@@ -93,9 +97,9 @@   | ViewPicker UiTestPickerState   | ViewHelp UiVmState -makeLenses ''UiVmState-makeLenses ''UiTestPickerState-makeLenses ''UiBrowserState+makeFieldLabelsNoPrefix ''UiVmState+makeFieldLabelsNoPrefix ''UiTestPickerState+makeFieldLabelsNoPrefix ''UiBrowserState makePrisms ''UiState  -- caching VM states lets us backstep efficiently@@ -142,10 +146,10 @@          Stepper.Run -> do           -- Have we reached the final result of this action?-          use (uiVm . result) >>= \case+          use (#vm % #result) >>= \case             Just _ -> do               -- Yes, proceed with the next action.-              vm <- use uiVm+              vm <- use #vm               interpret mode (k vm)             Nothing -> do               -- No, keep performing the current action@@ -154,7 +158,7 @@         -- Stepper wants to keep executing?         Stepper.Exec -> do           -- Have we reached the final result of this action?-          use (uiVm . result) >>= \case+          use (#vm % #result) >>= \case             Just r ->               -- Yes, proceed with the next action.               interpret mode (k r)@@ -165,7 +169,7 @@         -- Stepper is waiting for user input from a query         Stepper.Ask (PleaseChoosePath _ cont) -> do           -- ensure we aren't stepping past max iterations-          vm <- use uiVm+          vm <- use #vm           case maxIterationsReached vm ?maxIter of             Nothing -> pure $ Continue (k ())             Just n -> interpret mode (Stepper.evm (cont (not n)) >>= k)@@ -177,13 +181,13 @@          -- Stepper wants to make a query and wait for the results?         Stepper.IOAct q -> do-          Brick.zoom uiVm (StateT (runStateT q)) >>= interpret mode . k+          Brick.zoom (toLensVL #vm) (StateT (runStateT q)) >>= interpret mode . k          -- Stepper wants to modify the VM.         Stepper.EVM m -> do-          vm <- use uiVm+          vm <- use #vm           let (r, vm1) = runState m vm-          assign uiVm vm1+          assign #vm vm1           interpret mode (Stepper.exec >> (k r))  keepExecuting :: (?fetcher :: Fetcher@@ -204,7 +208,7 @@     interpret (Step (i - 1)) restart    StepUntil p -> do-    vm <- use uiVm+    vm <- use #vm     if p vm       then         interpret (Step 0) restart@@ -251,19 +255,19 @@   v <- mkVty   ui2 <- customMain v mkVty Nothing (app opts) (ViewVm ui0)   case ui2 of-    ViewVm ui -> return ui._uiVm+    ViewVm ui -> return ui.vm     _ -> error "internal error: customMain returned prematurely"   initUiVmState :: VM -> UnitTestOptions -> Stepper () -> UiVmState initUiVmState vm0 opts script =   UiVmState-    { _uiVm           = vm0-    , _uiStepper      = script-    , _uiStep         = 0-    , _uiSnapshots    = singleton 0 (vm0, script)-    , _uiShowMemory   = False-    , _uiTestOpts     = opts+    { vm           = vm0+    , stepper      = script+    , step         = 0+    , snapshots    = singleton 0 (vm0, script)+    , showMemory   = False+    , testOpts     = opts     }  @@ -290,7 +294,7 @@         let           dapp = dappInfo root contractMap sourceCache           ui = ViewPicker $ UiTestPickerState-            { _testPickerList =+            { tests =                 list                   TestPickerPane                   (Vec.fromList@@ -298,8 +302,8 @@                     (debuggableTests opts)                     dapp.unitTests))                   1-            , _testPickerDapp = dapp-            , _testOpts = opts+            , dapp = dapp+            , opts = opts             }         v <- mkVty         _ <- customMain v mkVty Nothing (app opts) (ui :: UiState)@@ -316,9 +320,9 @@     (Stopped (), _) ->       pure ()     (Continue steps, ui') ->-      put (ViewVm (ui' & set uiStepper steps))+      put (ViewVm (ui' & set #stepper steps))   where-    m = interpret mode ui._uiStepper+    m = interpret mode ui.stepper     nxt = runStateT m ui  backstepUntil@@ -327,32 +331,32 @@   => (UiVmState -> Pred VM) -> EventM n UiState () backstepUntil p = get >>= \case   ViewVm s ->-    case s._uiStep of+    case s.step of       0 -> pure ()       n -> do         s1 <- liftIO $ backstep s         let           -- find a previous vm that satisfies the predicate-          snapshots' = Data.Map.filter (p s1 . fst) s1._uiSnapshots+          snapshots' = Data.Map.filter (p s1 . fst) s1.snapshots         case lookupLT n snapshots' of           -- If no such vm exists, go to the beginning           Nothing ->             let-              (step', (vm', stepper')) = fromJust $ lookupLT (n - 1) s._uiSnapshots+              (step', (vm', stepper')) = fromJust $ lookupLT (n - 1) s.snapshots               s2 = s1-                & set uiVm vm'-                & set (uiVm . cache) s1._uiVm._cache-                & set uiStep step'-                & set uiStepper stepper'+                & set #vm vm'+                & set (#vm % #cache) s1.vm.cache+                & set #step step'+                & set #stepper stepper'             in takeStep s2 (Step 0)           -- step until the predicate doesn't hold           Just (step', (vm', stepper')) ->             let               s2 = s1-                & set uiVm vm'-                & set (uiVm . cache) s1._uiVm._cache-                & set uiStep step'-                & set uiStepper stepper'+                & set #vm vm'+                & set (#vm % #cache) s1.vm.cache+                & set #step step'+                & set #stepper stepper'             in takeStep s2 (StepUntil (not . p s1))   _ -> pure () @@ -361,7 +365,7 @@      ,?maxIter :: Maybe Integer)   => UiVmState -> IO UiVmState backstep s =-  case s._uiStep of+  case s.step of     -- We're already at the first step; ignore command.     0 -> pure s     -- To step backwards, we revert to the previous snapshot@@ -371,17 +375,17 @@     -- any blocking queries, and also the memory view.     n ->       let-        (step, (vm, stepper)) = fromJust $ lookupLT n s._uiSnapshots+        (step, (vm, stepper)) = fromJust $ lookupLT n s.snapshots         s1 = s-          & set uiVm vm-          & set (uiVm . cache) s._uiVm._cache-          & set uiStep step-          & set uiStepper stepper+          & set #vm vm+          & set (#vm % #cache) s.vm.cache+          & set #step step+          & set #stepper stepper         stepsToTake = n - step - 1        in         runStateT (interpret (Step stepsToTake) stepper) s1 >>= \case-          (Continue steps, ui') -> pure $ ui' & set uiStepper steps+          (Continue steps, ui') -> pure $ ui' & set #stepper steps           _ -> error "unexpected end"  appEvent@@ -393,7 +397,7 @@ appEvent (VtyEvent e@(V.EvKey V.KDown [])) = get >>= \case   ViewContracts _s -> do     Brick.zoom-      (_ViewContracts . browserContractList)+      (traverseOf $ _ViewContracts % #contracts)       (handleListEvent e)     pure ()   _ -> pure ()@@ -403,7 +407,7 @@ appEvent (VtyEvent e@(V.EvKey V.KUp [])) = get >>= \case   ViewContracts _s -> do     Brick.zoom-      (_ViewContracts . browserContractList)+      (traverseOf $ _ViewContracts % #contracts)       (handleListEvent e)   _ -> pure () @@ -411,19 +415,19 @@ -- Any: Esc - return to Vm Overview or Exit appEvent (VtyEvent (V.EvKey V.KEsc [])) = get >>= \case   ViewVm s -> do-    let opts = s ^. uiTestOpts+    let opts = s ^. #testOpts         dapp = opts.dapp         tests = concatMap (debuggableTests opts) dapp.unitTests     case tests of       [] -> halt       ts ->         put $ ViewPicker $ UiTestPickerState-          { _testPickerList = list TestPickerPane (Vec.fromList ts) 1-          , _testPickerDapp = dapp-          , _testOpts = opts+          { tests = list TestPickerPane (Vec.fromList ts) 1+          , dapp  = dapp+          , opts  = opts           }   ViewHelp s -> put (ViewVm s)-  ViewContracts s -> put (ViewVm $ s ^. browserVm)+  ViewContracts s -> put (ViewVm $ s ^. #vm)   _ -> halt  -- Vm Overview: Enter - open contracts view@@ -431,24 +435,24 @@ appEvent (VtyEvent (V.EvKey V.KEnter [])) = get >>= \case   ViewVm s ->     put . ViewContracts $ UiBrowserState-      { _browserContractList =+      { contracts =           list             BrowserPane-            (Vec.fromList (Map.toList s._uiVm._env._contracts))+            (Vec.fromList (Map.toList s.vm.env.contracts))             2-      , _browserVm = s+      , vm = s       }   ViewPicker s ->-    case listSelectedElement s._testPickerList of+    case listSelectedElement s.tests of       Nothing -> error "nothing selected"       Just (_, x) -> do-        let initVm  = initialUiVmStateForTest s._testOpts x+        let initVm  = initialUiVmStateForTest s.opts x         put (ViewVm initVm)   _ -> pure ()  -- Vm Overview: m - toggle memory pane appEvent (VtyEvent (V.EvKey (V.KChar 'm') [])) = get >>= \case-  ViewVm s -> put (ViewVm $ over uiShowMemory not s)+  ViewVm s -> put (ViewVm $ over #showMemory not s)   _ -> pure ()  -- Vm Overview: h - open help view@@ -476,28 +480,28 @@ -- Vm Overview: n - step appEvent (VtyEvent (V.EvKey (V.KChar 'n') [])) = get >>= \case   ViewVm s ->-    when (isNothing (s ^. uiVm . result)) $+    when (isNothing (s ^. #vm % #result)) $       takeStep s (Step 1)   _ -> pure ()  -- Vm Overview: N - step appEvent (VtyEvent (V.EvKey (V.KChar 'N') [])) = get >>= \case   ViewVm s ->-    when (isNothing (s ^. uiVm . result)) $+    when (isNothing (s ^. #vm % #result)) $       takeStep s (StepUntil (isNextSourcePosition s))   _ -> pure ()  -- Vm Overview: C-n - step appEvent (VtyEvent (V.EvKey (V.KChar 'n') [V.MCtrl])) = get >>= \case   ViewVm s ->-    when (isNothing (s ^. uiVm . result)) $+    when (isNothing (s ^. #vm % #result)) $       takeStep s (StepUntil (isNextSourcePositionWithoutEntering s))   _ -> pure ()  -- Vm Overview: e - step appEvent (VtyEvent (V.EvKey (V.KChar 'e') [])) = get >>= \case   ViewVm s ->-    when (isNothing (s ^. uiVm . result)) $+    when (isNothing (s ^. #vm % #result)) $       takeStep s (StepUntil (isExecutionHalted s))   _ -> pure () @@ -507,12 +511,12 @@     -- We keep the current cache so we don't have to redo     -- any blocking queries.     let-      (vm, stepper) = fromJust (Map.lookup 0 s._uiSnapshots)+      (vm, stepper) = fromJust (Map.lookup 0 s.snapshots)       s' = s-        & set uiVm vm-        & set (uiVm . cache) s._uiVm._cache-        & set uiStep 0-        & set uiStepper stepper+        & set #vm vm+        & set (#vm % #cache) s.vm.cache+        & set #step 0+        & set #stepper stepper      in takeStep s' (Step 0)   _ -> pure ()@@ -520,7 +524,7 @@ -- Vm Overview: p - backstep appEvent (VtyEvent (V.EvKey (V.KChar 'p') [])) = get >>= \case   ViewVm s ->-    case s._uiStep of+    case s.step of       0 ->         -- We're already at the first step; ignore command.         pure ()@@ -531,12 +535,12 @@         -- We keep the current cache so we don't have to redo         -- any blocking queries, and also the memory view.         let-          (step, (vm, stepper)) = fromJust $ lookupLT n s._uiSnapshots+          (step, (vm, stepper)) = fromJust $ lookupLT n s.snapshots           s1 = s-            & set uiVm vm -- set the vm to the one from the snapshot-            & set (uiVm . cache) s._uiVm._cache -- persist the cache-            & set uiStep step-            & set uiStepper stepper+            & set #vm vm -- set the vm to the one from the snapshot+            & set (#vm % #cache) s.vm.cache -- persist the cache+            & set #step step+            & set #stepper stepper           stepsToTake = n - step - 1          takeStep s1 (Step stepsToTake)@@ -553,9 +557,9 @@ -- Vm Overview: 0 - choose no jump appEvent (VtyEvent (V.EvKey (V.KChar '0') [])) = get >>= \case   ViewVm s ->-    case view (uiVm . result) s of+    case view (#vm % #result) s of       Just (VMFailure (Choose (PleaseChoosePath _ contin))) ->-        takeStep (s & set uiStepper (Stepper.evm (contin True) >> s._uiStepper))+        takeStep (s & set #stepper (Stepper.evm (contin True) >> s.stepper))           (Step 1)       _ -> pure ()   _ -> pure ()@@ -563,9 +567,9 @@ -- Vm Overview: 1 - choose jump appEvent (VtyEvent (V.EvKey (V.KChar '1') [])) = get >>= \case   ViewVm s ->-    case s._uiVm._result of+    case s.vm.result of       Just (VMFailure (Choose (PleaseChoosePath _ contin))) ->-        takeStep (s & set uiStepper (Stepper.evm (contin False) >> s._uiStepper))+        takeStep (s & set #stepper (Stepper.evm (contin False) >> s.stepper))           (Step 1)       _ -> pure ()   _ -> pure ()@@ -580,8 +584,7 @@  -- UnitTest Picker: (main) - render list appEvent (VtyEvent e) = do-  Brick.zoom-    (_ViewPicker . testPickerList)+  Brick.zoom (traverseOf (_ViewPicker % #tests))     (handleListEvent e)  -- Default@@ -690,7 +693,7 @@              withHighlight selected $                txt " Debug " <+> txt (contractNamePart x) <+> txt "::" <+> txt y)           True-          ui._testPickerList+          ui.tests   ]  drawVmBrowser :: UiBrowserState -> [UiWidget]@@ -707,14 +710,14 @@                    , "  ", pack (show k)                    ])               True-              ui._browserContractList+              ui.contracts       , case snd <$> Map.lookup (maybeHash c) dapp.solcByHash of           Nothing ->             hBox               [ borderWithLabel (txt "Contract information") . padBottom Max . padRight Max $ vBox-                  [ txt ("Codehash: " <> pack (show c._codehash))-                  , txt ("Nonce: "    <> showWordExact c._nonce)-                  , txt ("Balance: "  <> showWordExact c._balance)+                  [ txt ("Codehash: " <> pack (show c.codehash))+                  , txt ("Nonce: "    <> showWordExact c.nonce)+                  , txt ("Balance: "  <> showWordExact c.balance)                   --, txt ("Storage: "  <> storageDisplay (view storage c)) -- TODO: fix this                   ]                 ]@@ -738,10 +741,10 @@       ]   ]   where-    dapp = ui._browserVm._uiTestOpts.dapp-    (_, (_, c)) = fromJust $ listSelectedElement ui._browserContractList+    dapp = ui.vm.testOpts.dapp+    (_, (_, c)) = fromJust $ listSelectedElement ui.contracts --        currentContract  = view (dappSolcByHash . ix ) dapp-    maybeHash ch = fromJust (error "Internal error: cannot find concrete codehash for partially symbolic code") (maybeLitWord ch._codehash)+    maybeHash ch = fromJust (error "Internal error: cannot find concrete codehash for partially symbolic code") (maybeLitWord ch.codehash)  drawVm :: UiVmState -> [UiWidget] drawVm ui =@@ -794,36 +797,36 @@  stepOneOpcode :: Stepper a -> StateT UiVmState IO () stepOneOpcode restart = do-  n <- use uiStep+  n <- use #step   when (n > 0 && n `mod` snapshotInterval == 0) $ do-    vm <- use uiVm-    modifying uiSnapshots (insert n (vm, void restart))-  modifying uiVm (execState exec1)-  modifying uiStep (+ 1)+    vm <- use #vm+    modifying #snapshots (insert n (vm, void restart))+  modifying #vm (execState exec1)+  modifying #step (+ 1)  isNewTraceAdded   :: UiVmState -> Pred VM isNewTraceAdded ui vm =   let-    currentTraceTree = length <$> traceForest ui._uiVm+    currentTraceTree = length <$> traceForest ui.vm     newTraceTree = length <$> traceForest vm   in currentTraceTree /= newTraceTree  isNextSourcePosition   :: UiVmState -> Pred VM isNextSourcePosition ui vm =-  let dapp = ui._uiTestOpts.dapp-      initialPosition = currentSrcMap dapp ui._uiVm+  let dapp = ui.testOpts.dapp+      initialPosition = currentSrcMap dapp ui.vm   in currentSrcMap dapp vm /= initialPosition  isNextSourcePositionWithoutEntering   :: UiVmState -> Pred VM isNextSourcePositionWithoutEntering ui vm =   let-    dapp            = ui._uiTestOpts.dapp-    vm0             = ui._uiVm+    dapp            = ui.testOpts.dapp+    vm0             = ui.vm     initialPosition = currentSrcMap dapp vm0-    initialHeight   = length vm0._frames+    initialHeight   = length vm0.frames   in     case currentSrcMap dapp vm of       Nothing ->@@ -831,7 +834,7 @@       Just here ->         let           moved = Just here /= initialPosition-          deeper = length vm._frames > initialHeight+          deeper = length vm.frames > initialHeight           boring =             case srcMapCode dapp.sources here of               Just bs ->@@ -842,20 +845,20 @@            moved && not deeper && not boring  isExecutionHalted :: UiVmState -> Pred VM-isExecutionHalted _ vm = isJust vm._result+isExecutionHalted _ vm = isJust vm.result  currentSrcMap :: DappInfo -> VM -> Maybe SrcMap currentSrcMap dapp vm = do   this <- currentContract vm-  i <- this._opIxMap SVec.!? vm._state._pc+  i <- this.opIxMap SVec.!? vm.state.pc   srcMap dapp this i  drawStackPane :: UiVmState -> UiWidget drawStackPane ui =   let-    gasText = showWordExact (num ui._uiVm._state._gas)+    gasText = showWordExact (num ui.vm.state.gas)     labelText = txt ("Gas available: " <> gasText <> "; stack:")-    stackList = list StackPane (Vec.fromList $ zip [(1 :: Int)..] (simplify <$> ui._uiVm._state._stack)) 2+    stackList = list StackPane (Vec.fromList $ zip [(1 :: Int)..] (simplify <$> ui.vm.state.stack)) 2   in hBorderWithLabel labelText <=>     renderList       (\_ (i, w) ->@@ -864,14 +867,14 @@                <+> ourWrap (Text.unpack $ prettyIfConcreteWord w)            , dim (txt ("   " <> case unlit w of                        Nothing -> ""-                       Just u -> showWordExplanation u ui._uiTestOpts.dapp))+                       Just u -> showWordExplanation u ui.testOpts.dapp))            ])       False       stackList  message :: VM -> String message vm =-  case vm._result of+  case vm.result of     Just (VMSuccess (ConcreteBuf msg)) ->       "VMSuccess: " <> (show $ ByteStringS msg)     Just (VMSuccess (msg)) ->@@ -881,13 +884,13 @@     Just (VMFailure err) ->       "VMFailure: " <> show err     Nothing ->-      "Executing EVM code in " <> show vm._state._contract+      "Executing EVM code in " <> show vm.state.contract   drawBytecodePane :: UiVmState -> UiWidget drawBytecodePane ui =   let-    vm = ui._uiVm+    vm = ui.vm     move = maybe id listMoveTo $ vmOpIx vm   in     hBorderWithLabel (str $ message vm) <=>@@ -897,7 +900,7 @@                     else withDefAttr boldAttr (opWidget x))       False       (move $ list BytecodePane-        (maybe mempty (._codeOps) (currentContract vm))+        (maybe mempty (.codeOps) (currentContract vm))         1)  @@ -914,8 +917,8 @@  drawTracePane :: UiVmState -> UiWidget drawTracePane s =-  let vm = s._uiVm-      dapp = s._uiTestOpts.dapp+  let vm = s.vm+      dapp = s.testOpts.dapp       traceList =         list           TracePane@@ -925,20 +928,20 @@             $ vm)           1 -  in case s._uiShowMemory of+  in case s.showMemory of     True -> viewport TracePane Vertical $         hBorderWithLabel (txt "Calldata")-        <=> ourWrap (prettyIfConcrete vm._state._calldata)+        <=> ourWrap (prettyIfConcrete vm.state.calldata)         <=> hBorderWithLabel (txt "Returndata")-        <=> ourWrap (prettyIfConcrete vm._state._returndata)+        <=> ourWrap (prettyIfConcrete vm.state.returndata)         <=> hBorderWithLabel (txt "Output")-        <=> ourWrap (maybe "" show vm._result)+        <=> ourWrap (maybe "" show vm.result)         <=> hBorderWithLabel (txt "Cache")-        <=> ourWrap (show vm._cache._path)+        <=> ourWrap (show vm.cache.path)         <=> hBorderWithLabel (txt "Path Conditions")-        <=> (ourWrap $ show $ vm._constraints)+        <=> (ourWrap $ show $ vm.constraints)         <=> hBorderWithLabel (txt "Memory")-        <=> (ourWrap (prettyIfConcrete vm._state._memory))+        <=> (ourWrap (prettyIfConcrete vm.state.memory))     False ->       hBorderWithLabel (txt "Trace")       <=> renderList@@ -962,25 +965,27 @@     (case currentSrcMap dapp vm of         Nothing -> mempty         Just x ->-          view (-            ix x.srcMapFile-            . to (Vec.imap (,)))-          dapp.sources.lines)+          fromMaybe+            (error "Internal Error: unable to find line for source map")+            (preview (+              ix x.file+              % to (Vec.imap (,)))+            dapp.sources.lines))     1  drawSolidityPane :: UiVmState -> UiWidget drawSolidityPane ui =-  let dapp = ui._uiTestOpts.dapp+  let dapp = ui.testOpts.dapp       dappSrcs = dapp.sources-      vm = ui._uiVm+      vm = ui.vm   in case currentSrcMap dapp vm of     Nothing -> padBottom Max (hBorderWithLabel (txt "<no source map>"))     Just sm ->           let-            rows = dappSrcs.lines !! sm.srcMapFile-            subrange = lineSubrange rows (sm.srcMapOffset, sm.srcMapLength)+            rows = dappSrcs.lines !! sm.file+            subrange = lineSubrange rows (sm.offset, sm.length)             fileName :: Maybe Text-            fileName = preview (ix sm.srcMapFile . _1) dapp.sources.files+            fileName = preview (ix sm.file % _1) dapp.sources.files             lineNo :: Maybe Int             lineNo = ((\a -> Just (a - 1)) . snd) =<< srcMapCodePos dapp.sources sm           in vBox@@ -991,7 +996,7 @@                   -- Show the AST node type if present                   <+> txt (" (" <> fromMaybe "?"                                     (dapp.astSrcMap sm-                                       >>= preview (key "name" . _String)) <> ")")+                                       >>= preview (key "name" % _String)) <> ")")             , Centered.renderList                 (\_ (i, line) ->                    let s = case decodeUtf8 line of "" -> " "; y -> y@@ -1015,7 +1020,7 @@ ifTallEnough need w1 w2 =   Widget Greedy Greedy $ do     c <- getContext-    if view availHeightL c > need+    if view (lensVL availHeightL) c > need       then render w1       else render w2 
src/EVM/TTYCenteredList.hs view
@@ -2,7 +2,7 @@  -- Hard fork of brick's List that centers the currently highlighted line. -import Control.Lens+import Optics.Core import Data.Maybe (fromMaybe)  import Brick.Types@@ -31,15 +31,15 @@     Widget Greedy Greedy $ do         c <- getContext -        let es = V.slice start num (l^.listElementsL)-            idx = fromMaybe 0 (l^.listSelectedL)+        let es = V.slice start num (l ^. (lensVL listElementsL))+            idx = fromMaybe 0 (l ^. (lensVL listSelectedL))              start = max 0 $ idx - (initialNumPerHeight `div` 2)-            num = min (numPerHeight * 2) (V.length (l^.listElementsL) - start)+            num = min (numPerHeight * 2) (V.length (l ^. (lensVL listElementsL)) - start)              -- The number of items to show is the available height divided by             -- the item height...-            initialNumPerHeight = (c^.availHeightL) `div` (l^.listItemHeightL)+            initialNumPerHeight = (c ^. (lensVL availHeightL)) `div` (l ^. (lensVL listItemHeightL))             -- ... but if the available height leaves a remainder of             -- an item height then we need to ensure that we render an             -- extra item to show a partial item at the top or bottom to@@ -49,7 +49,7 @@             -- rendered with only its top 2 or bottom 2 rows visible,             -- depending on how the viewport state changes.)             numPerHeight = initialNumPerHeight +-                           if initialNumPerHeight * (l^.listItemHeightL) == c^.availHeightL+                           if initialNumPerHeight * (l ^. (lensVL listItemHeightL)) == c ^. (lensVL availHeightL)                            then 0                            else 1 @@ -66,6 +66,6 @@                                   else id                 in makeVisible elemWidget -        render $ viewport (l^.listNameL) Vertical $+        render $ viewport (l ^. (lensVL listNameL)) Vertical $                  -- translateBy (Location (0, off)) $                  vBox $ V.toList drawnElements
src/EVM/Transaction.hs view
@@ -3,15 +3,16 @@ import Prelude hiding (Word)  import qualified EVM-import EVM (balance, initialContract)+import EVM (initialContract) import EVM.FeeSchedule import EVM.RLP import EVM.Types import EVM.Expr (litAddr)-import Control.Lens import EVM.Sign -import Data.ByteString (ByteString)+import Optics.Core hiding (cons)++import Data.ByteString (ByteString, cons) import Data.Map (Map) import Data.Maybe (fromMaybe, isNothing, fromJust) import GHC.Generics (Generic)@@ -25,8 +26,8 @@ import Numeric (showHex)  data AccessListEntry = AccessListEntry {-  accessAddress :: Addr,-  accessStorageKeys :: [W256]+  address :: Addr,+  storageKeys :: [W256] } deriving (Show, Generic)  instance JSON.ToJSON AccessListEntry@@ -44,130 +45,130 @@   data Transaction = Transaction {-    txData     :: ByteString,-    txGasLimit :: Word64,-    txGasPrice :: Maybe W256,-    txNonce    :: W256,-    txR        :: W256,-    txS        :: W256,-    txToAddr   :: Maybe Addr,-    txV        :: W256,-    txValue    :: W256,-    txType     :: TxType,-    txAccessList :: [AccessListEntry],-    txMaxPriorityFeeGas :: Maybe W256,-    txMaxFeePerGas :: Maybe W256,-    txChainId  :: W256+    txdata            :: ByteString,+    gasLimit          :: Word64,+    gasPrice          :: Maybe W256,+    nonce             :: W256,+    r                 :: W256,+    s                 :: W256,+    toAddr            :: Maybe Addr,+    v                 :: W256,+    value             :: W256,+    txtype            :: TxType,+    accessList        :: [AccessListEntry],+    maxPriorityFeeGas :: Maybe W256,+    maxFeePerGas      :: Maybe W256,+    chainId           :: W256 } deriving (Show, Generic)  instance JSON.ToJSON Transaction where-  toJSON t = JSON.object [ ("input",             (JSON.toJSON (ByteStringS t.txData)))-                         , ("gas",               (JSON.toJSON $ "0x" ++ showHex (toInteger $ t.txGasLimit) ""))-                         , ("gasPrice",          (JSON.toJSON $ show $ fromJust $ t.txGasPrice))-                         , ("v",                 (JSON.toJSON $ show $ (t.txV)-27))-                         , ("r",                 (JSON.toJSON $ show $ t.txR))-                         , ("s",                 (JSON.toJSON $ show $ t.txS))-                         , ("to",                (JSON.toJSON $ t.txToAddr))-                         , ("nonce",             (JSON.toJSON $ show $ t.txNonce))-                         , ("value",             (JSON.toJSON $ show $ t.txValue))-                         , ("type",              (JSON.toJSON $ t.txType))-                         , ("accessList",        (JSON.toJSON $ t.txAccessList))-                         , ("maxPriorityFeePerGas", (JSON.toJSON $ show $ fromJust $ t.txMaxPriorityFeeGas))-                         , ("maxFeePerGas",      (JSON.toJSON $ show $ fromJust $ t.txMaxFeePerGas))-                         , ("chainId",           (JSON.toJSON $ show t.txChainId))+  toJSON t = JSON.object [ ("input",             (JSON.toJSON (ByteStringS t.txdata)))+                         , ("gas",               (JSON.toJSON $ "0x" ++ showHex (toInteger $ t.gasLimit) ""))+                         , ("gasPrice",          (JSON.toJSON $ show $ fromJust $ t.gasPrice))+                         , ("v",                 (JSON.toJSON $ show $ (t.v)-27))+                         , ("r",                 (JSON.toJSON $ show $ t.r))+                         , ("s",                 (JSON.toJSON $ show $ t.s))+                         , ("to",                (JSON.toJSON $ t.toAddr))+                         , ("nonce",             (JSON.toJSON $ show $ t.nonce))+                         , ("value",             (JSON.toJSON $ show $ t.value))+                         , ("type",              (JSON.toJSON $ t.txtype))+                         , ("accessList",        (JSON.toJSON $ t.accessList))+                         , ("maxPriorityFeePerGas", (JSON.toJSON $ show $ fromJust $ t.maxPriorityFeeGas))+                         , ("maxFeePerGas",      (JSON.toJSON $ show $ fromJust $ t.maxFeePerGas))+                         , ("chainId",           (JSON.toJSON $ show t.chainId))                          ]  emptyTransaction :: Transaction-emptyTransaction = Transaction { txData = mempty-                               , txGasLimit = 0-                               , txGasPrice = Nothing-                               , txNonce = 0-                               , txR = 0-                               , txS = 0-                               , txToAddr = Nothing-                               , txV = 0-                               , txValue = 0-                               , txType = EIP1559Transaction-                               , txAccessList = []-                               , txMaxPriorityFeeGas = Nothing-                               , txMaxFeePerGas = Nothing-                               , txChainId = 1+emptyTransaction = Transaction { txdata = mempty+                               , gasLimit = 0+                               , gasPrice = Nothing+                               , nonce = 0+                               , r = 0+                               , s = 0+                               , toAddr = Nothing+                               , v = 0+                               , value = 0+                               , txtype = EIP1559Transaction+                               , accessList = []+                               , maxPriorityFeeGas = Nothing+                               , maxFeePerGas = Nothing+                               , chainId = 1                                }  -- | utility function for getting a more useful representation of accesslistentries -- duplicates only matter for gas computation txAccessMap :: Transaction -> Map Addr [W256]-txAccessMap tx = ((Map.fromListWith (++)) . makeTups) tx.txAccessList-  where makeTups = map (\ale -> (ale.accessAddress , ale.accessStorageKeys ))+txAccessMap tx = ((Map.fromListWith (++)) . makeTups) tx.accessList+  where makeTups = map (\ale -> (ale.address , ale.storageKeys ))  -- Given Transaction, it recovers the address that sent it sender :: Transaction -> Maybe Addr-sender tx = ecrec v' tx.txR  tx.txS hash+sender tx = ecrec v' tx.r  tx.s hash   where hash = keccak' (signingData tx)-        v    = tx.txV+        v    = tx.v         v'   = if v == 27 || v == 28 then v                else 27 + v  sign :: Integer -> Transaction -> Transaction-sign sk tx = tx { txV = num v, txR = r, txS = s}+sign sk tx = tx { v = num v, r = r, s = s}   where     hash = keccak' $ signingData tx     (v, r, s) = EVM.Sign.sign hash sk  signingData :: Transaction -> ByteString signingData tx =-  case tx.txType of-    LegacyTransaction -> if v == (tx.txChainId * 2 + 35) || v == (tx.txChainId * 2 + 36)+  case tx.txtype of+    LegacyTransaction -> if v == (tx.chainId * 2 + 35) || v == (tx.chainId * 2 + 36)       then eip155Data       else normalData     AccessListTransaction -> eip2930Data     EIP1559Transaction -> eip1559Data-  where v          = fromIntegral tx.txV-        to'        = case tx.txToAddr of+  where v          = fromIntegral tx.v+        to'        = case tx.toAddr of           Just a  -> BS $ word160Bytes a           Nothing -> BS mempty-        maxFee = fromJust tx.txMaxFeePerGas-        maxPrio = fromJust tx.txMaxPriorityFeeGas-        gasPrice = fromJust tx.txGasPrice-        accessList = tx.txAccessList+        maxFee = fromJust tx.maxFeePerGas+        maxPrio = fromJust tx.maxPriorityFeeGas+        gasPrice = fromJust tx.gasPrice+        accessList = tx.accessList         rlpAccessList = EVM.RLP.List $ map (\accessEntry ->-          EVM.RLP.List [BS $ word160Bytes accessEntry.accessAddress,-                        EVM.RLP.List $ map rlpWordFull accessEntry.accessStorageKeys]+          EVM.RLP.List [BS $ word160Bytes accessEntry.address,+                        EVM.RLP.List $ map rlpWordFull accessEntry.storageKeys]           ) accessList-        normalData = rlpList [rlpWord256 tx.txNonce,+        normalData = rlpList [rlpWord256 tx.nonce,                               rlpWord256 gasPrice,-                              rlpWord256 (num tx.txGasLimit),+                              rlpWord256 (num tx.gasLimit),                               to',-                              rlpWord256 tx.txValue,-                              BS tx.txData]-        eip155Data = rlpList [rlpWord256 tx.txNonce,+                              rlpWord256 tx.value,+                              BS tx.txdata]+        eip155Data = rlpList [rlpWord256 tx.nonce,                               rlpWord256 gasPrice,-                              rlpWord256 (num tx.txGasLimit),+                              rlpWord256 (num tx.gasLimit),                               to',-                              rlpWord256 tx.txValue,-                              BS tx.txData,-                              rlpWord256 tx.txChainId,+                              rlpWord256 tx.value,+                              BS tx.txdata,+                              rlpWord256 tx.chainId,                               rlpWord256 0x0,                               rlpWord256 0x0]         eip1559Data = cons 0x02 $ rlpList [-          rlpWord256 tx.txChainId,-          rlpWord256 tx.txNonce,+          rlpWord256 tx.chainId,+          rlpWord256 tx.nonce,           rlpWord256 maxPrio,           rlpWord256 maxFee,-          rlpWord256 (num tx.txGasLimit),+          rlpWord256 (num tx.gasLimit),           to',-          rlpWord256 tx.txValue,-          BS tx.txData,+          rlpWord256 tx.value,+          BS tx.txdata,           rlpAccessList]          eip2930Data = cons 0x01 $ rlpList [-          rlpWord256 tx.txChainId,-          rlpWord256 tx.txNonce,+          rlpWord256 tx.chainId,+          rlpWord256 tx.nonce,           rlpWord256 gasPrice,-          rlpWord256 (num tx.txGasLimit),+          rlpWord256 (num tx.gasLimit),           to',-          rlpWord256 tx.txValue,-          BS tx.txData,+          rlpWord256 tx.value,+          BS tx.txdata,           rlpAccessList]  accessListPrice :: FeeSchedule Word64 -> [AccessListEntry] -> Word64@@ -175,17 +176,17 @@     sum (map       (\ale ->         fs.g_access_list_address  +-        (fs.g_access_list_storage_key  * (fromIntegral . length) ale.accessStorageKeys))+        (fs.g_access_list_storage_key  * (fromIntegral . length) ale.storageKeys))         al)  txGasCost :: FeeSchedule Word64 -> Transaction -> Word64 txGasCost fs tx =-  let calldata     = tx.txData+  let calldata     = tx.txdata       zeroBytes    = BS.count 0 calldata       nonZeroBytes = BS.length calldata - zeroBytes       baseCost     = fs.g_transaction-        + (if isNothing tx.txToAddr then fs.g_txcreate else 0)-        + (accessListPrice fs tx.txAccessList )+        + (if isNothing tx.toAddr then fs.g_txcreate else 0)+        + (accessListPrice fs tx.accessList )       zeroCost     = fs.g_txdatazero       nonZeroCost  = fs.g_txdatanonzero   in baseCost + zeroCost * (fromIntegral zeroBytes) + nonZeroCost * (fromIntegral nonZeroBytes)@@ -226,7 +227,7 @@     JSON.typeMismatch "Transaction" invalid  accountAt :: Addr -> Getter (Map Addr EVM.Contract) EVM.Contract-accountAt a = (at a) . (to $ fromMaybe newAccount)+accountAt a = (at a) % (to $ fromMaybe newAccount)  touchAccount :: Addr -> Map Addr EVM.Contract -> Map Addr EVM.Contract touchAccount a = Map.insertWith (flip const) a newAccount@@ -238,8 +239,8 @@ setupTx :: Addr -> Addr -> W256 -> Word64 -> Map Addr EVM.Contract -> Map Addr EVM.Contract setupTx origin coinbase gasPrice gasLimit prestate =   let gasCost = gasPrice * (num gasLimit)-  in (Map.adjust ((over EVM.nonce   (+ 1))-               . (over balance (subtract gasCost))) origin)+  in (Map.adjust ((over #nonce   (+ 1))+               . (over #balance (subtract gasCost))) origin)     . touchAccount origin     . touchAccount coinbase $ prestate @@ -248,22 +249,22 @@ -- and pay receiving address initTx :: EVM.VM -> EVM.VM initTx vm = let-    toAddr   = vm._state._contract-    origin   = vm._tx._origin-    gasPrice = vm._tx._gasprice-    gasLimit = vm._tx._txgaslimit-    coinbase = vm._block._coinbase-    value    = vm._state._callvalue-    toContract = initialContract vm._state._code-    preState = setupTx origin coinbase gasPrice gasLimit vm._env._contracts-    oldBalance = view (accountAt toAddr . balance) preState-    creation = vm._tx._isCreate+    toAddr   = vm.state.contract+    origin   = vm.tx.origin+    gasPrice = vm.tx.gasprice+    gasLimit = vm.tx.gaslimit+    coinbase = vm.block.coinbase+    value    = vm.state.callvalue+    toContract = initialContract vm.state.code+    preState = setupTx origin coinbase gasPrice gasLimit vm.env.contracts+    oldBalance = view (accountAt toAddr % #balance) preState+    creation = vm.tx.isCreate     initState = (case unlit value of-      Just v -> ((Map.adjust (over balance (subtract v))) origin)-              . (Map.adjust (over balance (+ v))) toAddr+      Just v -> ((Map.adjust (over #balance (subtract v))) origin)+              . (Map.adjust (over #balance (+ v))) toAddr       Nothing -> id)       . (if creation-         then Map.insert toAddr (toContract & balance .~ oldBalance)+         then Map.insert toAddr (toContract & #balance .~ oldBalance)          else touchAccount toAddr)       $ preState @@ -274,7 +275,7 @@     resetStore (SStore {}) = error "cannot reset storage if it contains symbolic addresses"     resetStore s = s     in-      vm & EVM.env . EVM.contracts .~ initState-         & EVM.tx . EVM.txReversion .~ preState-         & EVM.env . EVM.storage %~ resetStore-         & EVM.env . EVM.origStorage %~ resetConcreteStore+      vm & #env % #contracts .~ initState+         & #tx % #txReversion .~ preState+         & #env % #storage %~ resetStore+         & #env % #origStorage %~ resetConcreteStore
src/EVM/Types.hs view
@@ -55,8 +55,8 @@  newtype W256 = W256 Word256   deriving-    ( Num, Integral, Real, Ord, Generic-    , Bits , FiniteBits, Enum, Eq , Bounded+    ( Num, Integral, Real, Ord, Bits+    , Generic, FiniteBits, Enum, Eq , Bounded     )  {- |@@ -141,7 +141,6 @@ deriving instance Ord (GVar a)  --- add type level list of constraints data Expr (a :: EType) where    -- identifiers@@ -453,6 +452,10 @@   PImpl a b <= PImpl c d = a <= c && b <= d   _ <= _ = False +-- | https://docs.soliditylang.org/en/v0.8.19/abi-spec.html#function-selector+newtype FunctionSelector = FunctionSelector { unFunctionSelector :: Word32 }+  deriving (Num, Eq, Ord, Real, Enum, Integral)+instance Show FunctionSelector where show s = "0x" <> showHex s ""  unlit :: Expr EWord -> Maybe W256 unlit (Lit x) = Just x@@ -743,12 +746,13 @@ keccak' :: ByteString -> W256 keccak' = keccakBytes >>> BS.take 32 >>> word -abiKeccak :: ByteString -> Word32+abiKeccak :: ByteString -> FunctionSelector abiKeccak =   keccakBytes     >>> BS.take 4     >>> BS.unpack     >>> word32+    >>> FunctionSelector  -- Utils 
src/EVM/UnitTest.hs view
@@ -30,7 +30,10 @@ import EVM.Stepper qualified as Stepper  import Control.Monad.Operational qualified as Operational-import Control.Lens hiding (Indexed, elements, List, passing)+import Optics.Core hiding (elements)+import Optics.State+import Optics.State.Operators+import Optics.Zoom import Control.Monad.Par.Class (spawn_) import Control.Monad.Par.Class qualified as Par import Control.Monad.Par.IO (runParIO)@@ -83,22 +86,22 @@   }  data TestVMParams = TestVMParams-  { testAddress       :: Addr-  , testCaller        :: Addr-  , testOrigin        :: Addr-  , testGasCreate     :: Word64-  , testGasCall       :: Word64-  , testBaseFee       :: W256-  , testPriorityFee   :: W256-  , testBalanceCreate :: W256-  , testCoinbase      :: Addr-  , testNumber        :: W256-  , testTimestamp     :: W256-  , testGaslimit      :: Word64-  , testGasprice      :: W256-  , testMaxCodeSize   :: W256-  , testPrevrandao    :: W256-  , testChainId       :: W256+  { address       :: Addr+  , caller        :: Addr+  , origin        :: Addr+  , gasCreate     :: Word64+  , gasCall       :: Word64+  , baseFee       :: W256+  , priorityFee   :: W256+  , balanceCreate :: W256+  , coinbase      :: Addr+  , number        :: W256+  , timestamp     :: W256+  , gaslimit      :: Word64+  , gasprice      :: W256+  , maxCodeSize   :: W256+  , prevrandao    :: W256+  , chainId       :: W256   }  defaultGasForCreating :: Word64@@ -140,7 +143,7 @@         Just path ->           -- merge all of the post-vm caches and save into the state           let-            evmcache = mconcat [vm._cache | vm <- vms]+            evmcache = mconcat [vm.cache | vm <- vms]           in             liftIO $ Git.saveFacts (Git.RepoAt path) (Facts.cacheFacts evmcache) @@ -152,13 +155,13 @@ -- | 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 -> SolcContract -> Stepper ()-initializeUnitTest UnitTestOptions { .. } theContract = do+initializeUnitTest opts theContract = do -  let addr = testParams.testAddress+  let addr = opts.testParams.address    Stepper.evm $ do     -- Maybe modify the initial VM, e.g. to load library code-    modify vmModifier+    modify opts.vmModifier     -- Make a trace entry for running the constructor     pushTrace (EntryTrace "constructor") @@ -167,14 +170,14 @@    Stepper.evm $ do     -- Give a balance to the test target-    env . contracts . ix addr . balance += testParams.testBalanceCreate+    #env % #contracts % ix addr % #balance %= (+ opts.testParams.balanceCreate)      -- call setUp(), if it exists, to initialize the test contract     let theAbi = theContract.abiMap         setUp  = abiKeccak (encodeUtf8 "setUp()")      when (isJust (Map.lookup setUp theAbi)) $ do-      abiCall testParams (Left ("setUp()", emptyAbi))+      abiCall opts.testParams (Left ("setUp()", emptyAbi))       popTrace       pushTrace (EntryTrace "setUp()") @@ -206,13 +209,13 @@ exploreStep :: UnitTestOptions -> ByteString -> Stepper Bool exploreStep UnitTestOptions{..} bs = do   Stepper.evm $ do-    cs <- use (env . contracts)+    cs <- use (#env % #contracts)     abiCall testParams (Right bs)     let (Method _ inputs sig _ _) = fromMaybe (error "unknown abi call") $ Map.lookup (num $ word $ BS.take 4 bs) dapp.abiMap         types = snd <$> inputs     let ?context = DappContext dapp cs-    this <- fromMaybe (error "unknown target") <$> (use (env . contracts . at testParams.testAddress))-    let name = maybe "" (contractNamePart . (.contractName)) $ lookupCode this._contractcode dapp+    this <- fromMaybe (error "unknown target") <$> (use (#env % #contracts % at testParams.address))+    let name = maybe "" (contractNamePart . (.contractName)) $ lookupCode this.contractcode dapp     pushTrace (EntryTrace (name <> "." <> sig <> "(" <> intercalate "," ((pack . show) <$> types) <> ")" <> showCall types (ConcreteBuf bs)))   -- Try running the test method   Stepper.execFully >>= \case@@ -244,7 +247,7 @@ fuzzTest :: UnitTestOptions -> Text -> [AbiType] -> VM -> Property fuzzTest opts@UnitTestOptions{..} sig types vm = forAllShow (genAbiValue (AbiTupleType $ Vector.fromList types)) (show . ByteStringS . encodeAbiValue)   $ \args -> ioProperty $-    fst <$> runStateT (EVM.Stepper.interpret (Fetch.oracle solvers rpcInfo) (runUnitTest opts sig args)) vm+    EVM.Stepper.interpret (Fetch.oracle solvers rpcInfo) vm (runUnitTest opts sig args)  tick :: Text -> IO () tick x = Text.putStr x >> hFlush stdout@@ -256,10 +259,10 @@   } deriving (Show)  instance Eq OpLocation where-  (==) (OpLocation a b) (OpLocation a' b') = b == b' && a._contractcode == a'._contractcode+  (==) (OpLocation a b) (OpLocation a' b') = b == b' && a.contractcode == a'.contractcode  instance Ord OpLocation where-  compare (OpLocation a b) (OpLocation a' b') = compare (a._contractcode, b) (a'._contractcode, b')+  compare (OpLocation a b) (OpLocation a' b') = compare (a.contractcode, b) (a'.contractcode, b')  srcMapForOpLocation :: DappInfo -> OpLocation -> Maybe SrcMap srcMapForOpLocation dapp (OpLocation contr opIx) = srcMap dapp contr opIx@@ -278,14 +281,14 @@  execWithCoverage :: StateT CoverageState IO VMResult execWithCoverage = do _ <- runWithCoverage-                      fromJust <$> use (_1 . result)+                      fromJust <$> use (_1 % #result)  runWithCoverage :: StateT CoverageState IO VM runWithCoverage = do   -- This is just like `exec` except for every instruction evaluated,   -- we also increment a counter indexed by the current code location.   vm0 <- use _1-  case vm0._result of+  case vm0.result of     Nothing -> do       vm1 <- zoom _1 (State.state (runState exec1) >> get)       zoom _2 (modify (MultiSet.insert (currentOpLocation vm1)))@@ -430,13 +433,12 @@     Just theContract -> do       -- Construct the initial VM and begin the contract's constructor       let vm0 = initialUnitTestVm opts theContract-      vm1 <--        liftIO $ execStateT-          (EVM.Stepper.interpret (Fetch.oracle solvers rpcInfo)-            (Stepper.enter name >> initializeUnitTest opts theContract))-          vm0+      vm1 <- liftIO $ EVM.Stepper.interpret (Fetch.oracle solvers rpcInfo) vm0 $ do+        Stepper.enter name+        initializeUnitTest opts theContract+        Stepper.evm get -      case vm1._result of+      case vm1.result of         Nothing -> error "internal error: setUp() did not end with a result"         Just (VMFailure _) -> liftIO $ do           Text.putStrLn "\x1b[31m[BAIL]\x1b[0m setUp() "@@ -451,7 +453,7 @@             runCache (results, vm) (test, types) = do               (t, r, vm') <- runTest opts vm (test, types)               liftIO $ Text.putStrLn t-              let vmCached = vm { _cache = vm'._cache }+              let vmCached = vm { cache = vm'.cache }               pure (((r, vm'): results), vmCached)            -- Run all the test cases and print their status updates,@@ -517,8 +519,8 @@      Nothing ->       Stepper.evmIO $ do        vm <- get-       let cs = vm._env._contracts-           noCode c = case c._contractcode of+       let cs = vm.env.contracts+           noCode c = case c.contractcode of              RuntimeCode (ConcreteRuntimeCode "") -> True              RuntimeCode (SymbolicRuntimeCode c') -> null c'              _ -> False@@ -532,11 +534,11 @@              -- exclude testing abis              Map.filter (isNothing . preview (ix unitTestMarkerAbi) . (.abiMap)) $              -- pick all contracts with known compiler artifacts-             fmap fromJust (Map.filter isJust $ Map.fromList [(addr, lookupCode c._contractcode dapp) | (addr, c)  <- Map.toList cs])+             fmap fromJust (Map.filter isJust $ Map.fromList [(addr, lookupCode c.contractcode dapp) | (addr, c)  <- Map.toList cs])            selected = [(addr,                         fromMaybe (error ("no src found for: " <> show addr)) $                           lookupCode (fromMaybe (error $ "contract not found: " <> show addr) $-                            Map.lookup addr cs)._contractcode dapp)+                            Map.lookup addr cs).contractcode dapp)                        | addr  <- targets]        -- go to IO and generate a random valid call to any known contract        liftIO $ do@@ -559,17 +561,17 @@          let cd = abiMethod (sig <> "(" <> intercalate "," ((pack . show) <$> types) <> ")") args          -- increment timestamp with random amount          timepassed <- num <$> generate (arbitrarySizedNatural :: Gen Word32)-         let ts = fromMaybe (error "symbolic timestamp not supported here") $ maybeLitWord vm._block._timestamp+         let ts = fromMaybe (error "symbolic timestamp not supported here") $ maybeLitWord vm.block.timestamp          return (caller', target, cd, num ts + timepassed)- let opts' = opts { testParams = testParams {testAddress = target, testCaller = caller', testTimestamp = timestamp'}}+ let opts' = opts { testParams = testParams {address = target, caller = caller', timestamp = timestamp'}}      thisCallRLP = List [BS $ word160Bytes caller', BS $ word160Bytes target, BS cd, BS $ word256Bytes timestamp']  -- set the timestamp- Stepper.evm $ assign (block . timestamp) (Lit timestamp')+ Stepper.evm $ assign (#block % #timestamp) (Lit timestamp')  -- perform the call  bailed <- exploreStep opts' cd  Stepper.evm popTrace  let newHistory = if bailed then List history else List (thisCallRLP:history)-     opts'' = opts {testParams = testParams {testTimestamp = timestamp'}}+     opts'' = opts {testParams = testParams {timestamp = timestamp'}}      carryOn = explorationStepper opts'' testName replayData targets newHistory (i - 1)  -- if we didn't revert, run the test function  if bailed@@ -585,7 +587,7 @@ getTargetContracts UnitTestOptions{..} = do   vm <- Stepper.evm get   let contract' = fromJust $ currentContract vm-      theAbi = (fromJust $ lookupCode contract'._contractcode dapp).abiMap+      theAbi = (fromJust $ lookupCode contract'.contractcode dapp).abiMap       setUp  = abiKeccak (encodeUtf8 "targetContracts()")   case Map.lookup setUp theAbi of     Nothing -> return []@@ -609,18 +611,21 @@ exploreRun :: UnitTestOptions -> VM -> ABIMethod -> [ExploreTx] -> IO (Text, Either Text Text, VM) exploreRun opts@UnitTestOptions{..} initialVm testName replayTxs = do   let oracle = Fetch.oracle solvers rpcInfo-  (targets, _) <- runStateT (EVM.Stepper.interpret oracle (getTargetContracts opts)) initialVm+  targets <- EVM.Stepper.interpret oracle initialVm (getTargetContracts opts)   let depth = fromMaybe 20 maxDepth   ((x, counterex), vm') <--    if null replayTxs-    then-    foldM (\a@((success, _), _) _ ->-                       if success-                       then runStateT (EVM.Stepper.interpret oracle (initialExplorationStepper opts testName [] targets depth)) initialVm-                       else pure a)-                       ((True, (List [])), initialVm)  -- no canonical "post vm"-                       [0..fuzzRuns]-    else runStateT (EVM.Stepper.interpret oracle (initialExplorationStepper opts testName replayTxs targets (length replayTxs))) initialVm+    if null replayTxs then+      foldM (\a@((success, _),_) _ ->+               if success then+                 EVM.Stepper.interpret oracle initialVm $+                   (,) <$> initialExplorationStepper opts testName [] targets depth+                       <*> Stepper.evm get+               else pure a)+            ((True, (List [])), initialVm)  -- no canonical "post vm"+            [0..fuzzRuns]+    else EVM.Stepper.interpret oracle initialVm $+      (,) <$> initialExplorationStepper opts testName replayTxs targets (length replayTxs)+          <*> Stepper.evm get   if x   then return ("\x1b[32m[PASS]\x1b[0m " <> testName <>  " (runs: " <> (pack $ show fuzzRuns) <>", depth: " <> pack (show depth) <> ")",                Right (passOutput vm' opts testName), vm') -- no canonical "post vm"@@ -631,21 +636,21 @@  execTest :: UnitTestOptions -> VM -> ABIMethod -> AbiValue -> IO (Bool, VM) execTest opts@UnitTestOptions{..} vm testName args =-  runStateT-    (EVM.Stepper.interpret (Fetch.oracle solvers rpcInfo) (execTestStepper opts testName args))-    vm+  EVM.Stepper.interpret (Fetch.oracle solvers rpcInfo) vm $ do+    (,) <$> execTestStepper opts testName args+        <*> Stepper.evm get  -- | Define the thread spawner for normal test cases runOne :: UnitTestOptions -> VM -> ABIMethod -> AbiValue -> IO (Text, Either Text Text, VM) runOne opts@UnitTestOptions{..} vm testName args = do   let argInfo = pack (if args == emptyAbi then "" else " with arguments: " <> show args)   (bailed, vm') <- execTest opts vm testName args-  (success, vm'') <--    runStateT-      (EVM.Stepper.interpret (Fetch.oracle solvers rpcInfo) (checkFailures opts testName bailed)) vm'+  (success, vm'') <- EVM.Stepper.interpret (Fetch.oracle solvers rpcInfo) vm' $ do+    (,) <$> (checkFailures opts testName bailed)+        <*> Stepper.evm get   if success   then-     let gasSpent = num testParams.testGasCall - vm'._state._gas+     let gasSpent = num testParams.gasCall - vm'.state.gas          gasText = pack $ show (fromIntegral gasSpent :: Integer)      in         pure@@ -693,7 +698,8 @@           ppOutput = pack $ show abiValue       in do         -- Run the failing test again to get a proper trace-        vm' <- execStateT (EVM.Stepper.interpret (Fetch.oracle solvers rpcInfo) (runUnitTest opts testName abiValue)) vm+        vm' <- EVM.Stepper.interpret (Fetch.oracle solvers rpcInfo) vm $+          runUnitTest opts testName abiValue >> Stepper.evm get         pure ("\x1b[31m[FAIL]\x1b[0m "                <> testName <> ". Counterexample: " <> ppOutput                <> "\nRun:\n dapp test --replay '(\"" <> testName <> "\",\""@@ -713,7 +719,7 @@ symRun opts@UnitTestOptions{..} vm testName types = do     let cd = symCalldata testName types [] (AbstractBuf "txdata")         shouldFail = "proveFail" `isPrefixOf` testName-        testContract = vm._state._contract+        testContract = vm.state.contract      -- define postcondition depending on `shouldFail`     -- We directly encode the failure conditions from failed() in ds-test since this is easier to encode than a call into failed()@@ -729,11 +735,11 @@                                    Return _ _ store -> PNeg (failed store)                                    _ -> PBool False -    (_, vm') <- runStateT-      (EVM.Stepper.interpret (Fetch.oracle solvers rpcInfo) (Stepper.evm $ do-          popTrace-          makeTxCall testParams cd-        )) vm+    vm' <- EVM.Stepper.interpret (Fetch.oracle solvers rpcInfo) vm $+      Stepper.evm $ do+        popTrace+        makeTxCall testParams cd+        get      -- check postconditions against vm     (_, results) <- verify solvers (makeVeriOpts opts) vm' (Just postcondition)@@ -827,7 +833,7 @@  passOutput :: VM -> UnitTestOptions -> Text -> Text passOutput vm UnitTestOptions { .. } testName =-  let ?context = DappContext { info = dapp, env = vm._env._contracts }+  let ?context = DappContext { info = dapp, env = vm.env.contracts }   in let v = fromMaybe 0 verbose   in if (v > 1) then     mconcat@@ -835,7 +841,7 @@       , fromMaybe "" (stripSuffix "()" testName)       , "\n"       , if (v > 2) then indentLines 2 (showTraceTree dapp vm) else ""-      , indentLines 2 (formatTestLogs dapp.eventMap vm._logs)+      , indentLines 2 (formatTestLogs dapp.eventMap vm.logs)       , "\n"       ]     else ""@@ -843,7 +849,7 @@ -- TODO failOutput :: VM -> UnitTestOptions -> Text -> Text failOutput vm UnitTestOptions { .. } testName =-  let ?context = DappContext { info = dapp, env = vm._env._contracts}+  let ?context = DappContext { info = dapp, env = vm.env.contracts }   in mconcat   [ "Failure: "   , fromMaybe "" (stripSuffix "()" testName)@@ -851,7 +857,7 @@   , case verbose of       Just _ -> indentLines 2 (showTraceTree dapp vm)       _ -> ""-  , indentLines 2 (formatTestLogs dapp.eventMap vm._logs)+  , indentLines 2 (formatTestLogs dapp.eventMap vm.logs)   , "\n"   ] @@ -934,55 +940,54 @@   in makeTxCall params (ConcreteBuf cd, [])  makeTxCall :: TestVMParams -> (Expr Buf, [Prop]) -> EVM ()-makeTxCall TestVMParams{..} (cd, cdProps) = do+makeTxCall params (cd, cdProps) = do   resetState-  assign (tx . isCreate) False-  loadContract testAddress-  assign (state . EVM.calldata) cd-  constraints %= (<> cdProps)-  assign (state . caller) (litAddr testCaller)-  assign (state . gas) testGasCall-  origin' <- fromMaybe (initialContract (RuntimeCode (ConcreteRuntimeCode ""))) <$> use (env . contracts . at testOrigin)-  let originBal = origin'._balance-  when (originBal < testGasprice * (num testGasCall)) $ error "insufficient balance for gas cost"+  assign (#tx % #isCreate) False+  loadContract params.address+  assign (#state % #calldata) cd+  #constraints %= (<> cdProps)+  assign (#state % #caller) (litAddr params.caller)+  assign (#state % #gas) params.gasCall+  origin' <- fromMaybe (initialContract (RuntimeCode (ConcreteRuntimeCode ""))) <$> use (#env % #contracts % at params.origin)+  let originBal = origin'.balance+  when (originBal < params.gasprice * (num params.gasCall)) $ error "insufficient balance for gas cost"   vm <- get   put $ initTx vm  initialUnitTestVm :: UnitTestOptions -> SolcContract -> VM initialUnitTestVm (UnitTestOptions {..}) theContract =   let-    TestVMParams {..} = testParams     vm = makeVm $ VMOpts-           { vmoptContract = initialContract (InitCode theContract.creationCode mempty)-           , vmoptCalldata = mempty-           , vmoptValue = Lit 0-           , vmoptAddress = testAddress-           , vmoptCaller = litAddr testCaller-           , vmoptOrigin = testOrigin-           , vmoptGas = testGasCreate-           , vmoptGaslimit = testGasCreate-           , vmoptCoinbase = testCoinbase-           , vmoptNumber = testNumber-           , vmoptTimestamp = Lit testTimestamp-           , vmoptBlockGaslimit = testGaslimit-           , vmoptGasprice = testGasprice-           , vmoptBaseFee = testBaseFee-           , vmoptPriorityFee = testPriorityFee-           , vmoptMaxCodeSize = testMaxCodeSize-           , vmoptPrevRandao = testPrevrandao-           , vmoptSchedule = FeeSchedule.berlin-           , vmoptChainId = testChainId-           , vmoptCreate = True-           , vmoptStorageBase = Concrete-           , vmoptTxAccessList = mempty -- TODO: support unit test access lists???-           , vmoptAllowFFI = ffiAllowed+           { contract = initialContract (InitCode theContract.creationCode mempty)+           , calldata = mempty+           , value = Lit 0+           , address = testParams.address+           , caller = litAddr testParams.caller+           , origin = testParams.origin+           , gas = testParams.gasCreate+           , gaslimit = testParams.gasCreate+           , coinbase = testParams.coinbase+           , number = testParams.number+           , timestamp = Lit testParams.timestamp+           , blockGaslimit = testParams.gaslimit+           , gasprice = testParams.gasprice+           , baseFee = testParams.baseFee+           , priorityFee = testParams.priorityFee+           , maxCodeSize = testParams.maxCodeSize+           , prevRandao = testParams.prevrandao+           , schedule = FeeSchedule.berlin+           , chainId = testParams.chainId+           , create = True+           , initialStorage = EmptyStore+           , txAccessList = mempty -- TODO: support unit test access lists???+           , allowFFI = ffiAllowed            }     creator =       initialContract (RuntimeCode (ConcreteRuntimeCode ""))-        & set nonce 1-        & set balance testBalanceCreate+        & set #nonce 1+        & set #balance testParams.balanceCreate   in vm-    & set (env . contracts . at ethrunAddress) (Just creator)+    & set (#env % #contracts % at ethrunAddress) (Just creator)   getParametersFromEnvironmentVariables :: Maybe Text -> IO TestVMParams@@ -994,12 +999,12 @@       Nothing  -> return (0,Lit 0,0,0,0,0)       Just url -> Fetch.fetchBlockFrom block' url >>= \case         Nothing -> error "Could not fetch block"-        Just EVM.Block{..} -> return (  _coinbase-                                      , _timestamp-                                      , _number-                                      , _prevRandao-                                      , _gaslimit-                                      , _baseFee+        Just EVM.Block{..} -> return (  coinbase+                                      , timestamp+                                      , number+                                      , prevRandao+                                      , gaslimit+                                      , baseFee                                       )   let     getWord s def = maybe def read <$> lookupEnv s
test/BlockchainTests.hs view
@@ -1,457 +1,9 @@-{-# LANGUAGE ImportQualifiedPost #-}-{-# LANGUAGE TupleSections #-}- module Main where -import Prelude hiding (Word)--import EVM qualified-import EVM (contractcode, storage, origStorage, balance, nonce, initialContract, StorageBase(..))-import EVM.Concrete qualified as EVM-import EVM.Dapp (emptyDapp)-import EVM.Expr (litAddr)-import EVM.FeeSchedule qualified-import EVM.Fetch qualified-import EVM.Stepper qualified-import EVM.Solvers (withSolvers, Solver(Z3))-import EVM.Transaction-import EVM.TTY qualified as TTY-import EVM.Types--import Control.Arrow ((***), (&&&))-import Control.Lens-import Control.Monad-import Control.Monad.State.Strict (execStateT)-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)-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 System.FilePath.Find qualified as Find-import System.FilePath.Posix (makeRelative, (</>))-import Witherable (Filterable, catMaybes)-+import EVM.Test.BlockchainTests import Test.Tasty-import Test.Tasty.ExpectedFailure-import Test.Tasty.HUnit -type Storage = Map W256 W256--data Which = Pre | Post--data Block = Block-  { blockCoinbase    :: Addr-  , blockDifficulty  :: W256-  , blockGasLimit    :: Word64-  , blockBaseFee     :: W256-  , blockNumber      :: W256-  , blockTimestamp   :: W256-  , blockTxs         :: [Transaction]-  } deriving Show--data Case = Case-  { testVmOpts      :: EVM.VMOpts-  , checkContracts  :: Map Addr (EVM.Contract, Storage)-  , testExpectation :: Map Addr (EVM.Contract, Storage)-  } deriving Show--data BlockchainCase = BlockchainCase-  { blockchainBlocks  :: [Block]-  , blockchainPre     :: Map Addr (EVM.Contract, Storage)-  , blockchainPost    :: Map Addr (EVM.Contract, Storage)-  , blockchainNetwork :: String-  } deriving Show- main :: IO () main = do   tests <- prepareTests   defaultMain tests--prepareTests :: IO TestTree-prepareTests = do-  repo <- getEnv "HEVM_ETHEREUM_TESTS_REPO"-  let testsDir = "BlockchainTests/GeneralStateTests"-  let dir = repo </> testsDir-  jsonFiles <- Find.find Find.always (Find.extension Find.==? ".json") dir-  putStrLn "Loading and parsing json files from ethereum-tests..."-  isCI <- 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-  putStrLn "Loaded."-  pure $ testGroup "ethereum-tests" groups--testsFromFile :: String -> Map String (TestTree -> TestTree) -> IO [TestTree]-testsFromFile file problematicTests = do-  parsed <- parseBCSuite <$> LazyByteString.readFile file-  case parsed of-   Left "No cases to check." -> pure [] -- error "no-cases ok"-   Left _err -> pure [] -- error err-   Right allTests -> pure $-     (\(name, x) -> testCase' name $ runVMTest False (name, x)) <$> Map.toList allTests-  where-  testCase' name assertion =-    case Map.lookup name problematicTests of-      Just f -> f (testCase name assertion)-      Nothing -> testCase name assertion---- CI has issues with some heaver tests, disable in bulk-ciIgnoredFiles :: [String]-ciIgnoredFiles = []--commonProblematicTests :: Map String (TestTree -> TestTree)-commonProblematicTests = Map.fromList-  [ ("loopMul_d0g0v0_London", ignoreTestBecause "hevm is too slow")-  , ("loopMul_d1g0v0_London", ignoreTestBecause "hevm is too slow")-  , ("loopMul_d2g0v0_London", ignoreTestBecause "hevm is too slow")-  , ("CALLBlake2f_MaxRounds_d0g0v0_London", ignoreTestBecause "very slow, bypasses timeout due time spent in FFI")-  ]--ciProblematicTests :: Map String (TestTree -> TestTree)-ciProblematicTests = Map.fromList-  [ ("Return50000_d0g1v0_London", ignoreTest)-  , ("Return50000_2_d0g1v0_London", ignoreTest)-  , ("randomStatetest177_d0g0v0_London", ignoreTest)-  , ("static_Call50000_d0g0v0_London", ignoreTest)-  , ("static_Call50000_d1g0v0_London", ignoreTest)-  , ("static_Call50000bytesContract50_1_d1g0v0_London", ignoreTest)-  , ("static_Call50000bytesContract50_2_d1g0v0_London", ignoreTest)-  , ("static_Return50000_2_d0g0v0_London", ignoreTest)-  , ("loopExp_d10g0v0_London", ignoreTest)-  , ("loopExp_d11g0v0_London", ignoreTest)-  , ("loopExp_d12g0v0_London", ignoreTest)-  , ("loopExp_d13g0v0_London", ignoreTest)-  , ("loopExp_d14g0v0_London", ignoreTest)-  , ("loopExp_d8g0v0_London", ignoreTest)-  , ("loopExp_d9g0v0_London", ignoreTest)-  ]--runVMTest :: Bool -> (String, Case) -> IO ()-runVMTest diffmode (_name, x) =- do-  let vm0 = vmForCase x-  result <- execStateT (EVM.Stepper.interpret (EVM.Fetch.zero 0 (Just 0)) . void $ EVM.Stepper.execFully) vm0-  maybeReason <- checkExpectation diffmode x result-  case maybeReason of-    Just reason -> assertFailure reason-    Nothing -> pure ()---- | Example usage:--- | $ cabal new-repl ethereum-tests--- | ghci> debugVMTest "BlockchainTests/GeneralStateTests/VMTests/vmArithmeticTest/twoOps.json" "twoOps_d0g0v0_London"-debugVMTest :: String -> String -> IO ()-debugVMTest file test = do-  repo <- getEnv "HEVM_ETHEREUM_TESTS_REPO"-  Right allTests <- parseBCSuite <$> LazyByteString.readFile (repo </> file)-  let x = case filter (\(name, _) -> name == test) $ Map.toList allTests of-        [(_, x')] -> x'-        _ -> error "test not found"-  let vm0 = vmForCase x-  result <- withSolvers Z3 0 Nothing $ \solvers ->-    TTY.runFromVM solvers Nothing Nothing emptyDapp vm0-  void $ checkExpectation True x result--splitEithers :: (Filterable f) => f (Either a b) -> (f a, f b)-splitEithers =-  (catMaybes *** catMaybes)-  . (fmap fst &&& fmap snd)-  . (fmap (preview _Left &&& preview _Right))--checkStateFail :: Bool -> Case -> EVM.VM -> (Bool, Bool, Bool, Bool) -> IO String-checkStateFail diff x vm (okMoney, okNonce, okData, okCode) = do-  let-    printContracts :: Map Addr (EVM.Contract, Storage) -> IO ()-    printContracts cs = putStrLn $ Map.foldrWithKey (\k (c, s) acc ->-      acc ++ show k ++ " : "-                   ++ (show . toInteger  $ (view nonce c)) ++ " "-                   ++ (show . toInteger  $ (view balance c)) ++ " "-                   ++ (printStorage s)-        ++ "\n") "" cs--    reason = map fst (filter (not . snd)-        [ ("bad-state",       okMoney || okNonce || okData  || okCode)-        , ("bad-balance", not okMoney || okNonce || okData  || okCode)-        , ("bad-nonce",   not okNonce || okMoney || okData  || okCode)-        , ("bad-storage", not okData  || okMoney || okNonce || okCode)-        , ("bad-code",    not okCode  || okMoney || okNonce || okData)-        ])-    check = x.checkContracts-    expected = x.testExpectation-    actual = Map.map (,mempty) $ view (EVM.env . EVM.contracts) vm -- . to (fmap (clearZeroStorage.clearOrigStorage))) vm-    printStorage = show -- TODO: fixme--  when diff $ do-    putStr (unwords reason)-    putStrLn "\nPre balance/state: "-    printContracts check-    putStrLn "\nExpected balance/state: "-    printContracts expected-    putStrLn "\nActual balance/state: "-    printContracts actual-  pure (unwords reason)--checkExpectation :: Bool -> Case -> EVM.VM -> IO (Maybe String)-checkExpectation diff x vm = do-  let expectation = x.testExpectation-      (okState, b2, b3, b4, b5) = checkExpectedContracts vm expectation-  if okState then-    pure Nothing-  else-    Just <$> checkStateFail diff x vm (b2, b3, b4, b5)---- quotient account state by nullness-(~=) :: Map Addr (EVM.Contract, Storage) -> Map Addr (EVM.Contract, Storage) -> Bool-(~=) cs1 cs2 =-    let nullAccount = EVM.initialContract (EVM.RuntimeCode (EVM.ConcreteRuntimeCode ""))-        padNewAccounts cs ks = Map.union cs $ Map.fromList [(k, (nullAccount, mempty)) | 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)--(===) :: (EVM.Contract, Storage) -> (EVM.Contract, Storage) -> Bool-(c1, s1) === (c2, s2) =-  codeEqual && storageEqual && (c1 ^. balance == c2 ^. balance) && (c1 ^. nonce ==  c2 ^. nonce)-  where-    storageEqual = s1 == s2-    codeEqual = case (c1 ^. contractcode, c2 ^. contractcode) of-      (EVM.RuntimeCode a', EVM.RuntimeCode b') -> a' == b'-      _ -> error "unexpected code"--checkExpectedContracts :: EVM.VM -> Map Addr (EVM.Contract, Storage) -> (Bool, Bool, Bool, Bool, Bool)-checkExpectedContracts vm expected =-  let cs = zipWithStorages $ vm ^. EVM.env . EVM.contracts -- . to (fmap (clearZeroStorage.clearOrigStorage))-      expectedCs = clearStorage <$> expected-  in ( (expectedCs ~= cs)-     , (clearBalance <$> expectedCs) ~= (clearBalance <$> cs)-     , (clearNonce   <$> expectedCs) ~= (clearNonce   <$> cs)-     , (clearStorage <$> expectedCs) ~= (clearStorage <$> cs)-     , (clearCode    <$> expectedCs) ~= (clearCode    <$> cs)-     )-  where-  zipWithStorages = Map.mapWithKey (\addr c -> (c, lookupStorage addr))-  lookupStorage _ =-    case vm ^. EVM.env . EVM.storage of-      ConcreteStore _ -> mempty -- clearZeroStorage $ fromMaybe mempty $ Map.lookup (num addr) s-      EmptyStore -> mempty-      AbstractStore -> mempty -- error "AbstractStore, should this be handled?"-      SStore {} -> mempty -- error "SStore, should this be handled?"-      GVar _ -> error "unexpected global variable"--clearStorage :: (EVM.Contract, Storage) -> (EVM.Contract, Storage)-clearStorage (c, _) = (c, mempty)--clearBalance :: (EVM.Contract, Storage) -> (EVM.Contract, Storage)-clearBalance (c, s) = (set balance 0 c, s)--clearNonce :: (EVM.Contract, Storage) -> (EVM.Contract, Storage)-clearNonce (c, s) = (set nonce 0 c, s)--clearCode :: (EVM.Contract, Storage) -> (EVM.Contract, Storage)-clearCode (c, s) = (set contractcode (EVM.RuntimeCode (EVM.ConcreteRuntimeCode "")) c, s)--newtype ContractWithStorage = ContractWithStorage (EVM.Contract, Storage)--instance FromJSON ContractWithStorage where-  parseJSON (JSON.Object v) = do-    code <- (EVM.RuntimeCode . EVM.ConcreteRuntimeCode <$> (hexText <$> v .: "code"))-    storage' <- v .: "storage"-    balance' <- v .: "balance"-    nonce'   <- v .: "nonce"-    let c = EVM.initialContract code-              & balance .~ balance'-              & nonce   .~ nonce'-    return $ ContractWithStorage (c, storage')--  parseJSON invalid =-    JSON.typeMismatch "Contract" invalid--instance FromJSON BlockchainCase where-  parseJSON (JSON.Object v) = BlockchainCase-    <$> v .: "blocks"-    <*> parseContracts Pre v-    <*> parseContracts Post v-    <*> v .: "network"-  parseJSON invalid =-    JSON.typeMismatch "GeneralState test case" invalid--instance FromJSON Block where-  parseJSON (JSON.Object v) = do-    v'         <- v .: "blockHeader"-    txs        <- v .: "transactions"-    coinbase   <- addrField v' "coinbase"-    difficulty <- wordField v' "difficulty"-    gasLimit   <- word64Field v' "gasLimit"-    number     <- wordField v' "number"-    baseFee    <- fmap read <$> v' .:? "baseFeePerGas"-    timestamp  <- wordField v' "timestamp"-    return $ Block coinbase difficulty gasLimit (fromMaybe 0 baseFee) number timestamp txs-  parseJSON invalid =-    JSON.typeMismatch "Block" invalid--parseContracts ::-  Which -> JSON.Object -> JSON.Parser (Map Addr (EVM.Contract, Storage))-parseContracts w v =-  (Map.map unwrap) <$> (v .: which >>= parseJSON)-  where which = case w of-          Pre  -> "pre"-          Post -> "postState"-        unwrap (ContractWithStorage x) = x--parseBCSuite ::-  Lazy.ByteString -> Either String (Map String Case)-parseBCSuite x = case (JSON.eitherDecode' x) :: Either String (Map String BlockchainCase) of-  Left e        -> Left e-  Right bcCases -> let allCases = fromBlockchainCase <$> bcCases-                       keepError (Left e) = errorFatal e-                       keepError _        = True-                       filteredCases = Map.filter keepError allCases-                       (erroredCases, parsedCases) = splitEithers filteredCases-    in if Map.size erroredCases > 0-    then Left ("errored case: " ++ (show erroredCases))-    else if Map.size parsedCases == 0-    then Left "No cases to check."-    else Right parsedCases---data BlockchainError-  = TooManyBlocks-  | TooManyTxs-  | NoTxs-  | SignatureUnverified-  | InvalidTx-  | OldNetwork-  | FailedCreate-  deriving Show--errorFatal :: BlockchainError -> Bool-errorFatal TooManyBlocks = True-errorFatal TooManyTxs = True-errorFatal SignatureUnverified = True-errorFatal InvalidTx = True-errorFatal _ = False--fromBlockchainCase :: BlockchainCase -> Either BlockchainError Case-fromBlockchainCase (BlockchainCase blocks preState postState network) =-  case (blocks, network) of-    ([block], "London") -> case block.blockTxs of-      [tx] -> fromBlockchainCase' block tx preState postState-      []        -> Left NoTxs-      _         -> Left TooManyTxs-    ([_], _) -> Left OldNetwork-    (_, _)   -> Left TooManyBlocks--fromBlockchainCase' :: Block -> Transaction-                       -> Map Addr (EVM.Contract, Storage) -> Map Addr (EVM.Contract, Storage)-                       -> Either BlockchainError Case-fromBlockchainCase' block tx preState postState =-  let isCreate = isNothing tx.txToAddr in-  case (sender tx, checkTx tx block preState) of-      (Nothing, _) -> Left SignatureUnverified-      (_, Nothing) -> Left (if isCreate then FailedCreate else InvalidTx)-      (Just origin, Just checkState) -> Right $ Case-        (EVM.VMOpts-         { vmoptContract      = EVM.initialContract theCode-         , vmoptCalldata      = (cd, [])-         , vmoptValue         = Lit tx.txValue-         , vmoptAddress       = toAddr-         , vmoptCaller        = litAddr origin-         , vmoptStorageBase   = Concrete-         , vmoptOrigin        = origin-         , vmoptGas           = tx.txGasLimit  - fromIntegral (txGasCost feeSchedule tx)-         , vmoptBaseFee       = block.blockBaseFee-         , vmoptPriorityFee   = priorityFee tx block.blockBaseFee-         , vmoptGaslimit      = tx.txGasLimit-         , vmoptNumber        = block.blockNumber-         , vmoptTimestamp     = Lit block.blockTimestamp-         , vmoptCoinbase      = block.blockCoinbase-         , vmoptPrevRandao    = block.blockDifficulty-         , vmoptMaxCodeSize   = 24576-         , vmoptBlockGaslimit = block.blockGasLimit-         , vmoptGasprice      = effectiveGasPrice-         , vmoptSchedule      = feeSchedule-         , vmoptChainId       = 1-         , vmoptCreate        = isCreate-         , vmoptTxAccessList  = txAccessMap tx-         , vmoptAllowFFI      = False-         })-        checkState-        postState-          where-            toAddr = fromMaybe (EVM.createAddress origin senderNonce) tx.txToAddr-            senderNonce = view (accountAt origin . nonce) (Map.map fst preState)-            feeSchedule = EVM.FeeSchedule.berlin-            toCode = Map.lookup toAddr preState-            theCode = if isCreate-                      then EVM.InitCode tx.txData mempty-                      else maybe (EVM.RuntimeCode (EVM.ConcreteRuntimeCode "")) (view contractcode . fst) toCode-            effectiveGasPrice = effectiveprice tx block.blockBaseFee-            cd = if isCreate-                 then mempty-                 else ConcreteBuf tx.txData--effectiveprice :: Transaction -> W256 -> W256-effectiveprice tx baseFee = priorityFee tx baseFee + baseFee--priorityFee :: Transaction -> W256 -> W256-priorityFee tx baseFee = let-    (txPrioMax, txMaxFee) = case tx.txType of-               EIP1559Transaction ->-                 let maxPrio = fromJust tx.txMaxPriorityFeeGas-                     maxFee = fromJust tx.txMaxFeePerGas-                 in (maxPrio, maxFee)-               _ ->-                 let gasPrice = fromJust tx.txGasPrice-                 in (gasPrice, gasPrice)-  in min txPrioMax (txMaxFee - baseFee)--maxBaseFee :: Transaction -> W256-maxBaseFee tx =-  case tx.txType of-     EIP1559Transaction -> fromJust tx.txMaxFeePerGas-     _ -> fromJust tx.txGasPrice--validateTx :: Transaction -> Block -> Map Addr (EVM.Contract, Storage) -> Maybe ()-validateTx tx block cs = do-  let cs' = Map.map fst cs-  origin        <- sender tx-  originBalance <- (view balance) <$> view (at origin) cs'-  originNonce   <- (view nonce)   <$> view (at origin) cs'-  let gasDeposit = (effectiveprice tx block.blockBaseFee) * (num tx.txGasLimit)-  if gasDeposit + tx.txValue <= originBalance-    && tx.txNonce == originNonce && block.blockBaseFee <= maxBaseFee tx-  then Just ()-  else Nothing--checkTx :: Transaction -> Block -> Map Addr (EVM.Contract, Storage) -> Maybe (Map Addr (EVM.Contract, Storage))-checkTx tx block prestate = do-  origin <- sender tx-  validateTx tx block prestate-  let isCreate   = isNothing tx.txToAddr-      senderNonce = view (accountAt origin . nonce) (Map.map fst prestate)-      toAddr      = fromMaybe (EVM.createAddress origin senderNonce) tx.txToAddr-      prevCode    = view (accountAt toAddr . contractcode) (Map.map fst prestate)-      prevNonce   = view (accountAt toAddr . nonce) (Map.map fst prestate)-  if isCreate && ((case prevCode of {EVM.RuntimeCode (EVM.ConcreteRuntimeCode b) -> not (BS.null b); _ -> True}) || (prevNonce /= 0))-  then mzero-  else-    return prestate--vmForCase :: Case -> EVM.VM-vmForCase x =-  let-    a = x.checkContracts-    cs = Map.map fst a-    st = Map.mapKeys num $ Map.map snd a-    vm = EVM.makeVm x.testVmOpts-      & set (EVM.env . EVM.contracts) cs-      & set (EVM.env . EVM.storage) (ConcreteStore st)-      & set (EVM.env . EVM.origStorage) st-  in-    initTx vm
+ test/EVM/Test/BlockchainTests.hs view
@@ -0,0 +1,448 @@+module EVM.Test.BlockchainTests where++import Prelude hiding (Word)++import EVM qualified+import EVM (initialContract)+import EVM.Concrete qualified as EVM+import EVM.Dapp (emptyDapp)+import EVM.Expr (litAddr)+import EVM.FeeSchedule qualified+import EVM.Fetch qualified+import EVM.Stepper qualified+import EVM.Solvers (withSolvers, Solver(Z3))+import EVM.Transaction+import EVM.TTY qualified as TTY+import EVM.Types++import Control.Arrow ((***), (&&&))+import Optics.Core+import Control.Monad+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)+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 System.FilePath.Find qualified as Find+import System.FilePath.Posix (makeRelative, (</>))+import Witherable (Filterable, catMaybes)++import Test.Tasty+import Test.Tasty.ExpectedFailure+import Test.Tasty.HUnit++type Storage = Map W256 W256++data Which = Pre | Post++data Block = Block+  { coinbase    :: Addr+  , difficulty  :: W256+  , gasLimit    :: Word64+  , baseFee     :: W256+  , number      :: W256+  , timestamp   :: W256+  , txs         :: [Transaction]+  } deriving Show++data Case = Case+  { vmOpts      :: EVM.VMOpts+  , checkContracts  :: Map Addr (EVM.Contract, Storage)+  , testExpectation :: Map Addr (EVM.Contract, Storage)+  } deriving Show++data BlockchainCase = BlockchainCase+  { blocks  :: [Block]+  , pre     :: Map Addr (EVM.Contract, Storage)+  , post    :: Map Addr (EVM.Contract, Storage)+  , network :: String+  } deriving Show++main :: IO ()+main = do+  tests <- prepareTests+  defaultMain tests++prepareTests :: IO TestTree+prepareTests = do+  repo <- getEnv "HEVM_ETHEREUM_TESTS_REPO"+  let testsDir = "BlockchainTests/GeneralStateTests"+  let dir = repo </> testsDir+  jsonFiles <- Find.find Find.always (Find.extension Find.==? ".json") dir+  putStrLn "Loading and parsing json files from ethereum-tests..."+  isCI <- 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+  putStrLn "Loaded."+  pure $ testGroup "ethereum-tests" groups++testsFromFile :: String -> Map String (TestTree -> TestTree) -> IO [TestTree]+testsFromFile file problematicTests = do+  parsed <- parseBCSuite <$> LazyByteString.readFile file+  case parsed of+   Left "No cases to check." -> pure [] -- error "no-cases ok"+   Left _err -> pure [] -- error err+   Right allTests -> pure $+     (\(name, x) -> testCase' name $ runVMTest False (name, x)) <$> Map.toList allTests+  where+  testCase' name assertion =+    case Map.lookup name problematicTests of+      Just f -> f (testCase name assertion)+      Nothing -> testCase name assertion++-- CI has issues with some heaver tests, disable in bulk+ciIgnoredFiles :: [String]+ciIgnoredFiles = []++commonProblematicTests :: Map String (TestTree -> TestTree)+commonProblematicTests = Map.fromList+  [ ("loopMul_d0g0v0_London", ignoreTestBecause "hevm is too slow")+  , ("loopMul_d1g0v0_London", ignoreTestBecause "hevm is too slow")+  , ("loopMul_d2g0v0_London", ignoreTestBecause "hevm is too slow")+  , ("CALLBlake2f_MaxRounds_d0g0v0_London", ignoreTestBecause "very slow, bypasses timeout due time spent in FFI")+  ]++ciProblematicTests :: Map String (TestTree -> TestTree)+ciProblematicTests = Map.fromList+  [ ("Return50000_d0g1v0_London", ignoreTest)+  , ("Return50000_2_d0g1v0_London", ignoreTest)+  , ("randomStatetest177_d0g0v0_London", ignoreTest)+  , ("static_Call50000_d0g0v0_London", ignoreTest)+  , ("static_Call50000_d1g0v0_London", ignoreTest)+  , ("static_Call50000bytesContract50_1_d1g0v0_London", ignoreTest)+  , ("static_Call50000bytesContract50_2_d1g0v0_London", ignoreTest)+  , ("static_Return50000_2_d0g0v0_London", ignoreTest)+  , ("loopExp_d10g0v0_London", ignoreTest)+  , ("loopExp_d11g0v0_London", ignoreTest)+  , ("loopExp_d12g0v0_London", ignoreTest)+  , ("loopExp_d13g0v0_London", ignoreTest)+  , ("loopExp_d14g0v0_London", ignoreTest)+  , ("loopExp_d8g0v0_London", ignoreTest)+  , ("loopExp_d9g0v0_London", ignoreTest)+  ]++runVMTest :: Bool -> (String, Case) -> IO ()+runVMTest diffmode (_name, x) = do+  let vm0 = vmForCase x+  result <- EVM.Stepper.interpret (EVM.Fetch.zero 0 (Just 0)) vm0 EVM.Stepper.runFully+  maybeReason <- checkExpectation diffmode x result+  forM_ maybeReason assertFailure++-- | Example usage:+-- $ cabal new-repl ethereum-tests+-- ghci> debugVMTest "BlockchainTests/GeneralStateTests/VMTests/vmArithmeticTest/twoOps.json" "twoOps_d0g0v0_London"+debugVMTest :: String -> String -> IO ()+debugVMTest file test = do+  repo <- getEnv "HEVM_ETHEREUM_TESTS_REPO"+  Right allTests <- parseBCSuite <$> LazyByteString.readFile (repo </> file)+  let x = case filter (\(name, _) -> name == test) $ Map.toList allTests of+        [(_, x')] -> x'+        _ -> error "test not found"+  let vm0 = vmForCase x+  result <- withSolvers Z3 0 Nothing $ \solvers ->+    TTY.runFromVM solvers Nothing Nothing emptyDapp vm0+  void $ checkExpectation True x result++splitEithers :: (Filterable f) => f (Either a b) -> (f a, f b)+splitEithers =+  (catMaybes *** catMaybes)+  . (fmap fst &&& fmap snd)+  . (fmap (preview _Left &&& preview _Right))++checkStateFail :: Bool -> Case -> EVM.VM -> (Bool, Bool, Bool, Bool) -> IO String+checkStateFail diff x vm (okMoney, okNonce, okData, okCode) = do+  let+    printContracts :: Map Addr (EVM.Contract, Storage) -> IO ()+    printContracts cs = putStrLn $ Map.foldrWithKey (\k (c, s) acc ->+      acc ++ show k ++ " : "+                   ++ (show . toInteger  $ (view #nonce c)) ++ " "+                   ++ (show . toInteger  $ (view #balance c)) ++ " "+                   ++ (printStorage s)+        ++ "\n") "" cs++    reason = map fst (filter (not . snd)+        [ ("bad-state",       okMoney || okNonce || okData  || okCode)+        , ("bad-balance", not okMoney || okNonce || okData  || okCode)+        , ("bad-nonce",   not okNonce || okMoney || okData  || okCode)+        , ("bad-storage", not okData  || okMoney || okNonce || okCode)+        , ("bad-code",    not okCode  || okMoney || okNonce || okData)+        ])+    check = x.checkContracts+    expected = x.testExpectation+    actual = Map.map (,mempty) $ view (#env % #contracts) vm -- . to (fmap (clearZeroStorage.clearOrigStorage))) vm+    printStorage = show -- TODO: fixme++  when diff $ do+    putStr (unwords reason)+    putStrLn "\nPre balance/state: "+    printContracts check+    putStrLn "\nExpected balance/state: "+    printContracts expected+    putStrLn "\nActual balance/state: "+    printContracts actual+  pure (unwords reason)++checkExpectation :: Bool -> Case -> EVM.VM -> IO (Maybe String)+checkExpectation diff x vm = do+  let expectation = x.testExpectation+      (okState, b2, b3, b4, b5) = checkExpectedContracts vm expectation+  if okState then+    pure Nothing+  else+    Just <$> checkStateFail diff x vm (b2, b3, b4, b5)++-- quotient account state by nullness+(~=) :: Map Addr (EVM.Contract, Storage) -> Map Addr (EVM.Contract, Storage) -> Bool+(~=) cs1 cs2 =+    let nullAccount = EVM.initialContract (EVM.RuntimeCode (EVM.ConcreteRuntimeCode ""))+        padNewAccounts cs ks = Map.union cs $ Map.fromList [(k, (nullAccount, mempty)) | 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)++(===) :: (EVM.Contract, Storage) -> (EVM.Contract, Storage) -> Bool+(c1, s1) === (c2, s2) =+  codeEqual && storageEqual && (c1 ^. #balance == c2 ^. #balance) && (c1 ^. #nonce ==  c2 ^. #nonce)+  where+    storageEqual = s1 == s2+    codeEqual = case (c1 ^. #contractcode, c2 ^. #contractcode) of+      (EVM.RuntimeCode a', EVM.RuntimeCode b') -> a' == b'+      _ -> error "unexpected code"++checkExpectedContracts :: EVM.VM -> Map Addr (EVM.Contract, Storage) -> (Bool, Bool, Bool, Bool, Bool)+checkExpectedContracts vm expected =+  let cs = zipWithStorages $ vm ^. #env % #contracts -- . to (fmap (clearZeroStorage.clearOrigStorage))+      expectedCs = clearStorage <$> expected+  in ( (expectedCs ~= cs)+     , (clearBalance <$> expectedCs) ~= (clearBalance <$> cs)+     , (clearNonce   <$> expectedCs) ~= (clearNonce   <$> cs)+     , (clearStorage <$> expectedCs) ~= (clearStorage <$> cs)+     , (clearCode    <$> expectedCs) ~= (clearCode    <$> cs)+     )+  where+  zipWithStorages = Map.mapWithKey (\addr c -> (c, lookupStorage addr))+  lookupStorage _ =+    case vm ^. #env % #storage of+      ConcreteStore _ -> mempty -- clearZeroStorage $ fromMaybe mempty $ Map.lookup (num addr) s+      EmptyStore -> mempty+      AbstractStore -> mempty -- error "AbstractStore, should this be handled?"+      SStore {} -> mempty -- error "SStore, should this be handled?"+      GVar _ -> error "unexpected global variable"++clearStorage :: (EVM.Contract, Storage) -> (EVM.Contract, Storage)+clearStorage (c, _) = (c, mempty)++clearBalance :: (EVM.Contract, Storage) -> (EVM.Contract, Storage)+clearBalance (c, s) = (set #balance 0 c, s)++clearNonce :: (EVM.Contract, Storage) -> (EVM.Contract, Storage)+clearNonce (c, s) = (set #nonce 0 c, s)++clearCode :: (EVM.Contract, Storage) -> (EVM.Contract, Storage)+clearCode (c, s) = (set #contractcode (EVM.RuntimeCode (EVM.ConcreteRuntimeCode "")) c, s)++newtype ContractWithStorage = ContractWithStorage (EVM.Contract, Storage)++instance FromJSON ContractWithStorage where+  parseJSON (JSON.Object v) = do+    code <- (EVM.RuntimeCode . EVM.ConcreteRuntimeCode <$> (hexText <$> v .: "code"))+    storage' <- v .: "storage"+    balance' <- v .: "balance"+    nonce'   <- v .: "nonce"+    let c = EVM.initialContract code+              & #balance .~ balance'+              & #nonce   .~ nonce'+    return $ ContractWithStorage (c, storage')++  parseJSON invalid =+    JSON.typeMismatch "Contract" invalid++instance FromJSON BlockchainCase where+  parseJSON (JSON.Object v) = BlockchainCase+    <$> v .: "blocks"+    <*> parseContracts Pre v+    <*> parseContracts Post v+    <*> v .: "network"+  parseJSON invalid =+    JSON.typeMismatch "GeneralState test case" invalid++instance FromJSON Block where+  parseJSON (JSON.Object v) = do+    v'         <- v .: "blockHeader"+    txs        <- v .: "transactions"+    coinbase   <- addrField v' "coinbase"+    difficulty <- wordField v' "difficulty"+    gasLimit   <- word64Field v' "gasLimit"+    number     <- wordField v' "number"+    baseFee    <- fmap read <$> v' .:? "baseFeePerGas"+    timestamp  <- wordField v' "timestamp"+    return $ Block coinbase difficulty gasLimit (fromMaybe 0 baseFee) number timestamp txs+  parseJSON invalid =+    JSON.typeMismatch "Block" invalid++parseContracts :: Which -> JSON.Object -> JSON.Parser (Map Addr (EVM.Contract, Storage))+parseContracts w v =+  (Map.map unwrap) <$> (v .: which >>= parseJSON)+  where which = case w of+          Pre  -> "pre"+          Post -> "postState"+        unwrap (ContractWithStorage x) = x++parseBCSuite :: Lazy.ByteString -> Either String (Map String Case)+parseBCSuite x = case (JSON.eitherDecode' x) :: Either String (Map String BlockchainCase) of+  Left e        -> Left e+  Right bcCases -> let allCases = fromBlockchainCase <$> bcCases+                       keepError (Left e) = errorFatal e+                       keepError _        = True+                       filteredCases = Map.filter keepError allCases+                       (erroredCases, parsedCases) = splitEithers filteredCases+    in if Map.size erroredCases > 0+    then Left ("errored case: " ++ (show erroredCases))+    else if Map.size parsedCases == 0+    then Left "No cases to check."+    else Right parsedCases+++data BlockchainError+  = TooManyBlocks+  | TooManyTxs+  | NoTxs+  | SignatureUnverified+  | InvalidTx+  | OldNetwork+  | FailedCreate+  deriving Show++errorFatal :: BlockchainError -> Bool+errorFatal TooManyBlocks = True+errorFatal TooManyTxs = True+errorFatal SignatureUnverified = True+errorFatal InvalidTx = True+errorFatal _ = False++fromBlockchainCase :: BlockchainCase -> Either BlockchainError Case+fromBlockchainCase (BlockchainCase blocks preState postState network) =+  case (blocks, network) of+    ([block], "London") -> case block.txs of+      [tx] -> fromBlockchainCase' block tx preState postState+      []        -> Left NoTxs+      _         -> Left TooManyTxs+    ([_], _) -> Left OldNetwork+    (_, _)   -> Left TooManyBlocks++fromBlockchainCase' :: Block -> Transaction+                       -> Map Addr (EVM.Contract, Storage) -> Map Addr (EVM.Contract, Storage)+                       -> Either BlockchainError Case+fromBlockchainCase' block tx preState postState =+  let isCreate = isNothing tx.toAddr in+  case (sender tx, checkTx tx block preState) of+      (Nothing, _) -> Left SignatureUnverified+      (_, Nothing) -> Left (if isCreate then FailedCreate else InvalidTx)+      (Just origin, Just checkState) -> Right $ Case+        (EVM.VMOpts+         { contract       = EVM.initialContract theCode+         , calldata       = (cd, [])+         , value          = Lit tx.value+         , address        = toAddr+         , caller         = litAddr origin+         , initialStorage = EmptyStore+         , origin         = origin+         , gas            = tx.gasLimit  - fromIntegral (txGasCost feeSchedule tx)+         , baseFee        = block.baseFee+         , priorityFee    = priorityFee tx block.baseFee+         , gaslimit       = tx.gasLimit+         , number         = block.number+         , timestamp      = Lit block.timestamp+         , coinbase       = block.coinbase+         , prevRandao     = block.difficulty+         , maxCodeSize    = 24576+         , blockGaslimit  = block.gasLimit+         , gasprice       = effectiveGasPrice+         , schedule       = feeSchedule+         , chainId        = 1+         , create         = isCreate+         , txAccessList   = txAccessMap tx+         , allowFFI       = False+         })+        checkState+        postState+          where+            toAddr = fromMaybe (EVM.createAddress origin senderNonce) tx.toAddr+            senderNonce = view (accountAt origin % #nonce) (Map.map fst preState)+            feeSchedule = EVM.FeeSchedule.berlin+            toCode = Map.lookup toAddr preState+            theCode = if isCreate+                      then EVM.InitCode tx.txdata mempty+                      else maybe (EVM.RuntimeCode (EVM.ConcreteRuntimeCode "")) (view #contractcode . fst) toCode+            effectiveGasPrice = effectiveprice tx block.baseFee+            cd = if isCreate+                 then mempty+                 else ConcreteBuf tx.txdata++effectiveprice :: Transaction -> W256 -> W256+effectiveprice tx baseFee = priorityFee tx baseFee + baseFee++priorityFee :: Transaction -> W256 -> W256+priorityFee tx baseFee = let+    (txPrioMax, txMaxFee) = case tx.txtype of+               EIP1559Transaction ->+                 let maxPrio = fromJust tx.maxPriorityFeeGas+                     maxFee = fromJust tx.maxFeePerGas+                 in (maxPrio, maxFee)+               _ ->+                 let gasPrice = fromJust tx.gasPrice+                 in (gasPrice, gasPrice)+  in min txPrioMax (txMaxFee - baseFee)++maxBaseFee :: Transaction -> W256+maxBaseFee tx =+  case tx.txtype of+     EIP1559Transaction -> fromJust tx.maxFeePerGas+     _ -> fromJust tx.gasPrice++validateTx :: Transaction -> Block -> Map Addr (EVM.Contract, Storage) -> Maybe ()+validateTx tx block cs = do+  let cs' = Map.map fst cs+  origin        <- sender tx+  originBalance <- (view #balance) <$> view (at origin) cs'+  originNonce   <- (view #nonce)   <$> view (at origin) cs'+  let gasDeposit = (effectiveprice tx block.baseFee) * (num tx.gasLimit)+  if gasDeposit + tx.value <= originBalance+    && tx.nonce == originNonce && block.baseFee <= maxBaseFee tx+  then Just ()+  else Nothing++checkTx :: Transaction -> Block -> Map Addr (EVM.Contract, Storage) -> Maybe (Map Addr (EVM.Contract, Storage))+checkTx tx block prestate = do+  origin <- sender tx+  validateTx tx block prestate+  let isCreate   = isNothing tx.toAddr+      senderNonce = view (accountAt origin % #nonce) (Map.map fst prestate)+      toAddr      = fromMaybe (EVM.createAddress origin senderNonce) tx.toAddr+      prevCode    = view (accountAt toAddr % #contractcode) (Map.map fst prestate)+      prevNonce   = view (accountAt toAddr % #nonce) (Map.map fst prestate)+  if isCreate && ((case prevCode of {EVM.RuntimeCode (EVM.ConcreteRuntimeCode b) -> not (BS.null b); _ -> True}) || (prevNonce /= 0))+  then mzero+  else+    return prestate++vmForCase :: Case -> EVM.VM+vmForCase x =+  let+    a = x.checkContracts+    cs = Map.map fst a+    st = Map.mapKeys num $ Map.map snd a+    vm = EVM.makeVm x.vmOpts+      & set (#env % #contracts) cs+      & set (#env % #storage) (ConcreteStore st)+      & set (#env % #origStorage) st+  in+    initTx vm
+ test/EVM/Test/Tracing.hs view
@@ -0,0 +1,868 @@+{-|+Module      : Tracing+Description : Tests to fuzz concrete tracing, and symbolic execution++Functions here are used to generate traces for the concrete+execution of HEVM and check that against evmtool from go-ehereum. Re-using some+of this code, we also generate a symbolic expression then evaluate it+concretely through Expr.simplify, then check that against evmtool's output.+-}++{-# Language DataKinds #-}+{-# Language DuplicateRecordFields #-}+{-# LANGUAGE DeriveGeneric #-}++module EVM.Test.Tracing where++import Data.ByteString (ByteString)+import System.Directory+import System.IO+import qualified Data.Word+import GHC.Generics+import Numeric (showHex)+import qualified Paths_hevm as Paths++import Prelude hiding (fail, LT, GT)++import qualified Data.ByteString as BS+import Data.Maybe+import Data.List qualified (length)+import Test.Tasty+import Test.Tasty.QuickCheck hiding (Failure)+import Test.QuickCheck.Instances.Text()+import Test.QuickCheck.Instances.Natural()+import Test.QuickCheck.Instances.ByteString()+import Test.QuickCheck (elements)+import Test.Tasty.HUnit+import qualified Data.Aeson as JSON+import Data.Aeson ((.:), (.:?))+import Data.ByteString.Char8 qualified as Char8++import qualified Control.Monad (when)+import qualified Control.Monad.Operational as Operational (view, ProgramViewT(..), ProgramView)+import Control.Monad.State.Strict hiding (state)+import Control.Monad.State.Strict qualified as State+import Optics.Core hiding (pre)+import Optics.State+import Optics.Zoom++import qualified Data.Vector as Vector+import qualified Data.Map.Strict as Map++import EVM+import EVM.SymExec+import EVM.Assembler+import EVM.Op hiding (getOp)+import EVM.Exec+import EVM.Types+import EVM.Traversals+import EVM.Concrete (createAddress)+import qualified EVM.FeeSchedule as FeeSchedule+import EVM.Solvers+import qualified EVM.Expr as Expr+import qualified Data.Text.IO as T+import qualified EVM.Stepper as Stepper+import qualified EVM.Fetch as Fetch+import System.Process+import qualified EVM.Transaction+import EVM.Format (formatBinary)+import EVM.Sign (deriveAddr)+import GHC.IO.Exception (ExitCode(ExitSuccess))++data VMTraceResult =+  VMTraceResult+  { out  :: ByteStringS+  , gasUsed :: Data.Word.Word64+  } deriving (Generic, Show)++instance JSON.ToJSON VMTraceResult where+  toEncoding = JSON.genericToEncoding JSON.defaultOptions++data EVMToolTrace =+  EVMToolTrace+    { pc :: Int+    , op :: Int+    , gas :: W256+    , memSize :: Integer+    , depth :: Int+    , refund :: Int+    , opName :: String+    , stack :: [W256]+    , error :: Maybe String+    } deriving (Generic, Show)++instance JSON.FromJSON EVMToolTrace where+  parseJSON = JSON.withObject "EVMToolTrace" $ \v -> EVMToolTrace+    <$> v .: "pc"+    <*> v .: "op"+    <*> v .: "gas"+    <*> v .: "memSize"+    <*> v .: "depth"+    <*> v .: "refund"+    <*> v .: "opName"+    <*> v .: "stack"+    <*> v .:? "error"++mkBlockHash:: Int -> Expr 'EWord+mkBlockHash x = (num x :: Integer) & show & Char8.pack & EVM.Types.keccak' & Lit++blockHashesDefault :: Map.Map Int W256+blockHashesDefault = Map.fromList [(x, forceLit $ mkBlockHash x) | x<- [1..256]]++data EVMToolOutput =+  EVMToolOutput+    { output :: ByteStringS+    , gasUsed :: W256+    , time :: Integer+    } deriving (Generic, Show)++instance JSON.FromJSON EVMToolOutput++data EVMToolTraceOutput =+  EVMToolTraceOutput+    { trace :: [EVMToolTrace]+    , output :: EVMToolOutput+    } deriving (Generic, Show)++instance JSON.FromJSON EVMToolTraceOutput++data EVMToolEnv = EVMToolEnv+  { coinbase    :: Addr+  , timestamp   :: Expr EWord+  , number      :: W256+  , prevRandao  :: W256+  , gasLimit    :: Data.Word.Word64+  , baseFee     :: W256+  , maxCodeSize :: W256+  , schedule    :: FeeSchedule.FeeSchedule Data.Word.Word64+  , blockHashes :: Map.Map Int W256+  } deriving (Show, Generic)++instance JSON.ToJSON EVMToolEnv where+  toJSON b = JSON.object [ ("currentCoinBase"  , (JSON.toJSON $ b.coinbase))+                         , ("currentDifficulty", (JSON.toJSON $ b.prevRandao))+                         , ("currentGasLimit"  , (JSON.toJSON ("0x" ++ showHex (toInteger $ b.gasLimit) "")))+                         , ("currentNumber"    , (JSON.toJSON $ b.number))+                         , ("currentTimestamp" , (JSON.toJSON tstamp))+                         , ("currentBaseFee"   , (JSON.toJSON $ b.baseFee))+                         , ("blockHashes"      , (JSON.toJSON $ b.blockHashes))+                         ]+              where+                tstamp :: W256+                tstamp = case (b.timestamp) of+                              Lit a -> a+                              _ -> error "Timestamp needs to be a Lit"++emptyEvmToolEnv :: EVMToolEnv+emptyEvmToolEnv = EVMToolEnv { coinbase = 0+                             , timestamp = Lit 0+                             , number     = 0+                             , prevRandao = 42069+                             , gasLimit   = 0xffffffffffffffff+                             , baseFee    = 0+                             , maxCodeSize= 0xffffffff+                             , schedule   = FeeSchedule.berlin+                             , blockHashes = mempty+                             }++data EVMToolReceipt =+  EVMToolReceipt+    { _type :: String+    , root :: String+    , status :: String+    , cumulativeGasUsed :: String+    , logsBloom :: String+    , logs :: Maybe String+    , transactionHash :: String+    , contractAddress :: String+    , gasUsed :: String+    , blockHash :: String+    , transactionIndex :: String+    } deriving (Generic, Show)++instance JSON.FromJSON EVMToolReceipt where+    parseJSON = JSON.withObject "EVMReceipt" $ \v -> EVMToolReceipt+        <$> v .: "type"+        <*> v .: "root"+        <*> v .: "status"+        <*> v .: "cumulativeGasUsed"+        <*> v .: "logsBloom"+        <*> v .: "logs"+        <*> v .: "transactionHash"+        <*> v .: "contractAddress"+        <*> v .: "gasUsed"+        <*> v .: "blockHash"+        <*> v .: "transactionIndex"++data EVMToolResult =+  EVMToolResult+  { stateRoot :: String+  , txRoot :: String+  , receiptsRoot :: String+  , logsHash :: String+  , logsBloom :: String+  , receipts :: [EVMToolReceipt]+  , currentDifficulty :: String+  , gasUsed :: String+  , rejected :: Maybe [EVMRejected]+  } deriving (Generic, Show)++instance JSON.FromJSON EVMToolResult++data EVMRejected =+  EVMRejected+    { index :: Int+    , err :: String+    } deriving (Generic, Show)++instance JSON.FromJSON EVMRejected where+  parseJSON = JSON.withObject "EVMRejected" $ \v -> EVMRejected+    <$> v .: "index"+    <*> v .: "error"++data EVMToolAlloc =+  EVMToolAlloc+  { balance :: W256+  , code :: ByteString+  , nonce :: W64+  } deriving (Generic)++instance JSON.ToJSON EVMToolAlloc where+  toJSON b = JSON.object [ ("balance" , (JSON.toJSON $ show b.balance))+                         , ("code", (JSON.toJSON $ ByteStringS b.code))+                         , ("nonce", (JSON.toJSON $ b.nonce))+                         ]++emptyEVMToolAlloc :: EVMToolAlloc+emptyEVMToolAlloc = EVMToolAlloc { balance = 0+                                 , code = mempty+                                 , nonce = 0+                                 }+-- Sets up common parts such as TX, origin contract, and environment that can+-- later be used to create & execute either an evmtool (from go-ethereum) or an+-- HEVM transaction. Some elements here are hard-coded such as the secret key,+-- which are currently not being fuzzed.+evmSetup :: OpContract -> ByteString -> Int -> (EVM.Transaction.Transaction, EVMToolEnv, EVMToolAlloc, Addr, Addr, Integer)+evmSetup contr txData gaslimitExec = (txn, evmEnv, contrAlloc, fromAddress, toAddress, sk)+  where+    contrLits = assemble $ getOpData contr+    toW8fromLitB :: Expr 'Byte -> Data.Word.Word8+    toW8fromLitB (LitByte a) = a+    toW8fromLitB _ = error "Cannot convert non-litB"++    bitcode = BS.pack . Vector.toList $ toW8fromLitB <$> contrLits+    contrAlloc = EVMToolAlloc{ balance = 0xa493d65e20984bc+                             , code = bitcode+                             , nonce = 0x48+                             }+    txn = EVM.Transaction.Transaction+      { txdata     = txData+      , gasLimit = fromIntegral gaslimitExec+      , gasPrice = Just 1+      , nonce    = 172+      , toAddr   = Just 0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192+      , r        = 0 -- will be fixed when we sign+      , s        = 0 -- will be fixed when we sign+      , v        = 0 -- will be fixed when we sign+      , value    = 0 -- setting this > 0 fails because HEVM doesn't handle value sent in toplevel transaction+      , txtype     = EVM.Transaction.EIP1559Transaction+      , accessList = []+      , maxPriorityFeeGas =  Just 1+      , maxFeePerGas = Just 1+      , chainId = 1+      }+    evmEnv = EVMToolEnv { coinbase   =  0xff+                        , timestamp   =  Lit 0x3e8+                        , number      =  0x0+                        , prevRandao  =  0x0+                        , gasLimit    =  fromIntegral gaslimitExec+                        , baseFee     =  0x0+                        , maxCodeSize =  0xfffff+                        , schedule    =  FeeSchedule.berlin+                        , blockHashes =  blockHashesDefault+                        }+    sk = 0xDC38EE117CAE37750EB1ECC5CFD3DE8E85963B481B93E732C5D0CB66EE6B0C9D+    fromAddress :: Addr+    fromAddress = fromJust $ deriveAddr sk+    toAddress :: Addr+    toAddress = 0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192++getHEVMRet :: OpContract -> ByteString -> Int -> IO (Either (EVM.Error, [VMTrace]) (Expr 'End, [VMTrace], VMTraceResult))+getHEVMRet contr txData gaslimitExec = do+  let (txn, evmEnv, contrAlloc, fromAddress, toAddress, _) = evmSetup contr txData gaslimitExec+  hevmRun <- runCodeWithTrace Nothing evmEnv contrAlloc txn (fromAddress, toAddress)+  return hevmRun++getEVMToolRet :: OpContract -> ByteString -> Int -> IO (Maybe EVMToolResult)+getEVMToolRet contr txData gaslimitExec = do+  let (txn, evmEnv, contrAlloc, fromAddress, toAddress, sk) = evmSetup contr txData gaslimitExec+      txs = [EVM.Transaction.sign sk txn]+      walletAlloc = EVMToolAlloc{ balance = 0x5ffd4878be161d74+                                , code = BS.empty+                                , nonce = 0xac+                                }+      alloc :: Map.Map Addr EVMToolAlloc+      alloc = Map.fromList ([ (fromAddress, walletAlloc), (toAddress, contrAlloc)])+  JSON.encodeFile "txs.json" txs+  JSON.encodeFile "alloc.json" alloc+  JSON.encodeFile "env.json" evmEnv+  (exitCode, evmtoolStdout, evmtoolStderr) <- readProcessWithExitCode "evm" [ "transition"+                               ,"--input.alloc" , "alloc.json"+                               , "--input.env" , "env.json"+                               , "--input.txs" , "txs.json"+                               , "--output.alloc" , "alloc-out.json"+                               , "--trace.returndata=true"+                               , "--trace" , "trace.json"+                               , "--output.result", "result.json"+                               ] ""+  Control.Monad.when (exitCode /= ExitSuccess) $ do+                   putStrLn $ "evmtool exited with code " <> show exitCode+                   putStrLn $ "evmtool stderr output:" <> show evmtoolStderr+                   putStrLn $ "evmtool stdout output:" <> show evmtoolStdout+  evmtoolResult <- JSON.decodeFileStrict "result.json" :: IO (Maybe EVMToolResult)+  return evmtoolResult++-- Compares traces of evmtool (from go-ethereum) and HEVM+compareTraces :: [VMTrace] -> [EVMToolTrace] -> IO (Bool)+compareTraces hevmTrace evmTrace = go hevmTrace evmTrace+  where+    go :: [VMTrace] -> [EVMToolTrace] -> IO (Bool)+    go [] [] = pure True+    go (a:ax) (b:bx) = do+      let aOp = a.traceOp+          bOp = b.op+          aPc = a.tracePc+          bPc = b.pc+          aStack = a.traceStack+          bStack = b.stack+          aGas = fromIntegral a.traceGas+          bGas = b.gas+      if aGas /= bGas then do+                          putStrLn "GAS doesn't match:"+                          putStrLn $ "HEVM's gas   : " <> (show aGas)+                          putStrLn $ "evmtool's gas: " <> (show bGas)+                          else+                          -- putStrLn $ "Gas match   : " <> (show aGas)+                          return ()+      if aOp /= bOp || aPc /= bPc then+                          putStrLn $ "HEVM: " <> (intToOpName aOp) <> " (pc " <> (show aPc) <> ") --- evmtool " <> (intToOpName bOp) <> " (pc " <> (show bPc) <> ")"+                          else+                          -- putStrLn $ "trace element match. " <> (intToOpName aOp) <> " pc: " <> (show aPc)+                          return ()++      Control.Monad.when (isJust b.error) $ do+                           putStrLn $ "Error by evmtool: " <> (show b.error)+                           putStrLn $ "Error by HEVM   : " <> (show a.traceError)++      Control.Monad.when (aStack /= bStack) $ do+                          putStrLn "stacks don't match:"+                          putStrLn $ "HEVM's stack   : " <> (show aStack)+                          putStrLn $ "evmtool's stack: " <> (show bStack)+      if aOp == bOp && aStack == bStack && aPc == bPc && aGas == bGas then go ax bx+      else pure False+++    go a@(_:_) [] = do+      putStrLn $ "Traces don't match. HEVM's trace is longer by:" <> (show a)+      pure False+    go [] [b] = do+      -- evmtool produces ONE more trace element of the error+      -- hevm on the other hand stops and doens't produce one more+      if isJust b.error then pure True+                           else do+                             putStrLn $ "Traces don't match. HEVM's trace is longer by:" <> (show b)+                             pure False+    go [] b@(_:_) = do+      putStrLn $ "Traces don't match. evmtool's trace is longer by:" <> (show b)+      pure False++getTraceFileName :: EVMToolResult -> String+getTraceFileName evmtoolResult = traceFileName+  where+    txName = ((evmtoolResult.receipts) !! 0).transactionHash+    traceFileName = "trace-0-" ++ txName ++ ".jsonl"++getTraceOutput :: Maybe EVMToolResult -> IO (Maybe EVMToolTraceOutput)+getTraceOutput evmtoolResult =+  case evmtoolResult of+    Nothing -> pure Nothing+    Just res -> do+      let traceFileName = getTraceFileName res+      convertPath <- Paths.getDataFileName "test/scripts/convert_trace_to_json.sh"+      (exitcode, _, _) <- readProcessWithExitCode "bash" [convertPath, getTraceFileName res] ""+      case exitcode of+        ExitSuccess -> JSON.decodeFileStrict (traceFileName ++ ".json") :: IO (Maybe EVMToolTraceOutput)+        _ -> pure Nothing++deleteTraceOutputFiles :: Maybe EVMToolResult -> IO ()+deleteTraceOutputFiles evmtoolResult =+  case evmtoolResult of+    Nothing -> return ()+    Just res -> do+      let traceFileName = getTraceFileName res+      System.Directory.removeFile traceFileName+      System.Directory.removeFile (traceFileName ++ ".json")++-- Create symbolic VM from concrete VM+symbolify :: VM -> VM+symbolify vm = vm { state = vm.state { calldata = AbstractBuf "calldata" } }++-- | Takes a runtime code and calls it with the provided calldata+--   Uses evmtool's alloc and transaction to set up the VM correctly+runCodeWithTrace :: Fetch.RpcInfo -> EVMToolEnv -> EVMToolAlloc -> EVM.Transaction.Transaction -> (Addr, Addr) -> IO (Either (EVM.Error, [VMTrace]) ((Expr 'End, [VMTrace], VMTraceResult)))+runCodeWithTrace rpcinfo evmEnv alloc txn (fromAddr, toAddress) = withSolvers Z3 0 Nothing $ \solvers -> do+  let origVM = vmForRuntimeCode code' calldata' evmEnv alloc txn (fromAddr, toAddress)+      calldata' = ConcreteBuf txn.txdata+      code' = alloc.code+      buildExpr :: SolverGroup -> VM -> IO (Expr End)+      buildExpr s vm = interpret (Fetch.oracle s Nothing) Nothing Nothing vm runExpr++  expr <- buildExpr solvers $ symbolify origVM+  (res, (vm, trace)) <- runStateT (interpretWithTrace (Fetch.oracle solvers rpcinfo) Stepper.execFully) (origVM, [])+  case res of+    Left x -> pure $ Left (x, trace)+    Right _ -> pure $ Right (expr, trace, vmres vm)++vmForRuntimeCode :: ByteString -> Expr Buf -> EVMToolEnv -> EVMToolAlloc -> EVM.Transaction.Transaction -> (Addr, Addr) -> VM+vmForRuntimeCode runtimecode calldata' evmToolEnv alloc txn (fromAddr, toAddress) =+  let contr = initialContract (RuntimeCode (ConcreteRuntimeCode runtimecode))+      contrWithBal = (contr :: Contract) { balance = alloc.balance }+  in+  (makeVm $ VMOpts+    { contract = contrWithBal+    , calldata = (calldata', [])+    , value = Lit txn.value+    , initialStorage = EmptyStore+    , address =  toAddress+    , caller = Expr.litAddr fromAddr+    , origin = fromAddr+    , coinbase = evmToolEnv.coinbase+    , number = evmToolEnv.number+    , timestamp = evmToolEnv.timestamp+    , gasprice = fromJust txn.gasPrice+    , gas = txn.gasLimit - fromIntegral (EVM.Transaction.txGasCost evmToolEnv.schedule txn)+    , gaslimit = txn.gasLimit+    , blockGaslimit = evmToolEnv.gasLimit+    , prevRandao = evmToolEnv.prevRandao+    , baseFee = evmToolEnv.baseFee+    , priorityFee = fromJust txn.maxPriorityFeeGas+    , maxCodeSize = evmToolEnv.maxCodeSize+    , schedule = evmToolEnv.schedule+    , chainId = txn.chainId+    , create = False+    , txAccessList = mempty+    , allowFFI = False+    }) & set (#env % #contracts % at ethrunAddress)+             (Just (initialContract (RuntimeCode (ConcreteRuntimeCode BS.empty))))+       & set (#state % #calldata) calldata'++runCode :: Fetch.RpcInfo -> ByteString -> Expr Buf -> IO (Maybe (Expr Buf))+runCode rpcinfo code' calldata' = withSolvers Z3 0 Nothing $ \solvers -> do+  let origVM = vmForRuntimeCode code' calldata' emptyEvmToolEnv emptyEVMToolAlloc EVM.Transaction.emptyTransaction (ethrunAddress, createAddress ethrunAddress 1)+  res <- Stepper.interpret (Fetch.oracle solvers rpcinfo) origVM Stepper.execFully+  pure $ case res of+    Left _ -> Nothing+    Right b -> Just b++vmtrace :: VM -> VMTrace+vmtrace vm =+  let+    memsize = vm.state.memorySize+  in VMTrace { tracePc = vm.state.pc+             , traceOp = num $ getOp vm+             , traceGas = vm.state.gas+             , traceMemSize = memsize+             -- increment to match geth format+             , traceDepth = 1 + length (vm.frames)+             -- reverse to match geth format+             , traceStack = reverse $ forceLit <$> vm.state.stack+             , traceError = readoutError vm.result+             }+  where+    readoutError :: Maybe VMResult -> Maybe String+    readoutError Nothing = Nothing+    readoutError (Just (VMSuccess _)) = Nothing+    readoutError (Just (VMFailure e)) = case e of+      -- NOTE: error text made to closely match go-ethereum's errors.go file+      OutOfGas {}             -> Just "out of gas"+      -- TODO "contract creation code storage out of gas" not handled+      CallDepthLimitReached   -> Just "max call depth exceeded"+      BalanceTooLow {}        -> Just "insufficient balance for transfer"+      -- TODO "contract address collision" not handled+      EVM.Revert {}           -> Just "execution reverted"+      -- TODO "max initcode size exceeded" not handled+      MaxCodeSizeExceeded {}  -> Just "max code size exceeded"+      EVM.BadJumpDestination  -> Just "invalid jump destination"+      StateChangeWhileStatic  -> Just "write protection"+      ReturnDataOutOfBounds   -> Just "return data out of bounds"+      EVM.IllegalOverflow     -> Just "gas uint64 overflow"+      UnrecognizedOpcode op   -> Just $ "invalid opcode: " <> show op+      EVM.NonceOverflow       -> Just "nonce uint64 overflow"+      EVM.StackUnderrun       -> Just "stack underflow"+      EVM.StackLimitExceeded  -> Just "stack limit reached"+      EVM.InvalidMemoryAccess -> Just "write protection"+      err                     -> Just $ "HEVM error: " <> show err++vmres :: VM -> VMTraceResult+vmres vm =+  let+    gasUsed' = vm.tx.gaslimit - vm.state.gas+    res = case vm.result of+      Just (VMSuccess (ConcreteBuf b)) -> (ByteStringS b)+      Just (VMSuccess x) -> error $ "unhandled: " <> (show x)+      Just (VMFailure (EVM.Revert (ConcreteBuf b))) -> (ByteStringS b)+      Just (VMFailure _) -> ByteStringS mempty+      _ -> ByteStringS mempty+  in VMTraceResult+     { out = res+     , gasUsed = gasUsed'+     }++type TraceState = (VM, [VMTrace])++execWithTrace :: StateT TraceState IO VMResult+execWithTrace = do+  _ <- runWithTrace+  fromJust <$> use (_1 % #result)++runWithTrace :: StateT TraceState IO VM+runWithTrace = do+  -- This is just like `exec` except for every instruction evaluated,+  -- we also increment a counter indexed by the current code location.+  vm0 <- use _1+  case vm0.result of+    Nothing -> do+      State.modify (\(a, b) -> (a, b ++ [vmtrace vm0]))+      zoom _1 (State.state (runState exec1))+      runWithTrace+    Just (VMSuccess _) -> pure vm0+    Just (VMFailure _) -> do+      -- Update error text for last trace element+      (a, b) <- State.get+      let updatedElem = (last b) {traceError = (vmtrace vm0).traceError}+          updatedTraces = take ((Data.List.length b)-1) b ++ [updatedElem]+      State.put (a, updatedTraces)+      pure vm0++interpretWithTrace+  :: Fetch.Fetcher+  -> Stepper.Stepper a+  -> StateT TraceState IO a+interpretWithTrace fetcher =+  eval . Operational.view++  where+    eval+      :: Operational.ProgramView Stepper.Action a+      -> StateT TraceState IO a++    eval (Operational.Return x) =+      pure x++    eval (action Operational.:>>= k) =+      case action of+        Stepper.Exec ->+          execWithTrace >>= interpretWithTrace fetcher . k+        Stepper.Run ->+          runWithTrace >>= interpretWithTrace fetcher . k+        Stepper.Wait q ->+          do m <- liftIO (fetcher q)+             zoom _1 (State.state (runState m)) >> interpretWithTrace fetcher (k ())+        Stepper.Ask _ ->+          error "cannot make choice in this interpreter"+        Stepper.IOAct q ->+          zoom _1 (StateT (runStateT q)) >>= interpretWithTrace fetcher . k+        Stepper.EVM m ->+          zoom _1 (State.state (runState m)) >>= interpretWithTrace fetcher . k++data OpContract = OpContract [Op]+instance Show OpContract where+  show (OpContract a) = "OpContract " ++ (show a)++getOpData :: OpContract-> [Op]+getOpData (OpContract x) = x++instance Arbitrary OpContract where+  arbitrary = fmap OpContract (sized genContract)++removeExtcalls :: OpContract -> OpContract+removeExtcalls (OpContract ops) = OpContract (filter (noStorageNoExtcalls) ops)+  where+    noStorageNoExtcalls :: Op -> Bool+    noStorageNoExtcalls o = case o of+                               -- Extrenal info functions+                               OpExtcodecopy -> False+                               OpExtcodehash -> False+                               OpExtcodesize -> False+                               OpAddress -> False+                               OpOrigin -> False+                               OpCaller -> False+                               OpCoinbase -> False+                               OpCreate -> False+                               OpCreate2 -> False+                               -- External call functions+                               OpDelegatecall -> False+                               OpStaticcall -> False+                               OpCall -> False+                               OpCallcode -> False+                               -- Not interesting+                               OpBalance -> False+                               OpSelfdestruct -> False+                               _ -> True++getJumpDests :: [Op] -> [Int]+getJumpDests ops = go ops 0 []+    where+      go :: [Op] -> Int -> [Int] -> [Int]+      go [] _ dests = dests+      go (a:ax) pos dests = case a of+                       OpJumpdest -> go ax (pos+1) (pos:dests)+                       OpPush _ -> go ax (pos+33) dests+                       -- We'll fix these up later to add a Push in between, hence they are 34 bytes+                       OpJump -> go ax (pos+34) dests+                       OpJumpi -> go ax (pos+34) dests+                       -- everything else is 1 byte+                       _ -> go ax (pos+1) dests++fixContractJumps :: OpContract -> IO OpContract+fixContractJumps (OpContract ops) = do+  let+    addedOps = ops++[OpJumpdest]+    jumpDests = getJumpDests addedOps+    -- always end on an OpJumpdest so we don't have an issue with a "later" position+    ops2 = fixup addedOps 0 []+    -- original set of operations, the set of jumpDests NOW valid, current position, return value+    fixup :: [Op] -> Int -> [Op] -> IO [Op]+    fixup [] _ ret = pure ret+    fixup (a:ax) pos ret = case a of+      OpJumpi -> do+        let filtDests = (filter (> pos) jumpDests)+        rndPos <- randItem filtDests+        fixup ax (pos+34) (ret++[(OpPush (Lit (fromInteger (fromIntegral rndPos)))), (OpJumpi)])+      OpJump -> do+        let filtDests = (filter (> pos) jumpDests)+        rndPos <- randItem filtDests+        fixup ax (pos+34) (ret++[(OpPush (Lit (fromInteger (fromIntegral rndPos)))), (OpJump)])+      myop@(OpPush _) -> fixup ax (pos+33) (ret++[myop])+      myop -> fixup ax (pos+1) (ret++[myop])+  fmap OpContract ops2++genPush :: Int -> Gen [Op]+genPush n = vectorOf n onePush+  where+    onePush :: Gen Op+    onePush  = do+      p <- chooseInt (1, 10)+      pure $ OpPush (Lit (fromIntegral p))++genContract :: Int -> Gen [Op]+genContract n = do+    y <- chooseInt (3, 6)+    pushes <- genPush y+    normalOps <- vectorOf (3*n+40) genOne+    addReturn <- chooseInt (0, 10)+    let contr = pushes ++ normalOps+    if addReturn < 10 then pure $ contr++[OpPush (Lit 0x40), OpPush (Lit 0x0), OpReturn]+                      else pure contr+  where+    genOne :: Gen Op+    genOne = frequency [+      -- math ops+      (200, frequency [+          (1, pure OpAdd)+        , (1, pure OpMul)+        , (1, pure OpSub)+        , (1, pure OpDiv)+        , (1, pure OpSdiv)+        , (1, pure OpMod)+        , (1, pure OpSmod)+        , (1, pure OpAddmod)+        , (1, pure OpMulmod)+        , (1, pure OpExp)+        , (1, pure OpSignextend)+        , (1, pure OpLt)+        , (1, pure OpGt)+        , (1, pure OpSlt)+        , (1, pure OpSgt)+        , (1, pure OpSha3)+      ])+      -- Comparison & binary ops+      , (200, frequency [+          (1, pure OpEq)+        , (1, pure OpIszero)+        , (1, pure OpAnd)+        , (1, pure OpOr)+        , (1, pure OpXor)+        , (1, pure OpNot)+        , (1, pure OpByte)+        , (1, pure OpShl)+        , (1, pure OpShr)+        , (1, pure OpSar)+      ])+      -- calldata+      , (800, pure OpCalldataload)+      , (200, pure OpCalldatacopy)+      -- Get some info+      , (100, frequency [+          (10, pure OpAddress)+        , (10, pure OpBalance)+        , (10, pure OpOrigin)+        , (10, pure OpCaller)+        , (10, pure OpCallvalue)+        , (10, pure OpCalldatasize)+        , (10, pure OpCodesize)+        , (10, pure OpGasprice)+        , (10, pure OpReturndatasize)+        , (10, pure OpReturndatacopy)+        , (10, pure OpExtcodehash)+        , (10, pure OpBlockhash)+        , (10, pure OpCoinbase)+        , (10, pure OpTimestamp)+        , (10, pure OpNumber)+        , (10, pure OpPrevRandao)+        , (10, pure OpGaslimit)+        , (10, pure OpChainid)+        , (10, pure OpSelfbalance)+        , (10, pure OpBaseFee)+        , (10, pure OpPc)+        , (10, pure OpMsize)+        , (10, pure OpGas)+        , (10, pure OpExtcodesize)+        , (10, pure OpCodecopy)+        , (10, pure OpExtcodecopy)+      ])+      -- memory manip+      , (1200, frequency [+          (50, pure OpMload)+        , (50, pure OpMstore)+        , (1, pure OpMstore8)+      ])+      -- storage manip+      , (100, frequency [+          (1, pure OpSload)+        , (1, pure OpSstore)+      ])+      -- Jumping around+      , (20, frequency [+            (1, pure OpJump)+          , (10, pure OpJumpi)+      ])+      -- calling out+      , (1, frequency [+          (1, pure OpStaticcall)+        , (1, pure OpCall)+        , (1, pure OpCallcode)+        , (1, pure OpDelegatecall)+        , (1, pure OpCreate)+        , (1, pure OpCreate2)+        , (1, pure OpSelfdestruct)+      ])+      -- manipulate stack+      , (13000, frequency [+          (1, pure OpPop)+        , (400, do+            -- x <- arbitrary+            large <- chooseInt (0, 100)+            x <- if large == 0 then chooseBoundedIntegral (0::W256, (2::W256)^(256::W256)-1)+                               else chooseBoundedIntegral (0, 10)+            pure $ OpPush (Lit (fromIntegral x)))+        , (10, do+            x <- chooseInt (1, 10)+            pure $ OpDup (fromIntegral x))+        , (10, do+            x <- chooseInt (1, 10)+            pure $ OpSwap (fromIntegral x))+      ])]+      -- End states+      -- , (1, frequency [+      --    (1, pure OpStop)+      --  , (10, pure OpReturn)+      --  , (10, pure OpRevert)+      -- ])++forceLit :: Expr EWord -> W256+forceLit (Lit x) = x+forceLit _ = undefined++randItem :: [a] -> IO a+randItem = generate . Test.QuickCheck.elements++getOp :: VM -> Data.Word.Word8+getOp vm =+  let pcpos  = vm ^. #state % #pc+      code' = vm ^. #state % #code+      xs = case code' of+        InitCode _ _ -> error "InitCode instead of RuntimeCode"+        RuntimeCode (ConcreteRuntimeCode xs') -> BS.drop pcpos xs'+        RuntimeCode (SymbolicRuntimeCode _) -> error "RuntimeCode is symbolic"+  in if xs == BS.empty then 0+                       else BS.head xs++tests :: TestTree+tests = testGroup "contract-quickcheck-run"+    [ testProperty "random-contract-concrete-call" $ \(contr :: OpContract) -> ioProperty $ do+        txDataRaw <- generate $ sized $ \n -> vectorOf (10*n+5) $ chooseInt (0,255)+        gaslimitExec <- generate $ chooseInt (40000, 0xffff)+        let txData = BS.pack $ toEnum <$> txDataRaw+        -- TODO: By removing external calls, we fuzz less+        --       It should work also when we external calls. Removing for now.+        contrFixed <- fixContractJumps $ removeExtcalls contr+        evmtoolResult <- getEVMToolRet contrFixed txData gaslimitExec+        hevmRun <- getHEVMRet contrFixed txData gaslimitExec+        (Just evmtoolTraceOutput) <- getTraceOutput evmtoolResult+        case hevmRun of+          (Right (expr, hevmTrace, hevmTraceResult)) -> do+            let+              concretize :: Expr a -> Expr Buf -> Expr a+              concretize a c = 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+              getReturnVal :: Expr End -> Maybe ByteString+              getReturnVal (Return _ (ConcreteBuf bs) _) = Just bs+              getReturnVal _ = Nothing+              simplConcrExprRetval = getReturnVal simplConcExpr+            traceOK <- compareTraces hevmTrace (evmtoolTraceOutput.trace)+            -- putStrLn $ "HEVM trace   : " <> show hevmTrace+            -- putStrLn $ "evmtool trace: " <> show (evmtoolTraceOutput.toTrace)+            assertEqual "Traces and gas must match" traceOK True+            let resultOK = evmtoolTraceOutput.output.output == hevmTraceResult.out+            if resultOK then do+              putStrLn $ "HEVM & evmtool's outputs match: '" <> (bsToHex $ bssToBs evmtoolTraceOutput.output.output) <> "'"+              if isNothing simplConcrExprRetval || (fromJust simplConcrExprRetval) == (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 ""+                 else do+                   putStrLn $ "concretized expr           : " <> (show concretizedExpr)+                   putStrLn $ "simplified concretized expr: " <> (show simplConcExpr)+                   putStrLn $ "return value computed      : " <> (show simplConcrExprRetval)+                   putStrLn $ "evmtool's return value     : " <> (show hevmTraceResult.out)+                   assertEqual "Simplified, concretized expression must match evmtool's output." True False+            else do+              putStrLn $ "Name of trace file: " <> (getTraceFileName $ fromJust evmtoolResult)+              putStrLn $ "HEVM result  :" <> (show hevmTraceResult)+              T.putStrLn $ "HEVM result: " <> (formatBinary $ bssToBs hevmTraceResult.out)+              T.putStrLn $ "evm result : " <> (formatBinary $ bssToBs evmtoolTraceOutput.output.output)+              putStrLn $ "HEVM result len: " <> (show (BS.length $ bssToBs hevmTraceResult.out))+              putStrLn $ "evm result  len: " <> (show (BS.length $ bssToBs evmtoolTraceOutput.output.output))+            assertEqual "Contract exec successful. HEVM & evmtool's outputs must match" resultOK True+          Left (evmerr, hevmTrace) -> do+            putStrLn $ "HEVM contract exec issue: " <> (show evmerr)+            -- putStrLn $ "evmtool result was: " <> show (fromJust evmtoolResult)+            -- putStrLn $ "output by evmtool is: '" <> bsToHex evmtoolTraceOutput.toOutput.output <> "'"+            traceOK <- compareTraces hevmTrace (evmtoolTraceOutput.trace)+            assertEqual "Traces and gas must match" traceOK True+        System.Directory.removeFile "txs.json"+        System.Directory.removeFile "alloc-out.json"+        System.Directory.removeFile "alloc.json"+        System.Directory.removeFile "result.json"+        System.Directory.removeFile "env.json"+        deleteTraceOutputFiles evmtoolResult+    ]+
+ test/EVM/Test/Utils.hs view
@@ -0,0 +1,136 @@+{-# Language QuasiQuotes #-}++module EVM.Test.Utils where++import Data.Text+import qualified Data.Text as T+import qualified Data.Text.IO as T+import qualified Paths_hevm as Paths+import Data.String.Here+import System.Directory+import System.IO.Temp+import GHC.IO.Handle (hClose)+import System.Process (readProcess)++import EVM.Solidity+import EVM.Solvers+import EVM.Dapp+import EVM.UnitTest+import EVM.Fetch (RpcInfo)+import qualified EVM.TTY as TTY++runDappTestCustom :: FilePath -> Text -> Maybe Integer -> Bool -> RpcInfo -> IO Bool+runDappTestCustom testFile match maxIter ffiAllowed rpcinfo = do+  root <- Paths.getDataDir+  (json, _) <- compileWithDSTest testFile+  --T.writeFile "output.json" json+  withCurrentDirectory root $ do+    withSystemTempFile "output.json" $ \file handle -> do+      hClose handle+      T.writeFile file json+      withSolvers Z3 1 Nothing $ \solvers -> do+        opts <- testOpts solvers root json match maxIter ffiAllowed rpcinfo+        dappTest opts file Nothing++runDappTest :: FilePath -> Text -> IO Bool+runDappTest testFile match = runDappTestCustom testFile match Nothing True Nothing++debugDappTest :: FilePath -> RpcInfo -> IO ()+debugDappTest testFile rpcinfo = do+  root <- Paths.getDataDir+  (json, _) <- compileWithDSTest testFile+  --TIO.writeFile "output.json" json+  withCurrentDirectory root $ do+    withSystemTempFile "output.json" $ \file handle -> do+      hClose handle+      T.writeFile file json+      withSolvers Z3 1 Nothing $ \solvers -> do+        opts <- testOpts solvers root json ".*" Nothing True rpcinfo+        TTY.main opts root file++testOpts :: SolverGroup -> FilePath -> Text -> Text -> Maybe Integer -> Bool -> RpcInfo -> IO UnitTestOptions+testOpts solvers root solcJson match maxIter allowFFI rpcinfo = do+  srcInfo <- case readJSON solcJson of+               Nothing -> error "Could not read solc json"+               Just (contractMap, asts, sources) -> do+                 sourceCache <- makeSourceCache sources asts+                 pure $ dappInfo root contractMap sourceCache++  params <- getParametersFromEnvironmentVariables Nothing++  pure UnitTestOptions+    { solvers = solvers+    , rpcInfo = rpcinfo+    , maxIter = maxIter+    , askSmtIters = Nothing+    , smtDebug = False+    , smtTimeout = Nothing+    , solver = Nothing+    , covMatch = Nothing+    , verbose = Just 1+    , match = match+    , maxDepth = Nothing+    , fuzzRuns = 100+    , replay = Nothing+    , vmModifier = id+    , testParams = params+    , dapp = srcInfo+    , ffiAllowed = allowFFI+    }++compileWithDSTest :: FilePath -> IO (Text, Text)+compileWithDSTest src =+  withSystemTempFile "input.json" $ \file handle -> do+    hClose handle+    dsTest <- readFile =<< Paths.getDataFileName "test/contracts/lib/test.sol"+    erc20 <- readFile =<< Paths.getDataFileName "test/contracts/lib/erc20.sol"+    testFilePath <- Paths.getDataFileName src+    testFile <- readFile testFilePath+    T.writeFile file+      [i|+      {+        "language": "Solidity",+        "sources": {+          "ds-test/test.sol": {+            "content": ${dsTest}+          },+          "lib/erc20.sol": {+            "content": ${erc20}+          },+          "test.sol": {+            "content": ${testFile}+          }+        },+        "settings": {+          "metadata": {+            "useLiteralContent": true+          },+          "outputSelection": {+            "*": {+              "*": [+                "metadata",+                "evm.bytecode",+                "evm.deployedBytecode",+                "abi",+                "storageLayout",+                "evm.bytecode.sourceMap",+                "evm.bytecode.linkReferences",+                "evm.bytecode.generatedSources",+                "evm.deployedBytecode.sourceMap",+                "evm.deployedBytecode.linkReferences",+                "evm.deployedBytecode.generatedSources"+              ],+              "": [+                "ast"+              ]+            }+          }+        }+      }+      |]+    x <- T.pack <$>+      readProcess+        "solc"+        ["--allow-paths", file, "--standard-json", file]+        ""+    return (x, T.pack testFilePath)
− test/EVM/TestUtils.hs
@@ -1,136 +0,0 @@-{-# Language QuasiQuotes #-}--module EVM.TestUtils where--import Data.Text-import qualified Data.Text as T-import qualified Data.Text.IO as T-import qualified Paths_hevm as Paths-import Data.String.Here-import System.Directory-import System.IO.Temp-import GHC.IO.Handle (hClose)-import System.Process (readProcess)--import EVM.Solidity-import EVM.Solvers-import EVM.Dapp-import EVM.UnitTest-import EVM.Fetch (RpcInfo)-import qualified EVM.TTY as TTY--runDappTestCustom :: FilePath -> Text -> Maybe Integer -> Bool -> RpcInfo -> IO Bool-runDappTestCustom testFile match maxIter ffiAllowed rpcinfo = do-  root <- Paths.getDataDir-  (json, _) <- compileWithDSTest testFile-  --T.writeFile "output.json" json-  withCurrentDirectory root $ do-    withSystemTempFile "output.json" $ \file handle -> do-      hClose handle-      T.writeFile file json-      withSolvers Z3 1 Nothing $ \solvers -> do-        opts <- testOpts solvers root json match maxIter ffiAllowed rpcinfo-        dappTest opts file Nothing--runDappTest :: FilePath -> Text -> IO Bool-runDappTest testFile match = runDappTestCustom testFile match Nothing True Nothing--debugDappTest :: FilePath -> RpcInfo -> IO ()-debugDappTest testFile rpcinfo = do-  root <- Paths.getDataDir-  (json, _) <- compileWithDSTest testFile-  --TIO.writeFile "output.json" json-  withCurrentDirectory root $ do-    withSystemTempFile "output.json" $ \file handle -> do-      hClose handle-      T.writeFile file json-      withSolvers Z3 1 Nothing $ \solvers -> do-        opts <- testOpts solvers root json ".*" Nothing True rpcinfo-        TTY.main opts root file--testOpts :: SolverGroup -> FilePath -> Text -> Text -> Maybe Integer -> Bool -> RpcInfo -> IO UnitTestOptions-testOpts solvers root solcJson match maxIter allowFFI rpcinfo = do-  srcInfo <- case readJSON solcJson of-               Nothing -> error "Could not read solc json"-               Just (contractMap, asts, sources) -> do-                 sourceCache <- makeSourceCache sources asts-                 pure $ dappInfo root contractMap sourceCache--  params <- getParametersFromEnvironmentVariables Nothing--  pure UnitTestOptions-    { solvers = solvers-    , rpcInfo = rpcinfo-    , maxIter = maxIter-    , askSmtIters = Nothing-    , smtDebug = False-    , smtTimeout = Nothing-    , solver = Nothing-    , covMatch = Nothing-    , verbose = Just 1-    , match = match-    , maxDepth = Nothing-    , fuzzRuns = 100-    , replay = Nothing-    , vmModifier = id-    , testParams = params-    , dapp = srcInfo-    , ffiAllowed = allowFFI-    }--compileWithDSTest :: FilePath -> IO (Text, Text)-compileWithDSTest src =-  withSystemTempFile "input.json" $ \file handle -> do-    hClose handle-    dsTest <- readFile =<< Paths.getDataFileName "test/contracts/lib/test.sol"-    erc20 <- readFile =<< Paths.getDataFileName "test/contracts/lib/erc20.sol"-    testFilePath <- Paths.getDataFileName src-    testFile <- readFile testFilePath-    T.writeFile file-      [i|-      {-        "language": "Solidity",-        "sources": {-          "ds-test/test.sol": {-            "content": ${dsTest}-          },-          "lib/erc20.sol": {-            "content": ${erc20}-          },-          "test.sol": {-            "content": ${testFile}-          }-        },-        "settings": {-          "metadata": {-            "useLiteralContent": true-          },-          "outputSelection": {-            "*": {-              "*": [-                "metadata",-                "evm.bytecode",-                "evm.deployedBytecode",-                "abi",-                "storageLayout",-                "evm.bytecode.sourceMap",-                "evm.bytecode.linkReferences",-                "evm.bytecode.generatedSources",-                "evm.deployedBytecode.sourceMap",-                "evm.deployedBytecode.linkReferences",-                "evm.deployedBytecode.generatedSources"-              ],-              "": [-                "ast"-              ]-            }-          }-        }-      }-      |]-    x <- T.pack <$>-      readProcess-        "solc"-        ["--allow-paths", file, "--standard-json", file]-        ""-    return (x, T.pack testFilePath)
− test/EVM/Tracing.hs
@@ -1,870 +0,0 @@-{-|-Module      : Tracing-Description : Tests to fuzz concrete tracing, and symbolic execution--Functions here are used to generate traces for the concrete-execution of HEVM and check that against evmtool from go-ehereum. Re-using some-of this code, we also generate a symbolic expression then evaluate it-concretely through Expr.simplify, then check that against evmtool's output.--}--{-# Language DataKinds #-}-{-# Language DuplicateRecordFields #-}-{-# LANGUAGE DeriveGeneric #-}--module EVM.Tracing where--import Data.ByteString (ByteString)-import System.Directory-import System.IO-import qualified Data.Word-import GHC.Generics-import Numeric (showHex)-import qualified Paths_hevm as Paths--import Prelude hiding (fail, LT, GT)--import qualified Data.ByteString as BS-import Data.Maybe-import Data.List qualified (length)-import Test.Tasty-import Test.Tasty.QuickCheck hiding (Failure)-import Test.QuickCheck.Instances.Text()-import Test.QuickCheck.Instances.Natural()-import Test.QuickCheck.Instances.ByteString()-import Test.QuickCheck (elements)-import Test.Tasty.HUnit-import qualified Data.Aeson as JSON-import Data.Aeson ((.:), (.:?))-import Data.ByteString.Char8 qualified as Char8--import qualified Control.Monad (when)-import qualified Control.Monad.Operational as Operational (view, ProgramViewT(..), ProgramView)-import Control.Monad.State.Strict hiding (state)-import Control.Monad.State.Strict qualified as State-import Control.Lens hiding (List, pre, (.>), re, op)--import qualified Data.Vector as Vector-import qualified Data.Map.Strict as Map--import EVM hiding (allowFFI)-import EVM.SymExec-import EVM.Assembler-import EVM.Op hiding (getOp)-import EVM.Exec-import EVM.Types-import EVM.Traversals-import EVM.Concrete (createAddress)-import qualified EVM.FeeSchedule as FeeSchedule-import EVM.Solvers-import qualified EVM.Expr as Expr-import qualified Data.Text.IO as T-import qualified EVM.Stepper as Stepper-import qualified EVM.Fetch as Fetch-import System.Process-import qualified EVM.Transaction-import EVM.Format (formatBinary)-import EVM.Sign (deriveAddr)-import GHC.IO.Exception (ExitCode(ExitSuccess))--data VMTraceResult =-  VMTraceResult-  { out  :: ByteStringS-  , gasUsed :: Data.Word.Word64-  } deriving (Generic, Show)--instance JSON.ToJSON VMTraceResult where-  toEncoding = JSON.genericToEncoding JSON.defaultOptions--data EVMToolTrace =-  EVMToolTrace-    { pc :: Int-    , op :: Int-    , gas :: W256-    , memSize :: Integer-    , depth :: Int-    , refund :: Int-    , opName :: String-    , stack :: [W256]-    , error :: Maybe String-    } deriving (Generic, Show)--instance JSON.FromJSON EVMToolTrace where-  parseJSON = JSON.withObject "EVMToolTrace" $ \v -> EVMToolTrace-    <$> v .: "pc"-    <*> v .: "op"-    <*> v .: "gas"-    <*> v .: "memSize"-    <*> v .: "depth"-    <*> v .: "refund"-    <*> v .: "opName"-    <*> v .: "stack"-    <*> v .:? "error"--mkBlockHash:: Int -> Expr 'EWord-mkBlockHash x = (num x :: Integer) & show & Char8.pack & EVM.Types.keccak' & Lit--blockHashesDefault :: Map.Map Int W256-blockHashesDefault = Map.fromList [(x, forceLit $ mkBlockHash x) | x<- [1..256]]--data EVMToolOutput =-  EVMToolOutput-    { output :: ByteStringS-    , gasUsed :: W256-    , time :: Integer-    } deriving (Generic, Show)--instance JSON.FromJSON EVMToolOutput--data EVMToolTraceOutput =-  EVMToolTraceOutput-    { trace :: [EVMToolTrace]-    , output :: EVMToolOutput-    } deriving (Generic, Show)--instance JSON.FromJSON EVMToolTraceOutput--data EVMToolEnv = EVMToolEnv-  { coinbase    :: Addr-  , timestamp   :: Expr EWord-  , number      :: W256-  , prevRandao  :: W256-  , gasLimit    :: Data.Word.Word64-  , baseFee     :: W256-  , maxCodeSize :: W256-  , schedule    :: FeeSchedule.FeeSchedule Data.Word.Word64-  , blockHashes :: Map.Map Int W256-  } deriving (Show, Generic)--instance JSON.ToJSON EVMToolEnv where-  toJSON b = JSON.object [ ("currentCoinBase"  , (JSON.toJSON $ b.coinbase))-                         , ("currentDifficulty", (JSON.toJSON $ b.prevRandao))-                         , ("currentGasLimit"  , (JSON.toJSON ("0x" ++ showHex (toInteger $ b.gasLimit) "")))-                         , ("currentNumber"    , (JSON.toJSON $ b.number))-                         , ("currentTimestamp" , (JSON.toJSON tstamp))-                         , ("currentBaseFee"   , (JSON.toJSON $ b.baseFee))-                         , ("blockHashes"      , (JSON.toJSON $ b.blockHashes))-                         ]-              where-                tstamp :: W256-                tstamp = case (b.timestamp) of-                              Lit a -> a-                              _ -> error "Timestamp needs to be a Lit"--emptyEvmToolEnv :: EVMToolEnv-emptyEvmToolEnv = EVMToolEnv { coinbase = 0-                             , timestamp = Lit 0-                             , number     = 0-                             , prevRandao = 42069-                             , gasLimit   = 0xffffffffffffffff-                             , baseFee    = 0-                             , maxCodeSize= 0xffffffff-                             , schedule   = FeeSchedule.berlin-                             , blockHashes = mempty-                             }--data EVMToolReceipt =-  EVMToolReceipt-    { _type :: String-    , root :: String-    , status :: String-    , cumulativeGasUsed :: String-    , logsBloom :: String-    , logs :: Maybe String-    , transactionHash :: String-    , contractAddress :: String-    , gasUsed :: String-    , blockHash :: String-    , transactionIndex :: String-    } deriving (Generic, Show)--instance JSON.FromJSON EVMToolReceipt where-    parseJSON = JSON.withObject "EVMReceipt" $ \v -> EVMToolReceipt-        <$> v .: "type"-        <*> v .: "root"-        <*> v .: "status"-        <*> v .: "cumulativeGasUsed"-        <*> v .: "logsBloom"-        <*> v .: "logs"-        <*> v .: "transactionHash"-        <*> v .: "contractAddress"-        <*> v .: "gasUsed"-        <*> v .: "blockHash"-        <*> v .: "transactionIndex"--data EVMToolResult =-  EVMToolResult-  { stateRoot :: String-  , txRoot :: String-  , receiptsRoot :: String-  , logsHash :: String-  , logsBloom :: String-  , receipts :: [EVMToolReceipt]-  , currentDifficulty :: String-  , gasUsed :: String-  , rejected :: Maybe [EVMRejected]-  } deriving (Generic, Show)--instance JSON.FromJSON EVMToolResult--data EVMRejected =-  EVMRejected-    { index :: Int-    , err :: String-    } deriving (Generic, Show)--instance JSON.FromJSON EVMRejected where-  parseJSON = JSON.withObject "EVMRejected" $ \v -> EVMRejected-    <$> v .: "index"-    <*> v .: "error"--data EVMToolAlloc =-  EVMToolAlloc-  { balance :: W256-  , code :: ByteString-  , nonce :: W64-  } deriving (Generic)--instance JSON.ToJSON EVMToolAlloc where-  toJSON b = JSON.object [ ("balance" , (JSON.toJSON $ show b.balance))-                         , ("code", (JSON.toJSON $ ByteStringS b.code))-                         , ("nonce", (JSON.toJSON $ b.nonce))-                         ]--emptyEVMToolAlloc :: EVMToolAlloc-emptyEVMToolAlloc = EVMToolAlloc { balance = 0-                                 , code = mempty-                                 , nonce = 0-                                 }--- Sets up common parts such as TX, origin contract, and environment that can--- later be used to create & execute either an evmtool (from go-ethereum) or an--- HEVM transaction. Some elements here are hard-coded such as the secret key,--- which are currently not being fuzzed.-evmSetup :: OpContract -> ByteString -> Int -> (EVM.Transaction.Transaction, EVMToolEnv, EVMToolAlloc, Addr, Addr, Integer)-evmSetup contr txData gaslimitExec = (txn, evmEnv, contrAlloc, fromAddress, toAddress, sk)-  where-    contrLits = assemble $ getOpData contr-    toW8fromLitB :: Expr 'Byte -> Data.Word.Word8-    toW8fromLitB (LitByte a) = a-    toW8fromLitB _ = error "Cannot convert non-litB"--    bitcode = BS.pack . Vector.toList $ toW8fromLitB <$> contrLits-    contrAlloc = EVMToolAlloc{ balance = 0xa493d65e20984bc-                             , code = bitcode-                             , nonce = 0x48-                             }-    txn = EVM.Transaction.Transaction-      { txData     = txData-      , txGasLimit = fromIntegral gaslimitExec-      , txGasPrice = Just 1-      , txNonce    = 172-      , txToAddr   = Just 0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192-      , txR        = 0 -- will be fixed when we sign-      , txS        = 0 -- will be fixed when we sign-      , txV        = 0 -- will be fixed when we sign-      , txValue    = 0 -- setting this > 0 fails because HEVM doesn't handle value sent in toplevel transaction-      , txType     = EVM.Transaction.EIP1559Transaction-      , txAccessList = []-      , txMaxPriorityFeeGas =  Just 1-      , txMaxFeePerGas = Just 1-      , txChainId = 1-      }-    evmEnv = EVMToolEnv { coinbase   =  0xff-                        , timestamp   =  Lit 0x3e8-                        , number      =  0x0-                        , prevRandao  =  0x0-                        , gasLimit    =  fromIntegral gaslimitExec-                        , baseFee     =  0x0-                        , maxCodeSize =  0xfffff-                        , schedule    =  FeeSchedule.berlin-                        , blockHashes =  blockHashesDefault-                        }-    sk = 0xDC38EE117CAE37750EB1ECC5CFD3DE8E85963B481B93E732C5D0CB66EE6B0C9D-    fromAddress :: Addr-    fromAddress = fromJust $ deriveAddr sk-    toAddress :: Addr-    toAddress = 0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192--getHEVMRet :: OpContract -> ByteString -> Int -> IO (Either (EVM.Error, [VMTrace]) (Expr 'End, [VMTrace], VMTraceResult))-getHEVMRet contr txData gaslimitExec = do-  let (txn, evmEnv, contrAlloc, fromAddress, toAddress, _) = evmSetup contr txData gaslimitExec-  hevmRun <- runCodeWithTrace Nothing evmEnv contrAlloc txn (fromAddress, toAddress)-  return hevmRun--getEVMToolRet :: OpContract -> ByteString -> Int -> IO (Maybe EVMToolResult)-getEVMToolRet contr txData gaslimitExec = do-  let (txn, evmEnv, contrAlloc, fromAddress, toAddress, sk) = evmSetup contr txData gaslimitExec-      txs = [EVM.Transaction.sign sk txn]-      walletAlloc = EVMToolAlloc{ balance = 0x5ffd4878be161d74-                                , code = BS.empty-                                , nonce = 0xac-                                }-      alloc :: Map.Map Addr EVMToolAlloc-      alloc = Map.fromList ([ (fromAddress, walletAlloc), (toAddress, contrAlloc)])-  JSON.encodeFile "txs.json" txs-  JSON.encodeFile "alloc.json" alloc-  JSON.encodeFile "env.json" evmEnv-  (exitCode, evmtoolStdout, evmtoolStderr) <- readProcessWithExitCode "evm" [ "transition"-                               ,"--input.alloc" , "alloc.json"-                               , "--input.env" , "env.json"-                               , "--input.txs" , "txs.json"-                               , "--output.alloc" , "alloc-out.json"-                               , "--trace.returndata=true"-                               , "--trace" , "trace.json"-                               , "--output.result", "result.json"-                               ] ""-  Control.Monad.when (exitCode /= ExitSuccess) $ do-                   putStrLn $ "evmtool exited with code " <> show exitCode-                   putStrLn $ "evmtool stderr output:" <> show evmtoolStderr-                   putStrLn $ "evmtool stdout output:" <> show evmtoolStdout-  evmtoolResult <- JSON.decodeFileStrict "result.json" :: IO (Maybe EVMToolResult)-  return evmtoolResult---- Compares traces of evmtool (from go-ethereum) and HEVM-compareTraces :: [VMTrace] -> [EVMToolTrace] -> IO (Bool)-compareTraces hevmTrace evmTrace = go hevmTrace evmTrace-  where-    go :: [VMTrace] -> [EVMToolTrace] -> IO (Bool)-    go [] [] = pure True-    go (a:ax) (b:bx) = do-      let aOp = a.traceOp-          bOp = b.op-          aPc = a.tracePc-          bPc = b.pc-          aStack = a.traceStack-          bStack = b.stack-          aGas = fromIntegral a.traceGas-          bGas = b.gas-      if aGas /= bGas then do-                          putStrLn "GAS doesn't match:"-                          putStrLn $ "HEVM's gas   : " <> (show aGas)-                          putStrLn $ "evmtool's gas: " <> (show bGas)-                          else-                          -- putStrLn $ "Gas match   : " <> (show aGas)-                          return ()-      if aOp /= bOp || aPc /= bPc then-                          putStrLn $ "HEVM: " <> (intToOpName aOp) <> " (pc " <> (show aPc) <> ") --- evmtool " <> (intToOpName bOp) <> " (pc " <> (show bPc) <> ")"-                          else-                          -- putStrLn $ "trace element match. " <> (intToOpName aOp) <> " pc: " <> (show aPc)-                          return ()--      Control.Monad.when (isJust b.error) $ do-                           putStrLn $ "Error by evmtool: " <> (show b.error)-                           putStrLn $ "Error by HEVM   : " <> (show a.traceError)--      Control.Monad.when (aStack /= bStack) $ do-                          putStrLn "stacks don't match:"-                          putStrLn $ "HEVM's stack   : " <> (show aStack)-                          putStrLn $ "evmtool's stack: " <> (show bStack)-      if aOp == bOp && aStack == bStack && aPc == bPc && aGas == bGas then go ax bx-      else pure False---    go a@(_:_) [] = do-      putStrLn $ "Traces don't match. HEVM's trace is longer by:" <> (show a)-      pure False-    go [] [b] = do-      -- evmtool produces ONE more trace element of the error-      -- hevm on the other hand stops and doens't produce one more-      if isJust b.error then pure True-                           else do-                             putStrLn $ "Traces don't match. HEVM's trace is longer by:" <> (show b)-                             pure False-    go [] b@(_:_) = do-      putStrLn $ "Traces don't match. evmtool's trace is longer by:" <> (show b)-      pure False--getTraceFileName :: EVMToolResult -> String-getTraceFileName evmtoolResult = traceFileName-  where-    txName = ((evmtoolResult.receipts) !! 0).transactionHash-    traceFileName = "trace-0-" ++ txName ++ ".jsonl"--getTraceOutput :: Maybe EVMToolResult -> IO (Maybe EVMToolTraceOutput)-getTraceOutput evmtoolResult =-  case evmtoolResult of-    Nothing -> pure Nothing-    Just res -> do-      let traceFileName = getTraceFileName res-      convertPath <- Paths.getDataFileName "test/scripts/convert_trace_to_json.sh"-      (exitcode, _, _) <- readProcessWithExitCode "bash" [convertPath, getTraceFileName res] ""-      case exitcode of-        ExitSuccess -> JSON.decodeFileStrict (traceFileName ++ ".json") :: IO (Maybe EVMToolTraceOutput)-        _ -> pure Nothing--deleteTraceOutputFiles :: Maybe EVMToolResult -> IO ()-deleteTraceOutputFiles evmtoolResult =-  case evmtoolResult of-    Nothing -> return ()-    Just res -> do-      let traceFileName = getTraceFileName res-      System.Directory.removeFile traceFileName-      System.Directory.removeFile (traceFileName ++ ".json")---- Create symbolic VM from concrete VM-symbolify :: VM -> VM-symbolify vm = vm { _state = vm._state { _calldata = AbstractBuf "calldata" } }---- | Takes a runtime code and calls it with the provided calldata---   Uses evmtool's alloc and transaction to set up the VM correctly-runCodeWithTrace :: Fetch.RpcInfo -> EVMToolEnv -> EVMToolAlloc -> EVM.Transaction.Transaction -> (Addr, Addr) -> IO (Either (EVM.Error, [VMTrace]) ((Expr 'End, [VMTrace], VMTraceResult)))-runCodeWithTrace rpcinfo evmEnv alloc txn (fromAddr, toAddress) = withSolvers Z3 0 Nothing $ \solvers -> do-  let origVM = vmForRuntimeCode code' calldata' evmEnv alloc txn (fromAddr, toAddress)-      calldata' = ConcreteBuf txn.txData-      code' = alloc.code-      buildExpr :: SolverGroup -> VM -> IO (Expr End)-      buildExpr s vm = evalStateT (interpret (Fetch.oracle s Nothing) Nothing Nothing runExpr) vm--  expr <- buildExpr solvers $ symbolify origVM-  (res, (vm, trace)) <- runStateT (interpretWithTrace (Fetch.oracle solvers rpcinfo) Stepper.execFully) (origVM, [])-  case res of-    Left x -> pure $ Left (x, trace)-    Right _ -> pure $ Right (expr, trace, vmres vm)--vmForRuntimeCode :: ByteString -> Expr Buf -> EVMToolEnv -> EVMToolAlloc -> EVM.Transaction.Transaction -> (Addr, Addr) -> VM-vmForRuntimeCode runtimecode calldata' evmToolEnv alloc txn (fromAddr, toAddress) =-  let contr = initialContract (RuntimeCode (ConcreteRuntimeCode runtimecode))-      contrWithBal = contr { _balance = alloc.balance }-  in-  (makeVm $ VMOpts-    { vmoptContract = contrWithBal-    , vmoptCalldata = (calldata', [])-    , vmoptValue = Lit txn.txValue-    , vmoptStorageBase = Concrete-    , vmoptAddress =  toAddress-    , vmoptCaller = Expr.litAddr fromAddr-    , vmoptOrigin = fromAddr-    , vmoptCoinbase = evmToolEnv.coinbase-    , vmoptNumber = evmToolEnv.number-    , vmoptTimestamp = evmToolEnv.timestamp-    , vmoptGasprice = fromJust txn.txGasPrice-    , vmoptGas = txn.txGasLimit - fromIntegral (EVM.Transaction.txGasCost evmToolEnv.schedule txn)-    , vmoptGaslimit = txn.txGasLimit-    , vmoptBlockGaslimit = evmToolEnv.gasLimit-    , vmoptPrevRandao = evmToolEnv.prevRandao-    , vmoptBaseFee = evmToolEnv.baseFee-    , vmoptPriorityFee = fromJust txn.txMaxPriorityFeeGas-    , vmoptMaxCodeSize = evmToolEnv.maxCodeSize-    , vmoptSchedule = evmToolEnv.schedule-    , vmoptChainId = txn.txChainId-    , vmoptCreate = False-    , vmoptTxAccessList = mempty-    , vmoptAllowFFI = False-    }) & set (EVM.env . contracts . at ethrunAddress)-             (Just (initialContract (RuntimeCode (ConcreteRuntimeCode BS.empty))))-       & set (state . calldata) calldata'--runCode :: Fetch.RpcInfo -> ByteString -> Expr Buf -> IO (Maybe (Expr Buf))-runCode rpcinfo code' calldata' = withSolvers Z3 0 Nothing $ \solvers -> do-  let origVM = vmForRuntimeCode code' calldata' emptyEvmToolEnv emptyEVMToolAlloc EVM.Transaction.emptyTransaction (ethrunAddress, createAddress ethrunAddress 1)-  res <- evalStateT (Stepper.interpret (Fetch.oracle solvers rpcinfo) Stepper.execFully) origVM-  pure $ case res of-    Left _ -> Nothing-    Right b -> Just b--vmtrace :: VM -> VMTrace-vmtrace vm =-  let-    -- Convenience function to access parts of the current VM state.-    -- Arcane type signature needed to avoid monomorphism restriction.-    the :: (b -> VM -> Const a VM) -> ((a -> Const a a) -> b) -> a-    the f g = Control.Lens.view (f . g) vm-    memsize = the state memorySize-  in VMTrace { tracePc = the state EVM.pc-             , traceOp = num $ getOp vm-             , traceGas = the state EVM.gas-             , traceMemSize = memsize-             -- increment to match geth format-             , traceDepth = 1 + length (Control.Lens.view frames vm)-             -- reverse to match geth format-             , traceStack = reverse $ forceLit <$> the state EVM.stack-             , traceError = readoutError vm._result-             }-  where-    readoutError :: Maybe VMResult -> Maybe String-    readoutError Nothing = Nothing-    readoutError (Just (VMSuccess _)) = Nothing-    readoutError (Just (VMFailure e)) = case e of-      -- NOTE: error text made to closely match go-ethereum's errors.go file-      OutOfGas {}             -> Just "out of gas"-      -- TODO "contract creation code storage out of gas" not handled-      CallDepthLimitReached   -> Just "max call depth exceeded"-      BalanceTooLow {}        -> Just "insufficient balance for transfer"-      -- TODO "contract address collision" not handled-      EVM.Revert {}           -> Just "execution reverted"-      -- TODO "max initcode size exceeded" not handled-      MaxCodeSizeExceeded {}  -> Just "max code size exceeded"-      EVM.BadJumpDestination  -> Just "invalid jump destination"-      StateChangeWhileStatic  -> Just "write protection"-      ReturnDataOutOfBounds   -> Just "return data out of bounds"-      EVM.IllegalOverflow     -> Just "gas uint64 overflow"-      UnrecognizedOpcode op   -> Just $ "invalid opcode: " <> show op-      EVM.NonceOverflow       -> Just "nonce uint64 overflow"-      EVM.StackUnderrun       -> Just "stack underflow"-      EVM.StackLimitExceeded  -> Just "stack limit reached"-      EVM.InvalidMemoryAccess -> Just "write protection"-      err                     -> Just $ "HEVM error: " <> show err--vmres :: VM -> VMTraceResult-vmres vm =-  let-    gasUsed' = Control.Lens.view (tx . txgaslimit) vm - Control.Lens.view (state . EVM.gas) vm-    res = case Control.Lens.view result vm of-      Just (VMSuccess (ConcreteBuf b)) -> (ByteStringS b)-      Just (VMSuccess x) -> error $ "unhandled: " <> (show x)-      Just (VMFailure (EVM.Revert (ConcreteBuf b))) -> (ByteStringS b)-      Just (VMFailure _) -> ByteStringS mempty-      _ -> ByteStringS mempty-  in VMTraceResult-     { out = res-     , gasUsed = gasUsed'-     }--type TraceState = (VM, [VMTrace])--execWithTrace :: StateT TraceState IO VMResult-execWithTrace = do-  _ <- runWithTrace-  fromJust <$> use (_1 . result)--runWithTrace :: StateT TraceState IO VM-runWithTrace = do-  -- This is just like `exec` except for every instruction evaluated,-  -- we also increment a counter indexed by the current code location.-  vm0 <- use _1-  case vm0._result of-    Nothing -> do-      State.modify (\(a, b) -> (a, b ++ [vmtrace vm0]))-      zoom _1 (State.state (runState exec1))-      runWithTrace-    Just (VMSuccess _) -> pure vm0-    Just (VMFailure _) -> do-      -- Update error text for last trace element-      (a, b) <- State.get-      let updatedElem = (last b) {traceError = (vmtrace vm0).traceError}-          updatedTraces = take ((Data.List.length b)-1) b ++ [updatedElem]-      State.put (a, updatedTraces)-      pure vm0--interpretWithTrace-  :: Fetch.Fetcher-  -> Stepper.Stepper a-  -> StateT TraceState IO a-interpretWithTrace fetcher =-  eval . Operational.view--  where-    eval-      :: Operational.ProgramView Stepper.Action a-      -> StateT TraceState IO a--    eval (Operational.Return x) =-      pure x--    eval (action Operational.:>>= k) =-      case action of-        Stepper.Exec ->-          execWithTrace >>= interpretWithTrace fetcher . k-        Stepper.Run ->-          runWithTrace >>= interpretWithTrace fetcher . k-        Stepper.Wait q ->-          do m <- liftIO (fetcher q)-             zoom _1 (State.state (runState m)) >> interpretWithTrace fetcher (k ())-        Stepper.Ask _ ->-          error "cannot make choice in this interpreter"-        Stepper.IOAct q ->-          zoom _1 (StateT (runStateT q)) >>= interpretWithTrace fetcher . k-        Stepper.EVM m ->-          zoom _1 (State.state (runState m)) >>= interpretWithTrace fetcher . k--data OpContract = OpContract [Op]-instance Show OpContract where-  show (OpContract a) = "OpContract " ++ (show a)--getOpData :: OpContract-> [Op]-getOpData (OpContract x) = x--instance Arbitrary OpContract where-  arbitrary = fmap OpContract (sized genContract)--removeExtcalls :: OpContract -> OpContract-removeExtcalls (OpContract ops) = OpContract (filter (noStorageNoExtcalls) ops)-  where-    noStorageNoExtcalls :: Op -> Bool-    noStorageNoExtcalls o = case o of-                               -- Extrenal info functions-                               OpExtcodecopy -> False-                               OpExtcodehash -> False-                               OpExtcodesize -> False-                               OpAddress -> False-                               OpOrigin -> False-                               OpCaller -> False-                               OpCoinbase -> False-                               OpCreate -> False-                               OpCreate2 -> False-                               -- External call functions-                               OpDelegatecall -> False-                               OpStaticcall -> False-                               OpCall -> False-                               OpCallcode -> False-                               -- Not interesting-                               OpBalance -> False-                               OpSelfdestruct -> False-                               _ -> True--getJumpDests :: [Op] -> [Int]-getJumpDests ops = go ops 0 []-    where-      go :: [Op] -> Int -> [Int] -> [Int]-      go [] _ dests = dests-      go (a:ax) pos dests = case a of-                       OpJumpdest -> go ax (pos+1) (pos:dests)-                       OpPush _ -> go ax (pos+33) dests-                       -- We'll fix these up later to add a Push in between, hence they are 34 bytes-                       OpJump -> go ax (pos+34) dests-                       OpJumpi -> go ax (pos+34) dests-                       -- everything else is 1 byte-                       _ -> go ax (pos+1) dests--fixContractJumps :: OpContract -> IO OpContract-fixContractJumps (OpContract ops) = do-  let-    addedOps = ops++[OpJumpdest]-    jumpDests = getJumpDests addedOps-    -- always end on an OpJumpdest so we don't have an issue with a "later" position-    ops2 = fixup addedOps 0 []-    -- original set of operations, the set of jumpDests NOW valid, current position, return value-    fixup :: [Op] -> Int -> [Op] -> IO [Op]-    fixup [] _ ret = pure ret-    fixup (a:ax) pos ret = case a of-      OpJumpi -> do-        let filtDests = (filter (> pos) jumpDests)-        rndPos <- randItem filtDests-        fixup ax (pos+34) (ret++[(OpPush (Lit (fromInteger (fromIntegral rndPos)))), (OpJumpi)])-      OpJump -> do-        let filtDests = (filter (> pos) jumpDests)-        rndPos <- randItem filtDests-        fixup ax (pos+34) (ret++[(OpPush (Lit (fromInteger (fromIntegral rndPos)))), (OpJump)])-      myop@(OpPush _) -> fixup ax (pos+33) (ret++[myop])-      myop -> fixup ax (pos+1) (ret++[myop])-  fmap OpContract ops2--genPush :: Int -> Gen [Op]-genPush n = vectorOf n onePush-  where-    onePush :: Gen Op-    onePush  = do-      p <- chooseInt (1, 10)-      pure $ OpPush (Lit (fromIntegral p))--genContract :: Int -> Gen [Op]-genContract n = do-    y <- chooseInt (3, 6)-    pushes <- genPush y-    normalOps <- vectorOf (3*n+40) genOne-    addReturn <- chooseInt (0, 10)-    let contr = pushes ++ normalOps-    if addReturn < 10 then pure $ contr++[OpPush (Lit 0x40), OpPush (Lit 0x0), OpReturn]-                      else pure contr-  where-    genOne :: Gen Op-    genOne = frequency [-      -- math ops-      (200, frequency [-          (1, pure OpAdd)-        , (1, pure OpMul)-        , (1, pure OpSub)-        , (1, pure OpDiv)-        , (1, pure OpSdiv)-        , (1, pure OpMod)-        , (1, pure OpSmod)-        , (1, pure OpAddmod)-        , (1, pure OpMulmod)-        , (1, pure OpExp)-        , (1, pure OpSignextend)-        , (1, pure OpLt)-        , (1, pure OpGt)-        , (1, pure OpSlt)-        , (1, pure OpSgt)-        , (1, pure OpSha3)-      ])-      -- Comparison & binary ops-      , (200, frequency [-          (1, pure OpEq)-        , (1, pure OpIszero)-        , (1, pure OpAnd)-        , (1, pure OpOr)-        , (1, pure OpXor)-        , (1, pure OpNot)-        , (1, pure OpByte)-        , (1, pure OpShl)-        , (1, pure OpShr)-        , (1, pure OpSar)-      ])-      -- calldata-      , (800, pure OpCalldataload)-      , (200, pure OpCalldatacopy)-      -- Get some info-      , (100, frequency [-          (10, pure OpAddress)-        , (10, pure OpBalance)-        , (10, pure OpOrigin)-        , (10, pure OpCaller)-        , (10, pure OpCallvalue)-        , (10, pure OpCalldatasize)-        , (10, pure OpCodesize)-        , (10, pure OpGasprice)-        , (10, pure OpReturndatasize)-        , (10, pure OpReturndatacopy)-        , (10, pure OpExtcodehash)-        , (10, pure OpBlockhash)-        , (10, pure OpCoinbase)-        , (10, pure OpTimestamp)-        , (10, pure OpNumber)-        , (10, pure OpPrevRandao)-        , (10, pure OpGaslimit)-        , (10, pure OpChainid)-        , (10, pure OpSelfbalance)-        , (10, pure OpBaseFee)-        , (10, pure OpPc)-        , (10, pure OpMsize)-        , (10, pure OpGas)-        , (10, pure OpExtcodesize)-        , (10, pure OpCodecopy)-        , (10, pure OpExtcodecopy)-      ])-      -- memory manip-      , (1200, frequency [-          (50, pure OpMload)-        , (50, pure OpMstore)-        , (1, pure OpMstore8)-      ])-      -- storage manip-      , (100, frequency [-          (1, pure OpSload)-        , (1, pure OpSstore)-      ])-      -- Jumping around-      , (20, frequency [-            (1, pure OpJump)-          , (10, pure OpJumpi)-      ])-      -- calling out-      , (1, frequency [-          (1, pure OpStaticcall)-        , (1, pure OpCall)-        , (1, pure OpCallcode)-        , (1, pure OpDelegatecall)-        , (1, pure OpCreate)-        , (1, pure OpCreate2)-        , (1, pure OpSelfdestruct)-      ])-      -- manipulate stack-      , (13000, frequency [-          (1, pure OpPop)-        , (400, do-            -- x <- arbitrary-            large <- chooseInt (0, 100)-            x <- if large == 0 then chooseBoundedIntegral (0::W256, (2::W256)^(256::W256)-1)-                               else chooseBoundedIntegral (0, 10)-            pure $ OpPush (Lit (fromIntegral x)))-        , (10, do-            x <- chooseInt (1, 10)-            pure $ OpDup (fromIntegral x))-        , (10, do-            x <- chooseInt (1, 10)-            pure $ OpSwap (fromIntegral x))-      ])]-      -- End states-      -- , (1, frequency [-      --    (1, pure OpStop)-      --  , (10, pure OpReturn)-      --  , (10, pure OpRevert)-      -- ])--forceLit :: Expr EWord -> W256-forceLit (Lit x) = x-forceLit _ = undefined--randItem :: [a] -> IO a-randItem = generate . Test.QuickCheck.elements--getOp :: VM -> Data.Word.Word8-getOp vm =-  let pcpos  = vm ^. state . EVM.pc-      code' = vm ^. state . EVM.code-      xs = case code' of-        InitCode _ _ -> error "InitCode instead of RuntimeCode"-        RuntimeCode (ConcreteRuntimeCode xs') -> BS.drop pcpos xs'-        RuntimeCode (SymbolicRuntimeCode _) -> error "RuntimeCode is symbolic"-  in if xs == BS.empty then 0-                       else BS.head xs--tests :: TestTree-tests = testGroup "contract-quickcheck-run"-    [ testProperty "random-contract-concrete-call" $ \(contr :: OpContract) -> ioProperty $ do-        txDataRaw <- generate $ sized $ \n -> vectorOf (10*n+5) $ chooseInt (0,255)-        gaslimitExec <- generate $ chooseInt (40000, 0xffff)-        let txData = BS.pack $ toEnum <$> txDataRaw-        -- TODO: By removing external calls, we fuzz less-        --       It should work also when we external calls. Removing for now.-        contrFixed <- fixContractJumps $ removeExtcalls contr-        evmtoolResult <- getEVMToolRet contrFixed txData gaslimitExec-        hevmRun <- getHEVMRet contrFixed txData gaslimitExec-        (Just evmtoolTraceOutput) <- getTraceOutput evmtoolResult-        case hevmRun of-          (Right (expr, hevmTrace, hevmTraceResult)) -> do-            let-              concretize :: Expr a -> Expr Buf -> Expr a-              concretize a c = 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-              getReturnVal :: Expr End -> Maybe ByteString-              getReturnVal (Return _ (ConcreteBuf bs) _) = Just bs-              getReturnVal _ = Nothing-              simplConcrExprRetval = getReturnVal simplConcExpr-            traceOK <- compareTraces hevmTrace (evmtoolTraceOutput.trace)-            -- putStrLn $ "HEVM trace   : " <> show hevmTrace-            -- putStrLn $ "evmtool trace: " <> show (evmtoolTraceOutput.toTrace)-            assertEqual "Traces and gas must match" traceOK True-            let resultOK = evmtoolTraceOutput.output.output == hevmTraceResult.out-            if resultOK then do-              putStrLn $ "HEVM & evmtool's outputs match: '" <> (bsToHex $ bssToBs evmtoolTraceOutput.output.output) <> "'"-              if isNothing simplConcrExprRetval || (fromJust simplConcrExprRetval) == (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 ""-                 else do-                   putStrLn $ "concretized expr           : " <> (show concretizedExpr)-                   putStrLn $ "simplified concretized expr: " <> (show simplConcExpr)-                   putStrLn $ "return value computed      : " <> (show simplConcrExprRetval)-                   putStrLn $ "evmtool's return value     : " <> (show hevmTraceResult.out)-                   assertEqual "Simplified, concretized expression must match evmtool's output." True False-            else do-              putStrLn $ "Name of trace file: " <> (getTraceFileName $ fromJust evmtoolResult)-              putStrLn $ "HEVM result  :" <> (show hevmTraceResult)-              T.putStrLn $ "HEVM result: " <> (formatBinary $ bssToBs hevmTraceResult.out)-              T.putStrLn $ "evm result : " <> (formatBinary $ bssToBs evmtoolTraceOutput.output.output)-              putStrLn $ "HEVM result len: " <> (show (BS.length $ bssToBs hevmTraceResult.out))-              putStrLn $ "evm result  len: " <> (show (BS.length $ bssToBs evmtoolTraceOutput.output.output))-            assertEqual "Contract exec successful. HEVM & evmtool's outputs must match" resultOK True-          Left (evmerr, hevmTrace) -> do-            putStrLn $ "HEVM contract exec issue: " <> (show evmerr)-            -- putStrLn $ "evmtool result was: " <> show (fromJust evmtoolResult)-            -- putStrLn $ "output by evmtool is: '" <> bsToHex evmtoolTraceOutput.toOutput.output <> "'"-            traceOK <- compareTraces hevmTrace (evmtoolTraceOutput.trace)-            assertEqual "Traces and gas must match" traceOK True-        System.Directory.removeFile "txs.json"-        System.Directory.removeFile "alloc-out.json"-        System.Directory.removeFile "alloc.json"-        System.Directory.removeFile "result.json"-        System.Directory.removeFile "env.json"-        deleteTraceOutputFiles evmtoolResult-    ]-
test/contracts/pass/cheatCodes.sol view
@@ -23,6 +23,10 @@     } } +contract Payable {+    function hi() public payable {}+}+ contract CheatCodes is DSTest {     address store = address(new HasStorage());     Hevm hevm = Hevm(HEVM_ADDRESS);@@ -100,5 +104,22 @@         hevm.prank(address(0xdeadbeef));         assertEq(prankster.prankme(), address(0xdeadbeef));         assertEq(prankster.prankme(), address(this));+    }++    function test_prank_val() public {+        address from = address(0x1312);+        uint amt = 10;++        Payable target = new Payable();+        from.call{value: amt}("");++        uint preBal = from.balance;++        hevm.prank(from);+        target.hi{value : amt}();++        uint postBal = from.balance;++        assertEq(preBal - postBal, amt);     } }
test/rpc.hs view
@@ -1,27 +1,23 @@-{-# Language GADTs #-} {-# Language DataKinds #-}  module Main where -import Control.Lens import Test.Tasty import Test.Tasty.HUnit-import Data.Text (Text)-import Control.Monad.State.Strict (execStateT)-import Data.Functor+ import Data.Maybe-import qualified Data.Map as Map-import qualified Data.Vector as V+import Data.Map qualified as Map+import Data.Text (Text)+import Data.Vector qualified as V  import EVM import EVM.ABI+import EVM.Fetch import EVM.SMT import EVM.Solvers-import EVM.Fetch+import EVM.Stepper qualified as Stepper import EVM.SymExec-import EVM.TestUtils-import qualified EVM.Stepper as Stepper-import qualified EVM.Fetch as Fetch+import EVM.Test.Utils import EVM.Types hiding (BlockNumber)  main :: IO ()@@ -31,31 +27,31 @@ tests = testGroup "rpc"   [ testGroup "Block Parsing Tests"     [ testCase "pre-merge-block" $ do-        let block' = BlockNumber 15537392-        (cb, numb, basefee, prevRan) <- fetchBlockFrom block' testRpc >>= \case+        let block = BlockNumber 15537392+        (cb, numb, basefee, prevRan) <- fetchBlockFrom block testRpc >>= \case                       Nothing -> error "Could not fetch block"-                      Just EVM.Block{..} -> return (_coinbase-                                                   , _number-                                                   , _baseFee-                                                   , _prevRandao+                      Just EVM.Block{..} -> return ( coinbase+                                                   , number+                                                   , baseFee+                                                   , prevRandao                                                    )          assertEqual "coinbase" (Addr 0xea674fdde714fd979de3edf0f56aa9716b898ec8) cb-        assertEqual "number" (BlockNumber numb) block'+        assertEqual "number" (BlockNumber numb) block         assertEqual "basefee" 38572377838 basefee         assertEqual "prevRan" 11049842297455506 prevRan     , testCase "post-merge-block" $ do-        let block' = BlockNumber 16184420-        (cb, numb, basefee, prevRan) <- fetchBlockFrom block' testRpc >>= \case+        let block = BlockNumber 16184420+        (cb, numb, basefee, prevRan) <- fetchBlockFrom block testRpc >>= \case                       Nothing -> error "Could not fetch block"-                      Just EVM.Block{..} -> return (_coinbase-                                                   , _number-                                                   , _baseFee-                                                   , _prevRandao+                      Just EVM.Block{..} -> return ( coinbase+                                                   , number+                                                   , baseFee+                                                   , prevRandao                                                    )          assertEqual "coinbase" (Addr 0x690b9a9e9aa1c9db991c7721a92d351db4fac990) cb-        assertEqual "number" (BlockNumber numb) block'+        assertEqual "number" (BlockNumber numb) block         assertEqual "basefee" 22163046690 basefee         assertEqual "prevRan" 0x2267531ab030ed32fd5f2ef51f81427332d0becbd74fe7f4cd5684ddf4b287e0 prevRan     ]@@ -74,14 +70,14 @@           calldata' = ConcreteBuf $ abiMethod "transfer(address,uint256)" (AbiTuple (V.fromList [AbiAddress (Addr 0xdead), AbiUInt 256 wad]))         vm <- weth9VM blockNum (calldata', [])         postVm <- withSolvers Z3 1 Nothing $ \solvers ->-          execStateT (Stepper.interpret (Fetch.oracle solvers (Just (BlockNumber blockNum, testRpc))) . void $ Stepper.execFully) vm+          Stepper.interpret (oracle solvers (Just (BlockNumber blockNum, testRpc))) vm Stepper.runFully         let-          postStore = case view (env . storage) postVm of+          postStore = case postVm.env.storage of             ConcreteStore s -> s             _ -> error "ConcreteStore expected"           wethStore = fromJust $ Map.lookup 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 postStore           receiverBal = fromJust $ Map.lookup (keccak' (word256Bytes 0xdead <> word256Bytes 0x3)) wethStore-          msg = case view result postVm of+          msg = case postVm.result of             Just (VMSuccess m) -> m             _ -> error "VMSuccess expected"         assertEqual "should succeed" msg (ConcreteBuf $ word256Bytes 0x1)@@ -122,29 +118,29 @@     Just b -> pure b    pure $ EVM.makeVm $ EVM.VMOpts-    { EVM.vmoptContract      = ctrct-    , EVM.vmoptCalldata      = calldata'-    , EVM.vmoptValue         = callvalue'-    , EVM.vmoptAddress       = address'-    , EVM.vmoptCaller        = caller'-    , EVM.vmoptOrigin        = 0xacab-    , EVM.vmoptGas           = 0xffffffffffffffff-    , EVM.vmoptGaslimit      = 0xffffffffffffffff-    , EVM.vmoptBaseFee       = view baseFee blk-    , EVM.vmoptPriorityFee   = 0-    , EVM.vmoptCoinbase      = view coinbase blk-    , EVM.vmoptNumber        = view number blk-    , EVM.vmoptTimestamp     = view timestamp blk-    , EVM.vmoptBlockGaslimit = view gaslimit blk-    , EVM.vmoptGasprice      = 0-    , EVM.vmoptMaxCodeSize   = view maxCodeSize blk-    , EVM.vmoptPrevRandao    = view prevRandao blk-    , EVM.vmoptSchedule      = view schedule blk-    , EVM.vmoptChainId       = 1-    , EVM.vmoptCreate        = False-    , EVM.vmoptStorageBase   = EVM.Concrete-    , EVM.vmoptTxAccessList  = mempty-    , EVM.vmoptAllowFFI      = False+    { EVM.contract       = ctrct+    , EVM.calldata       = calldata'+    , EVM.value          = callvalue'+    , EVM.address        = address'+    , EVM.caller         = caller'+    , EVM.origin         = 0xacab+    , EVM.gas            = 0xffffffffffffffff+    , EVM.gaslimit       = 0xffffffffffffffff+    , EVM.baseFee        = blk.baseFee+    , EVM.priorityFee    = 0+    , EVM.coinbase       = blk.coinbase+    , EVM.number         = blk.number+    , EVM.timestamp      = blk.timestamp+    , EVM.blockGaslimit  = blk.gaslimit+    , EVM.gasprice       = 0+    , EVM.maxCodeSize    = blk.maxCodeSize+    , EVM.prevRandao     = blk.prevRandao+    , EVM.schedule       = blk.schedule+    , EVM.chainId        = 1+    , EVM.create         = False+    , EVM.initialStorage = EmptyStore+    , EVM.txAccessList   = mempty+    , EVM.allowFFI       = False     }  testRpc :: Text
test/test.hs view
@@ -32,10 +32,12 @@ import Test.Tasty.HUnit import Test.Tasty.Runners hiding (Failure) import Test.Tasty.ExpectedFailure-import EVM.Tracing qualified+import EVM.Test.Tracing qualified as Tracing  import Control.Monad.State.Strict hiding (state)-import Control.Lens hiding (List, pre, (.>), re, op)+import Optics.Core hiding (pre, re)+import Optics.State+import Optics.Operators.Unsafe  import qualified Data.Vector as Vector import Data.String.Here@@ -44,7 +46,7 @@ import Data.Binary.Put (runPut) import Data.Binary.Get (runGetOrFail) -import EVM hiding (allowFFI)+import EVM import EVM.SymExec import EVM.ABI import EVM.Exec@@ -60,7 +62,7 @@ import qualified EVM.Expr as Expr import qualified Data.Text as T import Data.List (isSubsequenceOf)-import EVM.TestUtils+import EVM.Test.Utils import GHC.Conc (getNumProcessors)  main :: IO ()@@ -73,8 +75,7 @@  tests :: TestTree tests = testGroup "hevm"-  [-  EVM.Tracing.tests+  [ Tracing.tests   , testGroup "StorageTests"     [ testCase "read-from-sstore" $ assertEqual ""         (Lit 0xab)@@ -97,17 +98,17 @@     , testCase "accessStorage uses fetchedStorage" $ do         let dummyContract =               (initialContract (RuntimeCode (ConcreteRuntimeCode mempty)))-                { _external = True }+                { external = True }             vm = vmForEthrunCreation ""             -- perform the initial access             vm1 = execState (EVM.accessStorage 0 (Lit 0) (pure . pure ())) vm             -- it should fetch the contract first-            vm2 = case vm1._result of+            vm2 = case vm1.result of                     Just (VMFailure (Query (PleaseFetchContract _addr continue))) ->                       execState (continue dummyContract) vm1                     _ -> error "unexpected result"             -- then it should fetch the slow-            vm3 = case vm2._result of+            vm3 = case vm2.result of                     Just (VMFailure (Query (PleaseFetchSlot _addr _slot continue))) ->                       execState (continue 1337) vm2                     _ -> error "unexpected result"@@ -115,8 +116,19 @@             vm4 = execState (EVM.accessStorage 0 (Lit 0) (pure . pure ())) vm3          -- there won't be query now as accessStorage uses fetch cache-        assertBool (show vm4._result) (isNothing vm4._result)+        assertBool (show vm4.result) (isNothing vm4.result)     ]+  , testGroup "SimplifierUnitTests"+    -- common overflow cases that the simplifier was getting wrong+    [ testCase "writeWord-overflow" $ do+        let e = ReadByte (Lit 0x0) (WriteWord (Lit 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd) (Lit 0x0) (ConcreteBuf "\255\255\255\255"))+        b <- checkEquiv e (Expr.simplify e)+        assertBool "Simplifier failed" b+    , testCase "CopySlice-overflow" $ do+        let e = ReadWord (Lit 0x0) (CopySlice (Lit 0x0) (Lit 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc) (Lit 0x6) (ConcreteBuf "\255\255\255\255\255\255") (ConcreteBuf ""))+        b <- checkEquiv e (Expr.simplify e)+        assertBool "Simplifier failed" b+    ]   -- These tests fuzz the simplifier by generating a random expression,   -- applying some simplification rules, and then using the smt encoding to   -- check that the simplified version is semantically equivalent to the@@ -1131,7 +1143,7 @@                                        _ -> error "expected 2 args"                         in (x .<= Expr.add x y)                         -- TODO check if it's needed-                           .&& view (state . callvalue) preVM .== Lit 0+                           .&& preVM.state.callvalue .== Lit 0             post prestate leaf =               let (x, y) = case getStaticAbiArgs 2 prestate of                              [x', y'] -> (x', y')@@ -1139,7 +1151,7 @@               in case leaf of                    EVM.Types.Return _ b _ -> (ReadWord (Lit 0) b) .== (Add x y)                    _ -> PBool True-        (res, [Qed _]) <- withSolvers Z3 1 Nothing $ \s -> verifyContract s safeAdd (Just (Sig "add(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts SymbolicS (Just pre) (Just post)+        (res, [Qed _]) <- withSolvers Z3 1 Nothing $ \s -> verifyContract s safeAdd (Just (Sig "add(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts AbstractStore (Just pre) (Just post)         putStrLn $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"      , @@ -1157,7 +1169,7 @@                                        _ -> error "expected 2 args"                         in (x .<= Expr.add x y)                            .&& (x .== y)-                           .&& Control.Lens.view (state . callvalue) preVM .== Lit 0+                           .&& preVM.state.callvalue .== Lit 0             post prestate leaf =               let (_, y) = case getStaticAbiArgs 2 prestate of                              [x', y'] -> (x', y')@@ -1166,7 +1178,7 @@                    EVM.Types.Return _ b _ -> (ReadWord (Lit 0) b) .== (Mul (Lit 2) y)                    _ -> PBool True         (res, [Qed _]) <- withSolvers Z3 1 Nothing $ \s ->-          verifyContract s safeAdd (Just (Sig "add(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts SymbolicS (Just pre) (Just post)+          verifyContract s safeAdd (Just (Sig "add(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts AbstractStore (Just pre) (Just post)         putStrLn $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"       ,       testCase "summary storage writes" $ do@@ -1182,17 +1194,17 @@             }           }           |]-        let pre vm = Lit 0 .== Control.Lens.view (state . callvalue) vm+        let pre vm = Lit 0 .== vm.state.callvalue             post prestate leaf =               let y = case getStaticAbiArgs 1 prestate of                         [y'] -> y'                         _ -> error "expected 1 arg"-                  this = Expr.litAddr $ Control.Lens.view (state . codeContract) prestate-                  prex = Expr.readStorage' this (Lit 0) (Control.Lens.view (EVM.env . EVM.storage) prestate)+                  this = Expr.litAddr $ prestate.state.codeContract+                  prex = Expr.readStorage' this (Lit 0) prestate.env.storage               in case leaf of                 EVM.Types.Return _ _ postStore -> Expr.add prex (Expr.mul (Lit 2) y) .== (Expr.readStorage' this (Lit 0) postStore)                 _ -> PBool True-        (res, [Qed _]) <- withSolvers Z3 1 Nothing $ \s -> verifyContract s c (Just (Sig "f(uint256)" [AbiUIntType 256])) [] defaultVeriOpts SymbolicS (Just pre) (Just post)+        (res, [Qed _]) <- withSolvers Z3 1 Nothing $ \s -> verifyContract s c (Just (Sig "f(uint256)" [AbiUIntType 256])) [] defaultVeriOpts AbstractStore (Just pre) (Just post)         putStrLn $ "successfully explored: " <> show (Expr.numBranches res) <> " paths"         ,         -- tests how whiffValue handles Neg via application of the triple IsZero simplification rule@@ -1236,13 +1248,13 @@               }             }             |]-          let pre vm = (Lit 0) .== Control.Lens.view (state . callvalue) vm+          let pre vm = (Lit 0) .== vm.state.callvalue               post prestate poststate =                 let (x,y) = case getStaticAbiArgs 2 prestate of                         [x',y'] -> (x',y')                         _ -> error "expected 2 args"-                    this = Expr.litAddr $ Control.Lens.view (state . codeContract) prestate-                    prestore =  Control.Lens.view (EVM.env . EVM.storage) prestate+                    this = Expr.litAddr $ prestate.state.codeContract+                    prestore = prestate.env.storage                     prex = Expr.readStorage' this x prestore                     prey = Expr.readStorage' this y prestore                 in case poststate of@@ -1251,7 +1263,7 @@                            posty = Expr.readStorage' this y poststore                        in Expr.add prex prey .== Expr.add postx posty                      _ -> PBool True-          (_, [Qed _]) <- withSolvers Z3 1 Nothing $ \s -> verifyContract s c (Just (Sig "f(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts SymbolicS (Just pre) (Just post)+          (_, [Qed _]) <- withSolvers Z3 1 Nothing $ \s -> verifyContract s c (Just (Sig "f(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts AbstractStore (Just pre) (Just post)           putStrLn "Correct, this can never fail"         ,         -- Inspired by these `msg.sender == to` token bugs@@ -1270,13 +1282,13 @@               }             }             |]-          let pre vm = (Lit 0) .== Control.Lens.view (state . callvalue) vm+          let pre vm = (Lit 0) .== vm.state.callvalue               post prestate poststate =                 let (x,y) = case getStaticAbiArgs 2 prestate of                         [x',y'] -> (x',y')                         _ -> error "expected 2 args"-                    this = Expr.litAddr $ Control.Lens.view (state . codeContract) prestate-                    prestore =  Control.Lens.view (EVM.env . EVM.storage) prestate+                    this = Expr.litAddr $ prestate.state.codeContract+                    prestore =  prestate.env.storage                     prex = Expr.readStorage' this x prestore                     prey = Expr.readStorage' this y prestore                 in case poststate of@@ -1285,7 +1297,7 @@                            posty = Expr.readStorage' this y poststore                        in Expr.add prex prey .== Expr.add postx posty                      _ -> PBool True-          (_, [Cex (_, ctr)]) <- withSolvers Z3 1 Nothing $ \s -> verifyContract s c (Just (Sig "f(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts SymbolicS (Just pre) (Just post)+          (_, [Cex (_, ctr)]) <- withSolvers Z3 1 Nothing $ \s -> verifyContract s c (Just (Sig "f(uint256,uint256)" [AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts AbstractStore (Just pre) (Just post)           let x = getVar ctr "arg1"           let y = getVar ctr "arg2"           putStrLn $ "y:" <> show y@@ -1293,7 +1305,7 @@           assertEqual "Catch storage collisions" x y           putStrLn "expected counterexample found"         ,-        testCase "Simple Assert" $ do+        testCase "simple-assert" $ do           Just c <- solcRuntime "C"             [i|             contract C {@@ -1302,8 +1314,8 @@               }              }             |]-          (_, [Cex (l, _)]) <- withSolvers Z3 1 Nothing $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "foo()" [])) [] defaultVeriOpts-          assertEqual "incorrect revert msg" l (EVM.Types.Revert [] (ConcreteBuf $ panicMsg 0x01))+          (_, [Cex (EVM.Types.Revert _ msg, _)]) <- withSolvers Z3 1 Nothing $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "foo()" [])) [] defaultVeriOpts+          assertEqual "incorrect revert msg" msg (ConcreteBuf $ panicMsg 0x01)         ,         testCase "simple-assert-2" $ do           Just c <- solcRuntime "C"@@ -1750,10 +1762,10 @@           Just c <- solcRuntime "C" code'           Just a <- solcRuntime "A" code'           (_, [Cex (_, cex)]) <- withSolvers Z3 1 Nothing $ \s -> do-            let vm0 = abstractVM (mkCalldata (Just (Sig "call_A()" [])) []) c Nothing SymbolicS+            let vm0 = abstractVM (mkCalldata (Just (Sig "call_A()" [])) []) c Nothing AbstractStore             let vm = vm0-                  & set (state . callvalue) (Lit 0)-                  & over (EVM.env . contracts)+                  & set (#state % #callvalue) (Lit 0)+                  & over (#env % #contracts)                        (Map.insert aAddr (initialContract (RuntimeCode (ConcreteRuntimeCode a))))             verify s defaultVeriOpts vm (Just $ checkAssertions defaultPanicCodes) @@ -1818,7 +1830,7 @@         ,         ignoreTest $ testCase "safemath distributivity (yul)" $ do           let yulsafeDistributivity = hex "6355a79a6260003560e01c14156016576015601f565b5b60006000fd60a1565b603d602d604435600435607c565b6039602435600435607c565b605d565b6052604b604435602435605d565b600435607c565b141515605a57fe5b5b565b6000828201821115151560705760006000fd5b82820190505b92915050565b6000818384048302146000841417151560955760006000fd5b82820290505b92915050565b"-          let vm =  abstractVM (mkCalldata (Just (Sig "distributivity(uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) []) yulsafeDistributivity Nothing SymbolicS+          let vm =  abstractVM (mkCalldata (Just (Sig "distributivity(uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) []) yulsafeDistributivity Nothing AbstractStore           (_, [Qed _]) <-  withSolvers Z3 1 Nothing $ \s -> verify s defaultVeriOpts vm (Just $ checkAssertions defaultPanicCodes)           putStrLn "Proven"         ,@@ -1844,7 +1856,7 @@               }             |] -          (_, [Qed _]) <- withSolvers Z3 1 Nothing $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "distributivity(uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts+          (_, [Qed _]) <- withSolvers Z3 1 (Just 99999999) $ \s -> checkAssert s defaultPanicCodes c (Just (Sig "distributivity(uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) [] defaultVeriOpts           putStrLn "Proven"         ,         testCase "storage-cex-1" $ do@@ -1905,7 +1917,7 @@               }             }             |]-          (_, [Cex (_, cex)]) <- withSolvers Z3 1 Nothing $ \s -> verifyContract s c (Just (Sig "fun(uint256)" [AbiUIntType 256])) [] defaultVeriOpts ConcreteS Nothing (Just $ checkAssertions [0x01])+          (_, [Cex (_, cex)]) <- withSolvers Z3 1 Nothing $ \s -> verifyContract s c (Just (Sig "fun(uint256)" [AbiUIntType 256])) [] defaultVeriOpts EmptyStore Nothing (Just $ checkAssertions [0x01])           let testCex = Map.null cex.store           assertBool "Did not find expected storage cex" testCex           putStrLn "Expected counterexample found"@@ -2292,7 +2304,7 @@ runSimpleVM x ins = case loadVM x of                       Nothing -> Nothing                       Just vm -> let calldata' = (ConcreteBuf ins)-                       in case runState (assign (state . calldata) calldata' >> exec) vm of+                       in case runState (assign (#state % #calldata) calldata' >> exec) vm of                             (VMSuccess (ConcreteBuf bs), _) -> Just bs                             _ -> Nothing @@ -2301,11 +2313,11 @@ loadVM x =     case runState exec (vmForEthrunCreation x) of        (VMSuccess (ConcreteBuf targetCode), vm1) -> do-         let target = Control.Lens.view (state . contract) vm1+         let target = vm1.state.contract              vm2 = execState (replaceCodeOfSelf (RuntimeCode (ConcreteRuntimeCode targetCode))) vm1          return $ snd $ flip runState vm2                 (do resetState-                    assign (state . EVM.gas) 0xffffffffffffffff -- kludge+                    assign (#state % #gas) 0xffffffffffffffff -- kludge                     loadContract target)        _ -> Nothing @@ -2360,7 +2372,7 @@  getStaticAbiArgs :: Int -> VM -> [Expr EWord] getStaticAbiArgs n vm =-  let cd = Control.Lens.view (state . calldata) vm+  let cd = vm.state.calldata   in decodeStaticArgs 4 n cd  -- includes shaving off 4 byte function sig