|
12 | 12 |
|
13 | 13 | module Main where
|
14 | 14 |
|
15 |
| -import EVM (StorageModel(..)) |
| 15 | +import EVM (StorageModel(..), CalldataModel(..)) |
16 | 16 | import qualified EVM
|
17 | 17 | import EVM.Concrete (createAddress, w256)
|
18 |
| -import EVM.Symbolic (forceLitBytes, litBytes, litAddr, w256lit, sw256, SymWord(..), Buffer(..), len) |
| 18 | +import EVM.Symbolic (forceLitBytes, litBytes, litAddr, w256lit, sw256, SymWord(..), Buffer(..), len, Calldata(..)) |
19 | 19 | import qualified EVM.FeeSchedule as FeeSchedule
|
20 | 20 | import qualified EVM.Fetch
|
21 | 21 | import qualified EVM.Flatten
|
@@ -57,6 +57,7 @@ import Data.Text.IO (hPutStr)
|
57 | 57 | import Data.Maybe (fromMaybe, fromJust)
|
58 | 58 | import Data.Version (showVersion)
|
59 | 59 | import Data.SBV hiding (Word, solver, verbose, name)
|
| 60 | +import qualified Data.SBV.List as SList |
60 | 61 | import qualified Data.SBV as SBV
|
61 | 62 | import Data.SBV.Control hiding (Version, timeout, create)
|
62 | 63 | import System.IO (hFlush, hPrint, stdout, stderr)
|
@@ -110,17 +111,18 @@ data Command w
|
110 | 111 | , block :: w ::: Maybe W256 <?> "Block state is be fetched from"
|
111 | 112 |
|
112 | 113 | -- symbolic execution opts
|
113 |
| - , jsonFile :: w ::: Maybe String <?> "Filename or path to dapp build output (default: out/*.solc.json)" |
114 |
| - , dappRoot :: w ::: Maybe String <?> "Path to dapp project root directory (default: . )" |
115 |
| - , storageModel :: w ::: Maybe StorageModel <?> "Select storage model: ConcreteS, SymbolicS (default) or InitialS" |
116 |
| - , sig :: w ::: Maybe Text <?> "Signature of types to decode / encode" |
117 |
| - , arg :: w ::: [String] <?> "Values to encode" |
118 |
| - , debug :: w ::: Bool <?> "Run interactively" |
119 |
| - , getModels :: w ::: Bool <?> "Print example testcase for each execution path" |
120 |
| - , smttimeout :: w ::: Maybe Integer <?> "Timeout given to SMT solver in milliseconds (default: 20000)" |
121 |
| - , maxIterations :: w ::: Maybe Integer <?> "Number of times we may revisit a particular branching point" |
122 |
| - , solver :: w ::: Maybe Text <?> "Used SMT solver: z3 (default) or cvc4" |
123 |
| - , smtoutput :: w ::: Bool <?> "Print verbose smt output" |
| 114 | + , jsonFile :: w ::: Maybe String <?> "Filename or path to dapp build output (default: out/*.solc.json)" |
| 115 | + , dappRoot :: w ::: Maybe String <?> "Path to dapp project root directory (default: . )" |
| 116 | + , storageModel :: w ::: Maybe StorageModel <?> "Select storage model: ConcreteS, SymbolicS (default) or InitialS" |
| 117 | + , calldataModel :: w ::: Maybe CalldataModel <?> "Select calldata model: BoundedCD (default), or DynamicCD" |
| 118 | + , sig :: w ::: Maybe Text <?> "Signature of types to decode / encode" |
| 119 | + , arg :: w ::: [String] <?> "Values to encode" |
| 120 | + , debug :: w ::: Bool <?> "Run interactively" |
| 121 | + , getModels :: w ::: Bool <?> "Print example testcase for each execution path" |
| 122 | + , smttimeout :: w ::: Maybe Integer <?> "Timeout given to SMT solver in milliseconds (default: 20000)" |
| 123 | + , maxIterations :: w ::: Maybe Integer <?> "Number of times we may revisit a particular branching point" |
| 124 | + , solver :: w ::: Maybe Text <?> "Used SMT solver: z3 (default) or cvc4" |
| 125 | + , smtoutput :: w ::: Bool <?> "Print verbose smt output" |
124 | 126 | }
|
125 | 127 | | Equivalence -- prove equivalence between two programs
|
126 | 128 | { codeA :: w ::: ByteString <?> "Bytecode of the first program"
|
@@ -681,7 +683,7 @@ vmFromCommand cmd = do
|
681 | 683 | value' = word value 0
|
682 | 684 | caller' = addr caller 0
|
683 | 685 | origin' = addr origin 0
|
684 |
| - calldata' = ConcreteBuffer $ bytes calldata "" |
| 686 | + calldata' = CalldataBuffer $ ConcreteBuffer $ bytes calldata "" |
685 | 687 | codeType = if create cmd then EVM.InitCode else EVM.RuntimeCode
|
686 | 688 | address' = if create cmd
|
687 | 689 | then createAddress origin' (word nonce 0)
|
@@ -716,18 +718,29 @@ symvmFromCommand :: Command Options.Unwrapped -> Query EVM.VM
|
716 | 718 | symvmFromCommand cmd = do
|
717 | 719 | caller' <- maybe (SAddr <$> freshVar_) (return . litAddr) (caller cmd)
|
718 | 720 | callvalue' <- maybe (sw256 <$> freshVar_) (return . w256lit) (value cmd)
|
719 |
| - calldata' <- case (calldata cmd, sig cmd) of |
720 |
| - -- static calldata (up to 256 bytes) |
721 |
| - (Nothing, Nothing) -> do |
722 |
| - StaticSymBuffer <$> sbytes256 |
| 721 | + (calldata', preCond) <- case (calldata cmd, sig cmd, calldataModel cmd) of |
| 722 | + -- dynamic calldata via smt lists |
| 723 | + (Nothing, Nothing, Just DynamicCD) -> do |
| 724 | + cd <- freshVar_ |
| 725 | + return (CalldataBuffer (DynamicSymBuffer cd), |
| 726 | + SList.length cd .< 1000 .&& |
| 727 | + sw256 (sFromIntegral (SList.length cd)) .< sw256 1000) |
| 728 | + |
| 729 | + -- dynamic calldata via (bounded) haskell list |
| 730 | + (Nothing, Nothing, _) -> do |
| 731 | + cd <- sbytes256 |
| 732 | + len <- freshVar_ |
| 733 | + return (CalldataDynamic (cd, len), len .<= 256) |
| 734 | + |
723 | 735 | -- fully concrete calldata
|
724 |
| - (Just c, Nothing) -> |
725 |
| - return $ ConcreteBuffer $ decipher c |
| 736 | + (Just c, Nothing, _) -> |
| 737 | + return (CalldataBuffer (ConcreteBuffer $ decipher c), sTrue) |
726 | 738 | -- calldata according to given abi with possible specializations from the `arg` list
|
727 |
| - (Nothing, Just sig') -> do |
| 739 | + (Nothing, Just sig', _) -> do |
728 | 740 | method' <- io $ functionAbi sig'
|
729 | 741 | let typs = snd <$> view methodInputs method'
|
730 |
| - StaticSymBuffer <$> staticCalldata (view methodSignature method') typs (arg cmd) |
| 742 | + cd <- staticCalldata (view methodSignature method') typs (arg cmd) |
| 743 | + return (CalldataBuffer (StaticSymBuffer cd), sTrue) |
731 | 744 |
|
732 | 745 | _ -> error "incompatible options: calldata and abi"
|
733 | 746 |
|
@@ -773,7 +786,7 @@ symvmFromCommand cmd = do
|
773 | 786 | (_, _, Nothing) ->
|
774 | 787 | error $ "must provide at least (rpc + address) or code"
|
775 | 788 |
|
776 |
| - return vm |
| 789 | + return $ vm & over EVM.pathConditions (<> [preCond]) |
777 | 790 |
|
778 | 791 | where
|
779 | 792 | decipher = hexByteString "bytes" . strip0x
|
|
0 commit comments