Skip to content

Commit 6c2869b

Browse files
authored
Merge pull request #692 from ethereum/symbolic-block-number
Symbolic block number is now allowed in library mode
2 parents ddb822d + b71eb63 commit 6c2869b

File tree

13 files changed

+68
-31
lines changed

13 files changed

+68
-31
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8585
- Add `--arrays-exp` to cvc5 options.
8686
- We now use Options.Applicative and a rather different way of parsing CLI options.
8787
This should give us much better control over the CLI options and their parsing.
88+
- block.number can now be symbolic. This only affects library use of hevm
8889
- Removed `--smtoutput` since it was never used
8990
- We now build with -DCMAKE_POLICY_VERSION_MINIMUM=3.5 libff, as cmake deprecated 3.5
9091

cli/cli.hs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ launchExec cFileOpts execOpts cExecOpts cOpts = do
576576
vmFromCommand :: CommonOptions -> CommonExecOptions -> CommonFileOptions -> ExecOptions -> IO (VM Concrete RealWorld)
577577
vmFromCommand cOpts cExecOpts cFileOpts execOpts= do
578578
(miner,ts,baseFee,blockNum,prevRan) <- case cExecOpts.rpc of
579-
Nothing -> pure (LitAddr 0,Lit 0,0,0,0)
579+
Nothing -> pure (LitAddr 0,Lit 0,0,Lit 0,0)
580580
Just url -> Fetch.fetchBlockFrom block url >>= \case
581581
Nothing -> do
582582
putStrLn $ "Error, Could not fetch block" <> show block <> " from URL: " <> show url
@@ -665,7 +665,7 @@ vmFromCommand cOpts cExecOpts cFileOpts execOpts= do
665665
, priorityFee = word (.priorityFee) 0
666666
, gaslimit = word64 (.gaslimit) 0xffffffffffffffff
667667
, coinbase = addr (.coinbase) miner
668-
, number = word (.number) blockNum
668+
, number = maybe blockNum Lit cExecOpts.number
669669
, timestamp = Lit $ word (.timestamp) ts
670670
, blockGaslimit = word64 (.gaslimit) 0xffffffffffffffff
671671
, gasprice = word (.gasprice) 0
@@ -688,7 +688,7 @@ vmFromCommand cOpts cExecOpts cFileOpts execOpts= do
688688
symvmFromCommand :: CommonExecOptions -> SymbolicOptions -> CommonFileOptions -> (Expr Buf, [Prop]) -> IO (VM EVM.Types.Symbolic RealWorld)
689689
symvmFromCommand cExecOpts sOpts cFileOpts calldata = do
690690
(miner,blockNum,baseFee,prevRan) <- case cExecOpts.rpc of
691-
Nothing -> pure (SymAddr "miner",0,0,0)
691+
Nothing -> pure (SymAddr "miner",Lit 0,0,0)
692692
Just url -> Fetch.fetchBlockFrom block url >>= \case
693693
Nothing -> do
694694
putStrLn $ "Error, Could not fetch block" <> show block <> " from URL: " <> show url
@@ -765,7 +765,7 @@ symvmFromCommand cExecOpts sOpts cFileOpts calldata = do
765765
, baseFee = baseFee
766766
, priorityFee = word (.priorityFee) 0
767767
, coinbase = eaddr (.coinbase) miner
768-
, number = word (.number) blockNum
768+
, number = maybe blockNum Lit cExecOpts.number
769769
, timestamp = ts
770770
, blockGaslimit = word64 (.gaslimit) 0xffffffffffffffff
771771
, gasprice = word (.gasprice) 0

