Skip to content

Commit 118a860

Browse files
authored
Merge pull request #908 from argotorg/fix-blockchain-tests
Test: Fix parsing of contracts in ethereum-tests
2 parents acb72d0 + 1fa1411 commit 118a860

File tree

6 files changed

+46
-53
lines changed

6 files changed

+46
-53
lines changed

cli/cli.hs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -646,20 +646,19 @@ vmFromCommand cOpts cExecOpts cFileOpts execOpts sess = do
646646
Nothing -> do
647647
putStrLn $ "Error: contract not found: " <> show address
648648
exitFailure
649-
Just contract ->
649+
Just rpcContract ->
650650
-- if both code and url is given,
651651
-- fetch the contract and overwrite the code
652-
pure $ initialContract (mkCode $ fromJust code)
653-
& set #balance (contract.balance)
654-
& set #nonce (contract.nonce)
655-
& set #external (contract.external)
652+
pure $ initialContract (mkCode $ fromJust code)
653+
& set #balance (Lit rpcContract.balance)
654+
& set #nonce (Just rpcContract.nonce)
656655

657656
(Just url, Just addr', Nothing) ->
658657
liftIO $ Fetch.fetchContractWithSession conf sess block url addr' >>= \case
659658
Nothing -> do
660659
putStrLn $ "Error, contract not found: " <> show address
661660
exitFailure
662-
Just contract -> pure contract
661+
Just rpcContract -> pure $ Fetch.makeContractFromRPC rpcContract
663662

664663
(_, _, Just c) -> do
665664
let code = hexByteString $ strip0x c
@@ -760,8 +759,8 @@ symvmFromCommand cExecOpts sOpts cFileOpts sess calldata = do
760759
Nothing -> do
761760
putStrLn "Error, contract not found."
762761
exitFailure
763-
Just contract' -> case codeWrapped of
764-
Nothing -> pure contract'
762+
Just rpcContract' -> case codeWrapped of
763+
Nothing -> pure $ Fetch.makeContractFromRPC rpcContract'
765764
-- if both code and url is given,
766765
-- fetch the contract and overwrite the code
767766
Just c -> do
@@ -771,10 +770,8 @@ symvmFromCommand cExecOpts sOpts cFileOpts sess calldata = do
771770
exitFailure
772771
else pure $ do
773772
initialContract (mkCode $ fromJust c')
774-
& set #origStorage (contract'.origStorage)
775-
& set #balance (contract'.balance)
776-
& set #nonce (contract'.nonce)
777-
& set #external (contract'.external)
773+
& set #balance (Lit rpcContract'.balance)
774+
& set #nonce (Just rpcContract'.nonce)
778775

779776
(_, _, Just c) -> liftIO $ do
780777
let c' = decipher c

src/EVM/Fetch.hs

Lines changed: 17 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ module EVM.Fetch
1919
, FetchCache (..)
2020
, addFetchCache
2121
, saveCache
22+
, RPCContract (..)
23+
, makeContractFromRPC
2224
) where
2325

2426
import Prelude hiding (Foldable(..))
@@ -41,7 +43,6 @@ import Data.Aeson.Encode.Pretty (encodePretty)
4143
import qualified Data.ByteString.Lazy as BSL
4244
import Data.Bifunctor (first)
4345
import Control.Exception (try, SomeException)
44-
import Control.Monad (join)
4546

4647
import Control.Monad.Trans.Maybe
4748
import Control.Applicative (Alternative(..))
@@ -75,36 +76,11 @@ data Session = Session
7576
}
7677

