Skip to content

Commit a2af711

Browse files
committed
Fetch: Refactor how we use RPC info and Fetcher
1 parent a9e3e20 commit a2af711

File tree

8 files changed

+42
-54
lines changed

8 files changed

+42
-54
lines changed

cli/cli.hs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import Data.Text.IO qualified as T
2525
import Data.Version (showVersion)
2626
import Data.Word (Word64)
2727
import GHC.Conc (getNumProcessors)
28+
import GitHash
2829
import Numeric.Natural (Natural)
2930
import Optics.Core ((&), set)
3031
import Witch (unsafeInto)
@@ -43,7 +44,6 @@ import EVM.ABI (Sig(..))
4344
import EVM.Dapp (dappInfo, DappInfo, emptyDapp)
4445
import EVM.Expr qualified as Expr
4546
import EVM.Concrete qualified as Concrete
46-
import GitHash
4747
import EVM.FeeSchedule (feeSchedule)
4848
import EVM.Fetch qualified as Fetch
4949
import EVM.Format (hexByteString, strip0x, formatExpr)
@@ -405,12 +405,11 @@ equivalence eqOpts cOpts = do
405405
when (isNothing bytecodeB) $ liftIO $ do
406406
putStrLn "Error: invalid or no bytecode for program B. Provide a valid one with --code-b or --code-b-file"
407407
exitFailure
408-
let veriOpts = VeriOpts { iterConf = IterConfig {
408+
let veriOpts = defaultVeriOpts { iterConf = IterConfig {
409409
maxIter = parseMaxIters cOpts.maxIterations
410410
, askSmtIters = cOpts.askSmtIterations
411411
, loopHeuristic = cOpts.loopDetectionHeuristic
412412
}
413-
, rpcInfo = mempty
414413
}
415414
calldata <- buildCalldata cOpts eqOpts.sig eqOpts.arg
416415
solver <- liftIO $ getSolver cOpts.solver
@@ -520,7 +519,7 @@ symbCheck cFileOpts sOpts cExecOpts cOpts = do
520519
, askSmtIters = cOpts.askSmtIterations
521520
, loopHeuristic = cOpts.loopDetectionHeuristic
522521
}
523-
, rpcInfo = mempty {Fetch.blockNumURL = blockUrlInfo}
522+
, rpcInfo = Fetch.RpcInfo blockUrlInfo
524523
}
525524
let fetcher = Fetch.oracle solvers (Just sess) veriOpts.rpcInfo
526525
(expr, res) <- verify solvers fetcher veriOpts preState (checkAssertions errCodes)
@@ -576,7 +575,7 @@ launchExec cFileOpts execOpts cExecOpts cOpts = do
576575
let
577576
block = maybe Fetch.Latest Fetch.BlockNumber cExecOpts.block
578577
blockUrlInfo = (,) block <$> cExecOpts.rpc
579-
rpcDat :: Fetch.RpcInfo = mempty { Fetch.blockNumURL = blockUrlInfo }
578+
rpcDat :: Fetch.RpcInfo = Fetch.RpcInfo blockUrlInfo
580579

581580
-- TODO: we shouldn't need solvers to execute this code
582581
withSolvers Z3 0 1 Nothing $ \solvers -> do
@@ -841,7 +840,7 @@ unitTestOptions testOpts cOpts solvers buildOutput = do
841840
(Just block, Just url) -> Just (Fetch.BlockNumber block, url)
842841
(Nothing, Just url) -> Just (Fetch.Latest, url)
843842
_ -> Nothing
844-
rpcDat = Fetch.mkRpcInfo blockUrlInfo
843+
rpcDat = Fetch.RpcInfo blockUrlInfo
845844
sess <- Fetch.mkSession cOpts.cacheDir testOpts.number
846845
params <- paramsFromRpc rpcDat sess
847846
let testn = params.number