doc/src/limitations-and-workarounds.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,13 @@ WARNING: hevm was only able to partially explore the call prefix 0x[...] due to
105105
106106
For these cases, we suggest concretizing the call that creates the contract,
107107
such that the bytecode created and later jumped to, is not symbolic.
108+
109+
## Setting block number
110+
111+
The [roll(uint256)
112+
cheatcode](https://book.getfoundry.sh/cheatcodes/roll?highlight=roll#roll) can
113+
be used to set the block number in the current EVM state. However, it does not
114+
alter the block number that the RPC calls use. For that, one must use the
115+
`--number` command line option. Hence, it is not possible to dynamically change
116+
what block number the RPC calls fetch from, other than by restarting the hevm
117+
process with a different block number.

src/EVM.hs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -581,13 +581,21 @@ exec1 conf = do
581581
underrun
582582

583583
OpBlockhash -> do
584-
-- We adopt the fake block hash scheme of the VMTests,
585-
-- so that blockhash(i) is the hash of i as decimal ASCII.
586584
stackOp1 g_blockhash $ \case
587-
Lit i -> if i + 256 < vm.block.number || i >= vm.block.number
588-
then Lit 0
589-
else (into i :: Integer) & show & Char8.pack & keccak' & Lit
585+
Lit i -> case vm.block.number of
586+
Lit vmBlockNumber ->
587+
if i + 256 < vmBlockNumber || i >= vmBlockNumber
588+
-- blockhash is 0 if block is too old or too new as per EVM spec
589+
then Lit 0
590+
-- We adopt the fake block hash scheme of the VMTests,
591+
-- so that blockhash(i) is the hash of i as decimal ASCII.
592+
else fakeBlockHash i
593+
-- For symbolic block numbers, we don't know if it's too old or too new,
594+
-- so we return fake block hash
595+
_ -> fakeBlockHash i
590596
i -> BlockHash i
597+
where
598+
fakeBlockHash i = (into i :: Integer) & show & Char8.pack & keccak' & Lit
591599

592600
OpCoinbase ->
593601
limitStack 1 . burn g_base $
@@ -599,7 +607,7 @@ exec1 conf = do
599607

600608
OpNumber ->
601609
limitStack 1 . burn g_base $
602-
next >> push vm.block.number
610+
next >> pushSym vm.block.number
603611

604612
OpPrevRandao -> do
605613
limitStack 1 . burn g_base $
@@ -1802,8 +1810,8 @@ cheatActions = Map.fromList
18021810

18031811
, action "roll(uint256)" $
18041812
\sig input -> case decodeStaticArgs 0 1 input of
1805-
[x] -> forceConcrete x "cannot roll to a symbolic block number" $ \block -> do
1806-
assign (#block % #number) block
1813+
[x] -> do
1814+
assign (#block % #number) x
18071815
doStop
18081816
_ -> vmError (BadCheatCode "roll(uint256) parameter decoding failed" sig)
18091817

src/EVM/Exec.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ vmForEthrunCreation creationCode =
2727
, caller = LitAddr ethrunAddress
2828
, origin = LitAddr ethrunAddress
2929
, coinbase = LitAddr 0
30-
, number = 0
30+
, number = Lit 0
3131
, timestamp = Lit 0
3232
, blockGaslimit = 0
3333
, gasprice = 0

src/EVM/Fetch.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ parseBlock :: (AsValue s, Show s) => s -> Maybe Block
115115
parseBlock j = do
116116
coinbase <- LitAddr . readText <$> j ^? key "miner" % _String
117117
timestamp <- Lit . readText <$> j ^? key "timestamp" % _String
118-
number <- readText <$> j ^? key "number" % _String
118+
number <- Lit . readText <$> j ^? key "number" % _String
119119
gasLimit <- readText <$> j ^? key "gasLimit" % _String
120120
let
121121
baseFee = readText <$> j ^? key "baseFeePerGas" % _String

src/EVM/SymExec.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ loadSymVM x callvalue cd create =
257257
, caller = SymAddr "caller"
258258
, origin = SymAddr "origin"
259259
, coinbase = SymAddr "coinbase"
260-
, number = 0
260+
, number = Lit 0
261261
, timestamp = Lit 0
262262
, blockGaslimit = 0
263263
, gasprice = 0

src/EVM/Types.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,7 @@ data Env = Env
826826
data Block = Block
827827
{ coinbase :: Expr EAddr
828828
, timestamp :: Expr EWord
829-
, number :: W256
829+
, number :: Expr EWord
830830
, prevRandao :: W256
831831
, gaslimit :: Word64
832832
, baseFee :: W256
@@ -1004,7 +1004,7 @@ data VMOpts (t :: VMType) = VMOpts
10041004
, origin :: Expr EAddr
10051005
, gas :: Gas t
10061006
, gaslimit :: Word64
1007-
, number :: W256
1007+
, number :: Expr EWord
10081008
, timestamp :: Expr EWord
10091009
, coinbase :: Expr EAddr
10101010
, prevRandao :: W256

src/EVM/UnitTest.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ initialUnitTestVm (UnitTestOptions {..}) theContract = do
418418
, gas = toGas testParams.gasCreate
419419
, gaslimit = testParams.gasCreate
420420
, coinbase = testParams.coinbase
421-
, number = testParams.number
421+
, number = Lit testParams.number
422422
, timestamp = Lit testParams.timestamp
423423
, blockGaslimit = testParams.gaslimit
424424
, gasprice = testParams.gasprice
@@ -444,7 +444,7 @@ initialUnitTestVm (UnitTestOptions {..}) theContract = do
444444
paramsFromRpc :: Fetch.RpcInfo -> IO TestVMParams
445445
paramsFromRpc rpcinfo = do
446446
(miner,ts,blockNum,ran,limit,base) <- case rpcinfo of
447-
Nothing -> pure (SymAddr "miner", Lit 0, 0, 0, 0, 0)
447+
Nothing -> pure (SymAddr "miner", Lit 0, Lit 0, 0, 0, 0)
448448
Just (block, url) -> Fetch.fetchBlockFrom block url >>= \case
449449
Nothing -> internalError "Could not fetch block"
450450
Just Block{..} -> pure ( coinbase
@@ -467,7 +467,7 @@ paramsFromRpc rpcinfo = do
467467
, priorityFee = 0
468468
, balanceCreate = defaultBalanceForTestContract
469469
, coinbase = miner
470-
, number = blockNum
470+
, number = forceLit blockNum
471471
, timestamp = ts'
472472
, gaslimit = limit
473473
, gasprice = 0

test/EVM/Test/BlockchainTests.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ fromBlockchainCase' block tx preState postState =
444444
, baseFee = block.baseFee
445445
, priorityFee = priorityFee tx block.baseFee
446446
, gaslimit = tx.gasLimit
447-
, number = block.number
447+
, number = Lit block.number
448448
, timestamp = Lit block.timestamp
449449
, coinbase = LitAddr block.coinbase
450450
, prevRandao = block.mixHash

0 commit comments

Comments
 (0)