7778
data FetchCache = FetchCache
78-
{ contractCache :: Map.Map Addr Contract
79+
{ contractCache :: Map.Map Addr RPCContract
7980
, slotCache :: Map.Map (Addr, W256) W256
8081
, blockCache :: Map.Map W256 Block
8182
} deriving (Generic)
8283

83-
instance ToJSON Contract where
84-
toJSON c = object
85-
[ "code" .= case c.code of
86-
RuntimeCode (ConcreteRuntimeCode bs) -> Just (ByteStringS bs)
87-
_ -> Nothing
88-
, "nonce" .= c.nonce
89-
, "balance" .= case c.balance of
90-
Lit w -> Just w
91-
_ -> Nothing
92-
, "external" .= c.external
93-
]
94-
95-
instance FromJSON Contract where
96-
parseJSON = withObject "Contract" $ \v -> do
97-
maybeCodeText <- v .:? "code"
98-
let mcCode = hexText <$> join maybeCodeText
99-
mcNonce <- v .: "nonce"
100-
maybeBalance <- v .:? "balance"
101-
let mcBalance = join maybeBalance
102-
external <- v .: "external"
103-
let code = maybe (RuntimeCode (ConcreteRuntimeCode "")) (RuntimeCode . ConcreteRuntimeCode) mcCode
104-
pure $ initialContract code
105-
& #nonce .~ mcNonce
106-
& #balance .~ maybe (Lit 0) Lit mcBalance
107-
& #external .~ external
10884

10985
instance ToJSON FetchCache where
11086
toJSON (FetchCache cs ss bs) = object
@@ -150,11 +126,15 @@ data BlockNumber = Latest | BlockNumber W256
150126
deriving instance Show (RpcQuery a)
151127

152128
data RPCContract = RPCContract
153-
{ mcCode :: BS.ByteString
154-
, mcNonce :: W64
155-
, mcBalance :: W256
129+
{ code :: ByteStringS
130+
, nonce :: W64
131+
, balance :: W256
156132
}
157-
deriving (Eq, Show)
133+
deriving (Eq, Show, Generic)
134+
135+
instance ToJSON RPCContract
136+
137+
instance FromJSON RPCContract
158138

159139
data RpcInfo = RpcInfo
160140
{ blockNumURL :: Maybe (BlockNumber, Text) -- ^ (block number, RPC url)
@@ -196,7 +176,7 @@ instance ToRPC BlockNumber where
196176
readText :: Read a => Text -> a
197177
readText = read . unpack
198178

199-
addFetchCache :: Session -> Addr -> Contract -> IO ()
179+
addFetchCache :: Session -> Addr -> RPCContract -> IO ()
200180
addFetchCache sess address ctrct = do
201181
cache <- readMVar sess.sharedCache
202182
liftIO $ modifyMVar_ sess.sharedCache $ \c -> pure $ c { contractCache = (Map.insert address ctrct cache.contractCache) }
@@ -296,7 +276,7 @@ fetchWithSession url sess x = do
296276
r <- asValue =<< NetSession.post sess (unpack url) x
297277
pure (r ^? (lensVL responseBody) % key "result")
298278

299-
fetchContractWithSession :: Config -> Session -> BlockNumber -> Text -> Addr -> IO (Maybe Contract)
279+
fetchContractWithSession :: Config -> Session -> BlockNumber -> Text -> Addr -> IO (Maybe RPCContract)
300280
fetchContractWithSession conf sess nPre url addr = do
301281
n <- getLatestBlockNum conf sess nPre url
302282
cache <- readMVar sess.sharedCache
@@ -312,7 +292,7 @@ fetchContractWithSession conf sess nPre url addr = do
312292
code <- MaybeT $ fetch (QueryCode addr)
313293
nonce <- MaybeT $ fetch (QueryNonce addr)
314294
balance <- MaybeT $ fetch (QueryBalance addr)
315-
let contr = makeContractFromRPC (RPCContract code nonce balance)
295+
let contr = RPCContract (ByteStringS code) nonce balance
316296
liftIO $ modifyMVar_ sess.sharedCache $ \c ->
317297
pure $ c { contractCache = Map.insert addr contr c.contractCache }
318298
pure contr
@@ -338,7 +318,7 @@ getLatestBlockNum conf sess n url =
338318
_ -> pure n
339319

340320
makeContractFromRPC :: RPCContract -> Contract
341-
makeContractFromRPC (RPCContract code nonce balance) =
321+
makeContractFromRPC (RPCContract (ByteStringS code) nonce balance) =
342322
initialContract (RuntimeCode (ConcreteRuntimeCode code))
343323
& set #nonce (Just nonce)
344324
& set #balance (Lit balance)
@@ -490,13 +470,13 @@ oracle solvers preSess rpcInfo q = do
490470
case Map.lookup addr cache.contractCache of
491471
Just c -> do
492472
when (conf.debug) $ liftIO $ putStrLn $ "-> Using cached contract at " ++ show addr
493-
pure $ continue c
473+
pure $ continue $ makeContractFromRPC c
494474
Nothing -> do
495475
when (conf.debug) $ liftIO $ putStrLn $ "Fetching contract at " ++ show addr
496476
when (addr == 0 && conf.verb > 0) $ liftIO $ putStrLn "Warning: fetching contract at address 0"
497477
contract <- case rpcInfo.blockNumURL of
498478
Nothing -> pure $ Just $ nothingContract base addr
499-
Just (block, url) -> liftIO $ fetchContractWithSession conf sess block url addr
479+
Just (block, url) -> liftIO $ fmap (fmap makeContractFromRPC) $ fetchContractWithSession conf sess block url addr
500480
case contract of
501481
Just x -> pure $ continue x
502482
Nothing -> internalError $ "oracle error: " ++ show q

src/EVM/Types.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1237,7 +1237,9 @@ instance Show ByteStringS where
12371237
T.decodeUtf8 . toStrict . toLazyByteString . byteStringHex
12381238

12391239
instance JSON.FromJSON ByteStringS where
1240-
parseJSON (JSON.String x) = case BS16.decodeBase16Untyped (T.encodeUtf8 x) of
1240+
parseJSON (JSON.String x) =
1241+
let x' = if "0x" `T.isPrefixOf` x then T.drop 2 x else x in
1242+
case BS16.decodeBase16Untyped (T.encodeUtf8 x') of
12411243
Left _ -> mzero
12421244
Right bs -> pure (ByteStringS bs)
12431245
parseJSON _ = mzero

test/EVM/Test/BlockchainTests.hs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import EVM (initialContract, makeVm, setEIP4788Storage)
44
import EVM.Concrete qualified as EVM
55
import EVM.FeeSchedule (feeSchedule)
66
import EVM.Fetch qualified
7+
import EVM.Format (hexText)
78
import EVM.Stepper qualified
89
import EVM.Transaction
910
import EVM.UnitTest (writeTrace)
@@ -328,6 +329,21 @@ clearNonce c = set #nonce (Just 0) c
328329
clearCode :: Contract -> Contract
329330
clearCode c = set #code (RuntimeCode (ConcreteRuntimeCode "")) c
330331

332+
instance FromJSON Contract where
333+
parseJSON (JSON.Object v) = do
334+
code <- (RuntimeCode . ConcreteRuntimeCode <$> (hexText <$> v .: "code"))
335+
storage <- v .: "storage"
336+
balance <- v .: "balance"
337+
nonce <- v .: "nonce"
338+
pure $ EVM.initialContract code
339+
& #balance .~ (Lit balance)
340+
& #nonce ?~ nonce
341+
& #storage .~ (ConcreteStore storage)
342+
& #origStorage .~ (ConcreteStore storage)
343+
344+
parseJSON invalid =
345+
JSON.typeMismatch "Contract" invalid
346+
331347
instance FromJSON BlockchainCase where
332348
parseJSON (JSON.Object v) = BlockchainCase
333349
<$> v .: "blocks"

test/contracts/fail/rpc-cache-10307563.json

Lines changed: 0 additions & 2 deletions
Large diffs are not rendered by default.

test/rpc.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ vmFromRpc sess blockNum calldata callvalue caller address = do
143143
Just b -> pure b
144144

145145
liftIO $ stToIO (makeVm $ VMOpts
146-
{ contract = ctrct
146+
{ contract = makeContractFromRPC ctrct
147147
, otherContracts = []
148148
, calldata = calldata
149149
, value = callvalue

0 commit comments

Comments
 (0)