src/EVM/Fetch.hs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ module EVM.Fetch
88
, RpcInfo (..)
99
, RpcQuery (..)
1010
, EVM.Fetch.zero
11+
, noRpc
12+
, noRpcFetcher
1113
, BlockNumber (..)
12-
, mkRpcInfo
1314
, mkSession
1415
, mkSessionWithoutCache
1516
, Session (..)
@@ -46,7 +47,6 @@ import Data.Bifunctor (first)
4647
import Control.Exception (try, SomeException)
4748

4849
import Control.Monad.Trans.Maybe
49-
import Control.Applicative (Alternative(..))
5050
import Data.Aeson hiding (Error)
5151
import Data.Aeson.Optics
5252
import Data.ByteString qualified as BS
@@ -137,18 +137,11 @@ instance ToJSON RPCContract
137137

138138
instance FromJSON RPCContract
139139

140-
data RpcInfo = RpcInfo
141-
{ blockNumURL :: Maybe (BlockNumber, Text) -- ^ (block number, RPC url)
142-
}
140+
newtype RpcInfo = RpcInfo { blockNumURL :: Maybe (BlockNumber, Text)} -- ^ (block number, RPC url)
143141
deriving (Show)
144-
instance Semigroup RpcInfo where
145-
RpcInfo a1 <> RpcInfo b1 =
146-
RpcInfo (a1 <|> b1)
147-
instance Monoid RpcInfo where
148-
mempty = RpcInfo Nothing
149142

150-
mkRpcInfo :: Maybe (BlockNumber, Text) -> RpcInfo
151-
mkRpcInfo blockNumURL = RpcInfo blockNumURL
143+
noRpc :: RpcInfo
144+
noRpc = RpcInfo Nothing
152145

153146
rpc :: String -> [Value] -> Value
154147
rpc method args = object
@@ -422,7 +415,10 @@ zero :: Natural -> Maybe Natural -> Fetcher t m s
422415
zero smtjobs smttimeout q = do
423416
sess <- mkSessionWithoutCache
424417
withSolvers Z3 smtjobs 1 smttimeout $ \s ->
425-
oracle s (Just sess) mempty q
418+
oracle s (Just sess) noRpc q
419+
420+
noRpcFetcher :: forall t m s . App m => SolverGroup -> Fetcher t m s
421+
noRpcFetcher sg = oracle sg Nothing noRpc
426422

427423
-- SMT solving + RPC data fetching + reading from environment
428424
oracle :: forall t m s . App m => SolverGroup -> Maybe Session -> RpcInfo -> Fetcher t m s

src/EVM/SymExec.hs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,9 @@ data VeriOpts = VeriOpts
105105
defaultVeriOpts :: VeriOpts
106106
defaultVeriOpts = VeriOpts
107107
{ iterConf = defaultIterConf
108-
, rpcInfo = mempty
108+
, rpcInfo = Fetch.noRpc
109109
}
110110

111-
rpcVeriOpts :: (Fetch.BlockNumber, Text) -> VeriOpts
112-
rpcVeriOpts info = defaultVeriOpts { rpcInfo = mempty { Fetch.blockNumURL = Just info }}
113-
114111
extractCex :: VerifyResult -> Maybe (Expr End, SMTCex)
115112
extractCex (Cex c) = Just c
116113
extractCex _ = Nothing
@@ -840,7 +837,7 @@ equivalenceCheck solvers sess bytecodeA bytecodeB opts calldata create = do
840837
conf <- readConfig
841838
let bytecode = if BS.null bs then BS.pack [0] else bs
842839
prestate <- liftIO $ stToIO $ abstractVM calldata bytecode Nothing create
843-
expr <- interpret (Fetch.oracle solvers sess mempty) opts.iterConf prestate runExpr
840+
expr <- interpret (Fetch.oracle solvers sess Fetch.noRpc) opts.iterConf prestate runExpr
844841
let simpl = if conf.simp then Expr.simplify expr else expr
845842
pure $ flattenExpr simpl
846843
oneQedOrNoQed :: EqIssues -> EqIssues

test/EVM/Test/BlockchainTests.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ prepareTests = do
109109

