Skip to content

Commit 141eb25

Browse files
authored
Simplifyexec (dapphub#418)
* hevm: Remove ExecMode, always choosing with ExecuteAsBlockchainTest omitting --code simply creates an empty contract useful in combination with --state flag * hevm update changelog
1 parent f87331c commit 141eb25

File tree

5 files changed

+72
-143
lines changed

5 files changed

+72
-143
lines changed

src/hevm/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
## 0.39 - unreleased
44
- Exposes abi encoding to cli
55
- Added cheat code `hevm.store(address a, bytes32 location, bytes32 value)`
6+
- Removes `ExecMode`, always running as `ExecuteAsBlockchainTest`. This means that `hevm exec` now finalizes transactions as well.
7+
- `--code` is now entirely optional. Not supplying it returns an empty contract, or whatever is stored in `--state`.
68

79
## 0.38 - 2020-04-23
810
- Exposes metadata stripping of bytecode to the cli: `hevm strip-metadata --code X`. [357](https://github.com/dapphub/dapptools/pull/357).

src/hevm/hevm-cli/hevm-cli.hs

+24-40
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import Text.ParserCombinators.ReadP
2424
import qualified EVM.VMTest as VMTest
2525
#endif
2626

27-
import EVM (ExecMode(..))
2827
import EVM.Concrete (createAddress, w256)
2928
import EVM.Debug
3029
import EVM.Exec
@@ -132,13 +131,6 @@ data Command w
132131
, diff :: w ::: Bool <?> "Print expected vs. actual state on failure"
133132
, timeout :: w ::: Maybe Int <?> "Execution timeout (default: 10 sec.)"
134133
}
135-
| VmTest -- Run an Ethereum VMTest
136-
{ file :: w ::: String <?> "Path to .json test file"
137-
, test :: w ::: [String] <?> "Test case filter - only run specified test method(s)"
138-
, debug :: w ::: Bool <?> "Run interactively"
139-
, diff :: w ::: Bool <?> "Print expected vs. actual state on failure"
140-
, timeout :: w ::: Maybe Int <?> "Execution timeout (default: 10 sec.)"
141-
}
142134
| Compliance -- Run Ethereum Blockhain or VMTest compliance report
143135
{ tests :: w ::: String <?> "Path to Ethereum Tests directory"
144136
, group :: w ::: Maybe String <?> "Report group to run: VM or Blockchain (default: Blockchain)"
@@ -228,10 +220,8 @@ main = do
228220
launchExec cmd
229221
Abiencode {} ->
230222
print . ByteStringS $ abiencode (abi cmd) (arg cmd)
231-
VmTest {} ->
232-
launchTest ExecuteAsVMTest cmd
233223
BcTest {} ->
234-
launchTest ExecuteAsBlockchainTest cmd
224+
launchTest cmd
235225
DappTest {} ->
236226
withCurrentDirectory root $ do
237227
testFile <- findJsonFile (jsonFile cmd)
@@ -452,23 +442,21 @@ tohexOrText s = case "0x" `Char8.isPrefixOf` encodeUtf8 s of
452442

453443
vmFromCommand :: Command Options.Unwrapped -> IO EVM.VM
454444
vmFromCommand cmd = do
455-
vm <- case (rpc cmd, address cmd, code cmd) of
456-
(Just url, Just addr', _) -> do maybeContract <- EVM.Fetch.fetchContractFrom block' url addr'
457-
case maybeContract of
458-
Nothing -> error $ "contract not found: " <> show address' <> "and no --code given"
459-
Just contract' -> case (code cmd) of
460-
Nothing -> return (vm1 contract')
461-
-- if both code and url is given,
462-
-- fetch the contract and overwrite the code
463-
Just c -> return $ vm1 (
464-
EVM.initialContract (codeType $ hexByteString "--code" $ strip0x c)
465-
& set EVM.storage (view EVM.storage contract')
466-
& set EVM.balance (view EVM.balance contract')
467-
& set EVM.nonce (view EVM.nonce contract')
468-
& set EVM.external (view EVM.external contract'))
469-
470-
(_, _, Just c) -> return $ vm1 $ EVM.initialContract $ codeType $ hexByteString "--code" $ strip0x c
471-
(_, _, Nothing) -> error $ "must provide at least (rpc + address) or code"
445+
vm <- case (rpc cmd, address cmd) of
446+
(Just url, Just addr') -> do EVM.Fetch.fetchContractFrom block' url addr' >>= \case
447+
Nothing -> error $ "contract not found: " <> show address'
448+
Just contract' -> case code cmd of
449+
Nothing -> return (vm1 contract')
450+
-- if both code and url is given,
451+
-- fetch the contract and overwrite the code
452+
Just c -> return . vm1 $
453+
EVM.initialContract (codeType $ hexByteString "--code" $ strip0x c)
454+
& set EVM.storage (view EVM.storage contract')
455+
& set EVM.balance (view EVM.balance contract')
456+
& set EVM.nonce (view EVM.nonce contract')
457+
& set EVM.external (view EVM.external contract')
458+
459+
_ -> return . vm1 . EVM.initialContract . codeType $ bytes code ""
472460

473461
return $ vm & EVM.env . EVM.contracts . ix address' . EVM.balance +~ (w256 value')
474462
where
@@ -505,14 +493,10 @@ vmFromCommand cmd = do
505493
addr f def = fromMaybe def (f cmd)
506494
bytes f def = maybe def (hexByteString "bytes" . strip0x) (f cmd)
507495

508-
launchTest :: ExecMode -> Command Options.Unwrapped -> IO ()
509-
launchTest execmode cmd = do
496+
launchTest :: Command Options.Unwrapped -> IO ()
497+
launchTest cmd = do
510498
#if MIN_VERSION_aeson(1, 0, 0)
511-
let parser = case execmode of
512-
ExecuteAsVMTest -> VMTest.parseSuite
513-
ExecuteAsBlockchainTest -> VMTest.parseBCSuite
514-
ExecuteNormally -> error "cannot launchTest normally"
515-
parsed <- parser <$> LazyByteString.readFile (file cmd)
499+
parsed <- VMTest.parseBCSuite <$> LazyByteString.readFile (file cmd)
516500
case parsed of
517501
Left "No cases to check." -> putStrLn "no-cases ok"
518502
Left err -> print err
@@ -522,16 +506,16 @@ launchTest execmode cmd = do
522506
then id
523507
else filter (\(x, _) -> elem x (test cmd))
524508
in
525-
mapM_ (runVMTest (diff cmd) execmode (optsMode cmd) (timeout cmd)) $
509+
mapM_ (runVMTest (diff cmd) (optsMode cmd) (timeout cmd)) $
526510
testFilter (Map.toList allTests)
527511
#else
528512
putStrLn "Not supported"
529513
#endif
530514

531515
#if MIN_VERSION_aeson(1, 0, 0)
532-
runVMTest :: Bool -> ExecMode -> Mode -> Maybe Int -> (String, VMTest.Case) -> IO Bool
533-
runVMTest diffmode execmode mode timelimit (name, x) = do
534-
let vm0 = VMTest.vmForCase execmode x
516+
runVMTest :: Bool -> Mode -> Maybe Int -> (String, VMTest.Case) -> IO Bool
517+
runVMTest diffmode mode timelimit (name, x) = do
518+
let vm0 = VMTest.vmForCase x
535519
putStr (name ++ " ")
536520
hFlush stdout
537521
result <- do
@@ -545,7 +529,7 @@ runVMTest diffmode execmode mode timelimit (name, x) = do
545529
waitCatch action
546530
case result of
547531
Right (Just vm1) -> do
548-
ok <- VMTest.checkExpectation diffmode execmode x vm1
532+
ok <- VMTest.checkExpectation diffmode x vm1
549533
putStrLn (if ok then "ok" else "")
550534
return ok
551535
Right Nothing -> do

src/hevm/src/EVM.hs

+34-54
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ data VM = VM
100100
, _logs :: Seq Log
101101
, _traces :: Zipper.TreePos Zipper.Empty Trace
102102
, _cache :: Cache
103-
, _execMode :: ExecMode
104103
, _burned :: Word
105104
}
106105

@@ -118,8 +117,6 @@ data TraceData
118117
| EntryTrace Text
119118
| ReturnTrace ByteString FrameContext
120119

121-
data ExecMode = ExecuteNormally | ExecuteAsBlockchainTest | ExecuteAsVMTest
122-
123120
data Query where
124121
PleaseFetchContract :: Addr -> (Contract -> EVM ()) -> Query
125122
PleaseFetchSlot :: Addr -> Word -> (Word -> EVM ()) -> Query
@@ -371,7 +368,6 @@ makeVm o = VM
371368
}
372369
, _cache = Cache $ Map.fromList
373370
[(vmoptAddress o, vmoptContract o)]
374-
, _execMode = ExecuteNormally
375371
, _burned = 0
376372
} where theCode = case _contractcode (vmoptContract o) of
377373
InitCode b -> b
@@ -1455,43 +1451,40 @@ finalize = do
14551451
creation <- use (tx . isCreate)
14561452
createe <- use (state . contract)
14571453
createeExists <- (Map.member createe) <$> use (env . contracts)
1458-
if (creation && createeExists)
1454+
1455+
if creation && createeExists
14591456
then replaceCode createe (RuntimeCode output)
14601457
else noop
14611458

1462-
use execMode >>= \case
1463-
ExecuteAsVMTest ->
1464-
noop
1465-
_ -> do
1466-
-- compute and pay the refund to the caller and the
1467-
-- corresponding payment to the miner
1468-
txOrigin <- use (tx . origin)
1469-
sumRefunds <- (sum . (snd <$>)) <$> (use (tx . substate . refunds))
1470-
miner <- use (block . coinbase)
1471-
blockReward <- r_block <$> (use (block . schedule))
1472-
gasPrice <- use (tx . gasprice)
1473-
gasLimit <- use (tx . txgaslimit)
1474-
gasRemaining <- use (state . gas)
1475-
1476-
let
1477-
gasUsed = gasLimit - gasRemaining
1478-
cappedRefund = min (quot gasUsed 2) sumRefunds
1479-
originPay = (gasRemaining + cappedRefund) * gasPrice
1480-
minerPay = gasPrice * (gasUsed - cappedRefund)
1481-
1482-
modifying (env . contracts)
1483-
(Map.adjust (over balance (+ originPay)) txOrigin)
1484-
modifying (env . contracts)
1485-
(Map.adjust (over balance (+ minerPay)) miner)
1486-
touchAccount miner
1487-
1488-
-- pay out the block reward, recreating the miner if necessary
1489-
preuse (env . contracts . ix miner) >>= \case
1490-
Nothing -> modifying (env . contracts)
1491-
(Map.insert miner (initialContract (EVM.RuntimeCode mempty)))
1492-
Just _ -> noop
1493-
modifying (env . contracts)
1494-
(Map.adjust (over balance (+ blockReward)) miner)
1459+
-- compute and pay the refund to the caller and the
1460+
-- corresponding payment to the miner
1461+
txOrigin <- use (tx . origin)
1462+
sumRefunds <- (sum . (snd <$>)) <$> (use (tx . substate . refunds))
1463+
miner <- use (block . coinbase)
1464+
blockReward <- r_block <$> (use (block . schedule))
1465+
gasPrice <- use (tx . gasprice)
1466+
gasLimit <- use (tx . txgaslimit)
1467+
gasRemaining <- use (state . gas)
1468+
1469+
let
1470+
gasUsed = gasLimit - gasRemaining
1471+
cappedRefund = min (quot gasUsed 2) sumRefunds
1472+
originPay = (gasRemaining + cappedRefund) * gasPrice
1473+
minerPay = gasPrice * (gasUsed - cappedRefund)
1474+
1475+
modifying (env . contracts)
1476+
(Map.adjust (over balance (+ originPay)) txOrigin)
1477+
modifying (env . contracts)
1478+
(Map.adjust (over balance (+ minerPay)) miner)
1479+
touchAccount miner
1480+
1481+
-- pay out the block reward, recreating the miner if necessary
1482+
preuse (env . contracts . ix miner) >>= \case
1483+
Nothing -> modifying (env . contracts)
1484+
(Map.insert miner (initialContract (EVM.RuntimeCode mempty)))
1485+
Just _ -> noop
1486+
modifying (env . contracts)
1487+
(Map.adjust (over balance (+ blockReward)) miner)
14951488

14961489
-- perform state trie clearing (EIP 161), of selfdestructs
14971490
-- and touched accounts. addresses are cleared if they have
@@ -1653,12 +1646,7 @@ delegateCall this xGas xTo xValue xInOffset xInSize xOutOffset xOutSize xs conti
16531646
assign (state . returndata) mempty
16541647
pushTrace $ ErrorTrace CallDepthLimitReached
16551648
next
1656-
else case view execMode vm0 of
1657-
ExecuteAsVMTest -> do
1658-
assign (state . stack) (1 : xs)
1659-
next
1660-
_ ->
1661-
fetchAccount xTo . const $
1649+
else fetchAccount xTo . const $
16621650
preuse (env . contracts . ix xTo) >>= \case
16631651
Nothing ->
16641652
vmError (NoSuchContract xTo)
@@ -1734,11 +1722,7 @@ create self this xGas xValue xs newAddr initCode = do
17341722
modifying (env . contracts . ix self . nonce) succ
17351723
next
17361724
else burn xGas $
1737-
case (view execMode vm0) of
1738-
ExecuteAsVMTest -> do
1739-
assign (state . stack) (num newAddr : xs)
1740-
next
1741-
_ -> do
1725+
do
17421726
touchAccount self
17431727
touchAccount newAddr
17441728
let
@@ -1842,11 +1826,7 @@ finishFrame how = do
18421826
FrameReturned output -> VMSuccess output
18431827
FrameReverted output -> VMFailure (Revert output)
18441828
FrameErrored e -> VMFailure e
1845-
use execMode >>= \case
1846-
ExecuteNormally ->
1847-
noop
1848-
_ ->
1849-
finalize
1829+
finalize
18501830

18511831
-- Are there some remaining frames?
18521832
nextFrame : remainingFrames -> do

src/hevm/src/EVM/Dev.hs

+2-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import EVM.Dapp
66
import EVM.Solidity
77
import EVM.UnitTest
88

9-
import qualified EVM
109
import qualified EVM.Fetch
1110
import qualified EVM.TTY
1211
import qualified EVM.Emacs
@@ -63,12 +62,12 @@ ghciTest root path state =
6362

6463
runBCTest :: (String, VMTest.Case) -> IO Bool
6564
runBCTest (name, x) = do
66-
let vm0 = VMTest.vmForCase EVM.ExecuteAsBlockchainTest x
65+
let vm0 = VMTest.vmForCase x
6766
putStr (name ++ " ")
6867
result <-
6968
evaluate $
7069
execState (VMTest.interpret EVM.Stepper.execFully) vm0
71-
ok <- VMTest.checkExpectation False EVM.ExecuteAsBlockchainTest x result
70+
ok <- VMTest.checkExpectation False x result
7271
putStrLn (if ok then "ok" else "")
7372
return ok
7473

src/hevm/src/EVM/VMTest.hs

+10-46
Original file line numberDiff line numberDiff line change
@@ -147,10 +147,10 @@ checkStateFail diff x expectation vm (okState, okMoney, okNonce, okData, okCode)
147147
++ (show . Map.toList $ EVM._storage v)) actual
148148
return okState
149149

150-
checkExpectation :: Bool -> EVM.ExecMode -> Case -> EVM.VM -> IO Bool
151-
checkExpectation diff execmode x vm =
152-
case (execmode, testExpectation x, view EVM.result vm) of
153-
(EVM.ExecuteAsBlockchainTest, Just expectation, _) -> do
150+
checkExpectation :: Bool -> Case -> EVM.VM -> IO Bool
151+
checkExpectation diff x vm =
152+
case (testExpectation x, view EVM.result vm) of
153+
(Just expectation, _) -> do
154154
let (okState, b2, b3, b4, b5) =
155155
checkExpectedContracts vm (expectedContracts expectation)
156156
_ <- if not okState then
@@ -159,41 +159,17 @@ checkExpectation diff execmode x vm =
159159
else return True
160160
return okState
161161

162-
(_, Just expectation, Just (EVM.VMSuccess output)) -> do
163-
let
164-
(okState, ok2, ok3, ok4, ok5) =
165-
checkExpectedContracts vm (expectedContracts expectation)
166-
(s2, b2) = ("bad-output", checkExpectedOut output (expectedOut expectation))
167-
(s3, b3) = ("bad-gas", checkExpectedGas vm (expectedGas expectation))
168-
ss = map fst (filter (not . snd) [(s2, b2), (s3, b3)])
169-
_ <- if not okState then
170-
checkStateFail
171-
diff x expectation vm (okState, ok2, ok3, ok4, ok5)
172-
else
173-
return True
174-
putStr (unwords ss)
175-
return (okState && b2 && b3)
176-
177-
(_, Nothing, Just (EVM.VMSuccess _)) -> do
162+
(Nothing, Just (EVM.VMSuccess _)) -> do
178163
putStr "unexpected-success"
179164
return False
180165

181-
(_, Nothing, Just (EVM.VMFailure _)) ->
166+
(Nothing, Just (EVM.VMFailure _)) ->
182167
return True
183168

184-
(_, Just _, Just (EVM.VMFailure _)) -> do
185-
putStr "unexpected-failure"
186-
return False
187-
188-
(_, _, Nothing) -> do
169+
(_, Nothing) -> do
189170
cpprint (view EVM.result vm)
190171
error "internal error"
191172

192-
checkExpectedOut :: ByteString -> Maybe ByteString -> Bool
193-
checkExpectedOut output ex = case ex of
194-
Nothing -> True
195-
Just expected -> output == expected
196-
197173
-- quotient account state by nullness
198174
(~=) :: Map Addr EVM.Contract -> Map Addr EVM.Contract -> Bool
199175
(~=) cs cs' =
@@ -230,13 +206,6 @@ clearNonce = set EVM.nonce 0
230206
clearCode :: EVM.Contract -> EVM.Contract
231207
clearCode = set EVM.contractcode (EVM.RuntimeCode mempty)
232208

233-
checkExpectedGas :: EVM.VM -> Maybe W256 -> Bool
234-
checkExpectedGas vm ex = case ex of
235-
Nothing -> True
236-
Just expected -> case vm ^. EVM.state . EVM.gas of
237-
EVM.C _ x | x == expected -> True
238-
_ -> False
239-
240209
#if MIN_VERSION_aeson(1, 0, 0)
241210

242211
instance FromJSON Contract where
@@ -528,15 +497,11 @@ initTx x =
528497
else id)
529498
$ checkState
530499

531-
vmForCase :: EVM.ExecMode -> Case -> EVM.VM
532-
vmForCase mode x =
500+
vmForCase :: Case -> EVM.VM
501+
vmForCase x =
533502
let
534503
checkState = checkContracts x
535-
initState =
536-
case mode of
537-
EVM.ExecuteAsBlockchainTest -> initTx x
538-
EVM.ExecuteAsVMTest -> checkState
539-
EVM.ExecuteNormally -> error "cannot initialize VM normally"
504+
initState = initTx x
540505
opts = testVmOpts x
541506
creation = EVM.vmoptCreate opts
542507
touchedAccounts =
@@ -550,7 +515,6 @@ vmForCase mode x =
550515
& EVM.tx . EVM.txReversion .~ realizeContracts checkState
551516
& EVM.tx . EVM.origStorage .~ realizeContracts initState
552517
& EVM.tx . EVM.substate . EVM.touchedAccounts .~ touchedAccounts
553-
& EVM.execMode .~ mode
554518

555519
interpret :: Stepper a -> EVM a
556520
interpret =

0 commit comments

Comments
 (0)