110110
runTest :: App m => EVM.Fetch.Session -> (String, Case) -> m TestTree
111111
runTest session (name, x) = do
112-
let fetcher q = withSolvers Z3 0 1 (Just 0) $ \s -> EVM.Fetch.oracle s (Just session) mempty q
112+
let fetcher q = withSolvers Z3 0 1 (Just 0) $ \s -> EVM.Fetch.oracle s (Just session) EVM.Fetch.noRpc q
113113
exec <- toIO $ runVMTest fetcher x
114114
pure $ testCase' name exec
115115
testCase' :: String -> Assertion -> TestTree

test/EVM/Test/FuzzSymExec.hs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ concretely through Expr.simplify, then check that against evmtool's output.
1313
module EVM.Test.FuzzSymExec where
1414

1515
import Control.Monad (when)
16+
import Control.Monad.IO.Unlift
1617
import Control.Monad.ST (ST, stToIO)
1718
import Control.Monad.State.Strict (StateT(..))
1819
import Control.Monad.Reader (ReaderT)
@@ -29,6 +30,7 @@ import Data.Word (Word8, Word64)
2930
import GHC.Generics (Generic)
3031
import GHC.IO.Exception (ExitCode(ExitSuccess))
3132
import Numeric (showHex)
33+
import Optics.Core hiding (pre)
3234
import System.Directory (removeDirectoryRecursive)
3335
import System.FilePath ((</>))
3436
import System.IO.Temp (getCanonicalTemporaryDirectory, createTempDirectory)
@@ -42,8 +44,6 @@ import Test.Tasty.HUnit (assertEqual, testCase)
4244
import Test.Tasty.QuickCheck hiding (Failure, Success)
4345
import Witch (into, unsafeInto)
4446

45-
import Optics.Core hiding (pre)
46-
4747
import EVM (makeVm, initialContract, symbolify)
4848
import EVM.Assembler (assemble)
4949
import EVM.Expr qualified as Expr
@@ -60,7 +60,6 @@ import EVM.Traversals (mapExpr)
6060
import EVM.Transaction qualified
6161
import EVM.Types hiding (Env)
6262
import EVM.Effects
63-
import Control.Monad.IO.Unlift
6463
import EVM.Tracing (interpretWithTrace, VMTraceStep(..), VMTraceStepResult(..))
6564

6665
data EVMToolTrace =
@@ -283,7 +282,7 @@ getHEVMRet
283282
=> OpContract -> ByteString -> Int -> m (Either (EvmError, [VMTraceStep]) (Expr 'End, [VMTraceStep], VMTraceStepResult))
284283
getHEVMRet contr txData gaslimitExec = do
285284
let (txn, evmEnv, contrAlloc, fromAddress, toAddress, _) = evmSetup contr txData gaslimitExec
286-
runCodeWithTrace mempty evmEnv contrAlloc txn (LitAddr fromAddress) (LitAddr toAddress)
285+
runCodeWithTrace Fetch.noRpc evmEnv contrAlloc txn (LitAddr fromAddress) (LitAddr toAddress)
287286

288287
getEVMToolRet :: FilePath -> OpContract -> ByteString -> Int -> IO (Maybe EVMToolResult)
289288
getEVMToolRet evmDir contr txData gaslimitExec = do

test/EVM/Test/Utils.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import EVM.Effects
2424
import Data.Maybe (fromMaybe)
2525
import EVM.Types (internalError)
2626
import System.Environment (lookupEnv)
27-
import EVM.Fetch (RpcInfo)
27+
import EVM.Fetch (RpcInfo, noRpc)
2828
import EVM.Fetch qualified as Fetch
2929

3030
-- Returns tuple of (No cex, No warnings)
@@ -47,7 +47,7 @@ runForgeTestCustom testFile match timeout maxIter ffiAllowed rpcinfo = do
4747
runForgeTest
4848
:: (MonadMask m, App m)
4949
=> FilePath -> Text -> m (Bool, Bool)
50-
runForgeTest testFile match = runForgeTestCustom testFile match Nothing Nothing True mempty
50+
runForgeTest testFile match = runForgeTestCustom testFile match Nothing Nothing True noRpc
5151

5252
testOpts :: forall m . App m => SolverGroup -> FilePath -> Maybe BuildOutput -> Text -> Maybe Integer -> Bool -> RpcInfo -> m (UnitTestOptions RealWorld)
5353
testOpts solvers root buildOutput match maxIter allowFFI rpcinfo = do

test/rpc.hs

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,12 @@ tests = testGroup "rpc"
8282
-- https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2#code
8383
, test "weth-conc" $ do
8484
let
85-
blockNum = 16198552
8685
wad = 0x999999999999999999
8786
calldata' = ConcreteBuf $ abiMethod "transfer(address,uint256)" (AbiTuple (V.fromList [AbiAddress (Addr 0xdead), AbiUInt 256 wad]))
88-
rpcDat = Just (BlockNumber blockNum, testRpc)
89-
rpcInfo :: RpcInfo = mempty { blockNumURL = rpcDat }
9087
sess <- mkSessionWithoutCache
91-
vm <- weth9VM sess blockNum (calldata', [])
88+
vm <- weth9VM sess testBlockNumber (calldata', [])
9289
postVm <- withSolvers Z3 1 1 Nothing $ \solvers ->
93-
Stepper.interpret (oracle solvers (Just sess) rpcInfo) vm Stepper.runFully
90+
Stepper.interpret (oracle solvers (Just sess) testRpcInfo) vm Stepper.runFully
9491
let
9592
wethStore = (fromJust $ Map.lookup (LitAddr 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) postVm.env.contracts).storage
9693
wethStore' = case wethStore of
@@ -109,36 +106,34 @@ tests = testGroup "rpc"
109106
, test "weth-sym" $ do
110107
calldata' <- symCalldata "transfer(address,uint256)" [AbiAddressType, AbiUIntType 256] ["0xdead"] (AbstractBuf "txdata")
111108
let
112-
blockNum = 16198552
113109
postc _ (Failure _ _ (Revert _)) = PBool False
114110
postc _ _ = PBool True
115111
sess <- mkSession Nothing Nothing
116-
vm <- weth9VM sess blockNum calldata'
112+
vm <- weth9VM sess testBlockNumber calldata'
117113
(_, [Cex (_, model)]) <- withSolvers Z3 1 1 Nothing $ \s ->
118-
let rpcInfo ::RpcInfo = mempty { blockNumURL = Just (BlockNumber blockNum, testRpc) }
119-
in verify s (oracle s (Just sess) rpcInfo) (rpcVeriOpts (fromJust rpcInfo.blockNumURL)) (symbolify vm) postc
114+
verify s (oracle s (Just sess) testRpcInfo) (defaultVeriOpts {rpcInfo = testRpcInfo}) (symbolify vm) postc
120115
liftIO $ assertBool "model should exceed caller balance" (getVar model "arg2" >= 695836005599316055372648)
121116
]
122117
]
123118

124119
-- call into WETH9 from 0xf04a... (a large holder)
125-
weth9VM :: App m => Session -> W256 -> (Expr Buf, [Prop]) -> m (VM Concrete RealWorld)
120+
weth9VM :: App m => Session -> BlockNumber -> (Expr Buf, [Prop]) -> m (VM Concrete RealWorld)
126121
weth9VM sess blockNum calldata' = do
127122
let
128123
caller' = LitAddr 0xf04a5cc80b1e94c69b48f5ee68a08cd2f09a7c3e
129124
weth9 = Addr 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
130125
callvalue' = Lit 0
131126
vmFromRpc sess blockNum calldata' callvalue' caller' weth9
132127

133-
vmFromRpc :: App m => Session -> W256 -> (Expr Buf, [Prop]) -> Expr EWord -> Expr EAddr -> Addr -> m (VM Concrete RealWorld)
128+
vmFromRpc :: App m => Session -> BlockNumber -> (Expr Buf, [Prop]) -> Expr EWord -> Expr EAddr -> Addr -> m (VM Concrete RealWorld)
134129
vmFromRpc sess blockNum calldata callvalue caller address = do
135130
conf <- readConfig
136-
ctrct <- liftIO $ fetchContractWithSession conf sess (BlockNumber blockNum) testRpc address >>= \case
131+
ctrct <- liftIO $ fetchContractWithSession conf sess blockNum testRpc address >>= \case
137132
Nothing -> internalError $ "contract not found: " <> show address
138133
Just contract' -> pure contract'
139134

140135
liftIO $ addFetchCache sess address ctrct
141-
blk <- liftIO $ fetchBlockWithSession conf sess (BlockNumber blockNum) testRpc >>= \case
136+
blk <- liftIO $ fetchBlockWithSession conf sess blockNum testRpc >>= \case
142137
Nothing -> internalError "could not fetch block"
143138
Just b -> pure b
144139

@@ -174,6 +169,8 @@ vmFromRpc sess blockNum calldata callvalue caller address = do
174169
testRpc :: Text
175170
testRpc = "https://eth-mainnet.alchemyapi.io/v2/vpeKFsEF6PHifHzdtcwXSDbhV3ym5Ro4"
176171

172+
testBlockNumber :: BlockNumber
173+
testBlockNumber = BlockNumber 16198552
174+
177175
testRpcInfo :: RpcInfo
178-
testRpcInfo = let rpcDat = Just (BlockNumber 16198552, testRpc)
179-
in mempty { blockNumURL = rpcDat }
176+
testRpcInfo = RpcInfo $ Just (testBlockNumber, testRpc)

test/test.hs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,7 +1891,7 @@ tests = testGroup "hevm"
18911891
let calldata = (WriteWord (Lit 0x0) (Var "u") (ConcreteBuf ""), [])
18921892
initVM <- liftIO $ stToIO $ abstractVM calldata initCode Nothing True
18931893
let iterConf = IterConfig {maxIter=Nothing, askSmtIters=1, loopHeuristic=StackBased }
1894-
expr <- Expr.simplify <$> interpret (Fetch.oracle s Nothing mempty) iterConf initVM runExpr
1894+
expr <- Expr.simplify <$> interpret (Fetch.noRpcFetcher s) iterConf initVM runExpr
18951895
assertBoolM "unexptected partial execution" (not $ Expr.containsNode isPartial expr)
18961896
, test "mixed-concrete-symbolic-args" $ do
18971897
Just c <- solcRuntime "C"
@@ -1982,7 +1982,7 @@ tests = testGroup "hevm"
19821982
withDefaultSolver $ \s -> do
19831983
vm <- liftIO $ stToIO $ loadSymVM runtimecode (Lit 0) initCode False
19841984
let iterConf = IterConfig {maxIter=Nothing, askSmtIters=1, loopHeuristic=StackBased }
1985-
expr <- Expr.simplify <$> interpret (Fetch.oracle s Nothing mempty) iterConf vm runExpr
1985+
expr <- Expr.simplify <$> interpret (Fetch.noRpcFetcher s) iterConf vm runExpr
19861986
case expr of
19871987
Partial _ _ (JumpIntoSymbolicCode _ _ _) -> assertBoolM "" True
19881988
_ -> assertBoolM "did not encounter expected partial node" False
@@ -2022,7 +2022,7 @@ tests = testGroup "hevm"
20222022
, ("test/contracts/fail/symbolicFail.sol", "prove_symb_fail_allrev_selector.*", (False, False))
20232023
, ("test/contracts/fail/symbolicFail.sol", "prove_symb_fail_somerev_selector.*", (False, True))]
20242024
forM_ cases $ \(testFile, match, expected) -> do
2025-
actual <- runForgeTestCustom testFile match Nothing Nothing False mempty
2025+
actual <- runForgeTestCustom testFile match Nothing Nothing False Fetch.noRpc
20262026
putStrLnM $ "Test result for " <> testFile <> " match: " <> T.unpack match <> ": " <> show actual
20272027
assertEqualM "Must match" expected actual
20282028
, test "Trivial-Fail" $ do
@@ -2055,14 +2055,14 @@ tests = testGroup "hevm"
20552055
runForgeTest testFile "prove_trivial" >>= assertEqualM "prove_trivial" (False, False)
20562056
runForgeTest testFile "prove_trivial_dstest" >>= assertEqualM "prove_trivial_dstest" (False, False)
20572057
runForgeTest testFile "prove_add" >>= assertEqualM "prove_add" (False, True)
2058-
runForgeTestCustom testFile "prove_smtTimeout" (Just 1) Nothing False mempty
2058+
runForgeTestCustom testFile "prove_smtTimeout" (Just 1) Nothing False Fetch.noRpc
20592059
>>= assertEqualM "prove_smtTimeout" (True, False)
20602060
runForgeTest testFile "prove_multi" >>= assertEqualM "prove_multi" (False, True)
20612061
runForgeTest testFile "prove_distributivity" >>= assertEqualM "prove_distributivity" (False, True)
20622062
, test "Loop-Tests" $ do
20632063
let testFile = "test/contracts/pass/loops.sol"
2064-
runForgeTestCustom testFile "prove_loop" Nothing (Just 10) False mempty >>= assertEqualM "test result" (True, False)
2065-
runForgeTestCustom testFile "prove_loop" Nothing (Just 100) False mempty >>= assertEqualM "test result" (False, False)
2064+
runForgeTestCustom testFile "prove_loop" Nothing (Just 10) False Fetch.noRpc >>= assertEqualM "test result" (True, False)
2065+
runForgeTestCustom testFile "prove_loop" Nothing (Just 100) False Fetch.noRpc >>= assertEqualM "test result" (False, False)
20662066
, test "Cheat-Codes-Pass" $ do
20672067
let testFile = "test/contracts/pass/cheatCodes.sol"
20682068
runForgeTest testFile ".*" >>= assertEqualM "test result" (True, False)
@@ -4218,7 +4218,7 @@ tests = testGroup "hevm"
42184218
<&> set (#state % #callvalue) (Lit 0)
42194219
<&> over (#env % #contracts)
42204220
(Map.insert aAddr (initialContract (RuntimeCode (ConcreteRuntimeCode a))))
4221-
verify s (Fetch.oracle s Nothing mempty) defaultVeriOpts vm (checkAssertions defaultPanicCodes)
4221+
verify s (Fetch.noRpcFetcher s) defaultVeriOpts vm (checkAssertions defaultPanicCodes)
42224222

42234223
let storeCex = cex.store
42244224
testCex = case (Map.lookup cAddr storeCex, Map.lookup aAddr storeCex) of
@@ -4294,7 +4294,7 @@ tests = testGroup "hevm"
42944294
let yulsafeDistributivity = hex "6355a79a6260003560e01c14156016576015601f565b5b60006000fd60a1565b603d602d604435600435607c565b6039602435600435607c565b605d565b6052604b604435602435605d565b600435607c565b141515605a57fe5b5b565b6000828201821115151560705760006000fd5b82820190505b92915050565b6000818384048302146000841417151560955760006000fd5b82820290505b92915050565b"
42954295
calldata <- mkCalldata (Just (Sig "distributivity(uint256,uint256,uint256)" [AbiUIntType 256, AbiUIntType 256, AbiUIntType 256])) []
42964296
vm <- liftIO $ stToIO $ abstractVM calldata yulsafeDistributivity Nothing False
4297-
(_, [Qed]) <- withDefaultSolver $ \s -> verify s (Fetch.oracle s Nothing mempty) defaultVeriOpts vm (checkAssertions defaultPanicCodes)
4297+
(_, [Qed]) <- withDefaultSolver $ \s -> verify s (Fetch.noRpcFetcher s) defaultVeriOpts vm (checkAssertions defaultPanicCodes)
42984298
putStrLnM "Proven"
42994299
,
43004300
test "safemath-distributivity-sol" $ do

0 commit comments

Comments
 (0)