Skip to content

Commit b239196

Browse files
committed
the purge compiles...
1 parent 92b0dfc commit b239196

19 files changed

+341
-596
lines changed

cli/cli.hs

Lines changed: 112 additions & 222 deletions
Large diffs are not rendered by default.

hie.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ cradle:
44
component: "lib:hevm"
55
- path: "./bench"
66
component: "bench"
7-
- path: "./hevm-cli"
7+
- path: "./cli"
88
component: "exe:hevm"
99
- path: "./test/test.hs"
1010
component: "test:test"

src/EVM/ABI.hs

Lines changed: 96 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ module EVM.ABI
3737
, SolError (..)
3838
, Anonymity (..)
3939
, Indexed (..)
40+
, Sig(..)
4041
, putAbi
4142
, getAbi
4243
, getAbiSeq
@@ -82,13 +83,17 @@ import Data.Vector (Vector, toList)
8283
import Data.Vector qualified as Vector
8384
import Data.Word (Word32)
8485
import GHC.Generics (Generic)
85-
8686
import Test.QuickCheck hiding ((.&.), label)
87+
8788
import Text.Megaparsec qualified as P
8889
import Text.Megaparsec.Char qualified as P
8990
import Text.ParserCombinators.ReadP
9091
import Witch (unsafeInto, into)
9192

93+
-- | A method name, and the (ordered) types of it's arguments
94+
data Sig = Sig Text [AbiType]
95+
deriving (Show, Eq)
96+
9297
data AbiValue
9398
= AbiUInt Int Word256
9499
| AbiInt Int Int256
@@ -410,80 +415,6 @@ getBytesWith256BitPadding i =
410415
<* skip ((roundTo32Bytes n) - n)
411416
where n = fromIntegral i
412417

413-
-- QuickCheck instances
414-
415-
genAbiValue :: AbiType -> Gen AbiValue
416-
genAbiValue = \case
417-
AbiUIntType n -> AbiUInt n <$> genUInt n
418-
AbiIntType n -> do
419-
x <- genUInt n
420-
pure $ AbiInt n (signedWord (x - 2^(n-1)))
421-
AbiAddressType ->
422-
AbiAddress . fromIntegral <$> genUInt 20
423-
AbiBoolType ->
424-
elements [AbiBool False, AbiBool True]
425-
AbiBytesType n ->
426-
do xs <- replicateM n arbitrary
427-
pure (AbiBytes n (BS.pack xs))
428-
AbiBytesDynamicType ->
429-
AbiBytesDynamic . BS.pack <$> listOf arbitrary
430-
AbiStringType ->
431-
AbiString . BS.pack <$> listOf arbitrary
432-
AbiArrayDynamicType t ->
433-
do xs <- listOf1 (scale (`div` 2) (genAbiValue t))
434-
pure (AbiArrayDynamic t (Vector.fromList xs))
435-
AbiArrayType n t ->
436-
AbiArray n t . Vector.fromList <$>
437-
replicateM n (scale (`div` 2) (genAbiValue t))
438-
AbiTupleType ts ->
439-
AbiTuple <$> mapM genAbiValue ts
440-
AbiFunctionType ->
441-
do xs <- replicateM 24 arbitrary
442-
pure (AbiFunction (BS.pack xs))
443-
where
444-
genUInt :: Int -> Gen Word256
445-
genUInt n = arbitraryIntegralWithMax (2^n-1) :: Gen Word256
446-
447-
instance Arbitrary AbiType where
448-
arbitrary = oneof
449-
[ (AbiUIntType . (* 8)) <$> choose (1, 32)
450-
, (AbiIntType . (* 8)) <$> choose (1, 32)
451-
, pure AbiAddressType
452-
, pure AbiBoolType
453-
, AbiBytesType <$> choose (1,32)
454-
, pure AbiBytesDynamicType
455-
, pure AbiStringType
456-
, AbiArrayDynamicType <$> scale (`div` 2) arbitrary
457-
, AbiArrayType
458-
<$> (getPositive <$> arbitrary)
459-
<*> scale (`div` 2) arbitrary
460-
]
461-
462-
instance Arbitrary AbiValue where
463-
arbitrary = arbitrary >>= genAbiValue
464-
shrink = \case
465-
AbiArrayDynamic t v ->
466-
Vector.toList v ++
467-
map (AbiArrayDynamic t . Vector.fromList)
468-
(shrinkList shrink (Vector.toList v))
469-
AbiBytesDynamic b -> AbiBytesDynamic . BS.pack <$> shrinkList shrinkIntegral (BS.unpack b)
470-
AbiString b -> AbiString . BS.pack <$> shrinkList shrinkIntegral (BS.unpack b)
471-
AbiBytes n a | n <= 32 -> shrink $ AbiUInt (n * 8) (word256 a)
472-
--bytesN for N > 32 don't really exist right now anyway..
473-
AbiBytes _ _ | otherwise -> []
474-
AbiArray _ t v ->
475-
Vector.toList v ++
476-
map (\x -> AbiArray (length x) t (Vector.fromList x))
477-
(shrinkList shrink (Vector.toList v))
478-
AbiTuple v -> Vector.toList $ AbiTuple . Vector.fromList . shrink <$> v
479-
AbiUInt n a -> AbiUInt n <$> (shrinkIntegral a)
480-
AbiInt n a -> AbiInt n <$> (shrinkIntegral a)
481-
AbiBool b -> AbiBool <$> shrink b
482-
AbiAddress a -> [AbiAddress 0xacab, AbiAddress 0xdeadbeef, AbiAddress 0xbabeface]
483-
<> (AbiAddress <$> shrinkIntegral a)
484-
AbiFunction b -> shrink $ AbiBytes 24 b
485-
486-
487418
-- Bool synonym with custom read instance
488419
-- to be able to parse lower case 'false' and 'true'
489420
newtype Boolz = Boolz Bool
@@ -572,3 +503,93 @@ decodeBuf tps buf
572503
decodeStaticArgs :: Int -> Int -> Expr Buf -> [Expr EWord]
573504
decodeStaticArgs offset numArgs b =
574505
[readWord (Lit . unsafeInto $ i) b | i <- [offset,(offset+32) .. (offset + (numArgs-1)*32)]]
506+
507+
-- QuickCheck instances
508+
509+
genAbiValue :: AbiType -> Gen AbiValue
510+
genAbiValue = \case
511+
AbiUIntType n -> AbiUInt n <$> genUInt n
512+
AbiIntType n -> do
513+
x <- genUInt n
514+
pure $ AbiInt n (signedWord (x - 2^(n-1)))
515+
AbiAddressType ->
516+
AbiAddress . fromIntegral <$> genUInt 20
517+
AbiBoolType ->
518+
elements [AbiBool False, AbiBool True]
519+
AbiBytesType n ->
520+
do xs <- replicateM n arbitrary
521+
pure (AbiBytes n (BS.pack xs))
522+
AbiBytesDynamicType ->
523+
AbiBytesDynamic . BS.pack <$> listOf arbitrary
524+
AbiStringType ->
525+
AbiString . BS.pack <$> listOf arbitrary
526+
AbiArrayDynamicType t ->
527+
do xs <- listOf1 (scale (`div` 2) (genAbiValue t))
528+
pure (AbiArrayDynamic t (Vector.fromList xs))
529+
AbiArrayType n t ->
530+
AbiArray n t . Vector.fromList <$>
531+
replicateM n (scale (`div` 2) (genAbiValue t))
532+
AbiTupleType ts ->
533+
AbiTuple <$> mapM genAbiValue ts
534+
AbiFunctionType ->
535+
do xs <- replicateM 24 arbitrary
536+
pure (AbiFunction (BS.pack xs))
537+
where
538+
genUInt :: Int -> Gen Word256
539+
genUInt n = arbitraryIntegralWithMax (2^n-1) :: Gen Word256
540+
541+
instance Arbitrary AbiType where
542+
arbitrary = oneof
543+
[ (AbiUIntType . (* 8)) <$> choose (1, 32)
544+
, (AbiIntType . (* 8)) <$> choose (1, 32)
545+
, pure AbiAddressType
546+
, pure AbiBoolType
547+
, AbiBytesType <$> choose (1,32)
548+
, pure AbiBytesDynamicType
549+
, pure AbiStringType
550+
, AbiArrayDynamicType <$> scale (`div` 2) arbitrary
551+
, AbiArrayType
552+
<$> (getPositive <$> arbitrary)
553+
<*> scale (`div` 2) arbitrary
554+
]
555+
556+
instance Arbitrary AbiValue where
557+
arbitrary = arbitrary >>= genAbiValue
558+
shrink = \case
559+
AbiArrayDynamic t v ->
560+
Vector.toList v ++
561+
map (AbiArrayDynamic t . Vector.fromList)
562+
(shrinkList shrink (Vector.toList v))
563+
AbiBytesDynamic b -> AbiBytesDynamic . BS.pack <$> shrinkList shrinkIntegral (BS.unpack b)
564+
AbiString b -> AbiString . BS.pack <$> shrinkList shrinkIntegral (BS.unpack b)
565+
AbiBytes n a | n <= 32 -> shrink $ AbiUInt (n * 8) (word256 a)
566+
--bytesN for N > 32 don't really exist right now anyway..
567+
AbiBytes _ _ | otherwise -> []
568+
AbiArray _ t v ->
569+
Vector.toList v ++
570+
map (\x -> AbiArray (length x) t (Vector.fromList x))
571+
(shrinkList shrink (Vector.toList v))
572+
AbiTuple v -> Vector.toList $ AbiTuple . Vector.fromList . shrink <$> v
573+
AbiUInt n a -> AbiUInt n <$> (shrinkIntegral a)
574+
AbiInt n a -> AbiInt n <$> (shrinkIntegral a)
575+
AbiBool b -> AbiBool <$> shrink b
576+
AbiAddress a -> [AbiAddress 0xacab, AbiAddress 0xdeadbeef, AbiAddress 0xbabeface]
577+
<> (AbiAddress <$> shrinkIntegral a)
578+
AbiFunction b -> shrink $ AbiBytes 24 b
579+
580+
-- A modification of 'arbitrarySizedBoundedIntegral' quickcheck library
581+
-- which takes the maxbound explicitly rather than relying on a Bounded instance.
582+
-- Essentially a mix between three types of generators:
583+
-- one that strongly prefers values close to 0, one that prefers values close to max
584+
-- and one that chooses uniformly.
585+
arbitraryIntegralWithMax :: (Integral a) => Integer -> Gen a
586+
arbitraryIntegralWithMax maxbound =
587+
sized $ \s ->
588+
do let mn = 0 :: Int
589+
mx = maxbound
590+
bits n | n `quot` 2 == 0 = 0
591+
| otherwise = 1 + bits (n `quot` 2)
592+
k = 2^(s*(bits mn `max` bits mx `max` 40) `div` 100)
593+
smol <- choose (toInteger mn `max` (-k), toInteger mx `min` k)
594+
mid <- choose (0, maxbound)
595+
elements [fromIntegral smol, fromIntegral mid, fromIntegral (maxbound - (fromIntegral smol))]

src/EVM/Dapp.hs

Lines changed: 20 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ import EVM.Types
77

88
import Control.Arrow ((>>>))
99
import Data.Aeson (Value)
10-
import Data.Bifunctor (first, second)
10+
import Data.Bifunctor (second)
1111
import Data.ByteString (ByteString)
1212
import Data.ByteString qualified as BS
1313
import Data.List (find, sort)
1414
import Data.Map (Map)
1515
import Data.Map qualified as Map
16-
import Data.Maybe (isJust, fromJust, mapMaybe)
16+
import Data.Maybe (mapMaybe)
1717
import Data.Sequence qualified as Seq
18-
import Data.Text (Text, isPrefixOf, pack, unpack)
18+
import Data.Text (Text, isPrefixOf, pack)
1919
import Data.Text.Encoding (encodeUtf8)
2020
import Data.Vector qualified as V
2121
import Optics.Core
@@ -27,7 +27,7 @@ data DappInfo = DappInfo
2727
, solcByHash :: Map W256 (CodeType, SolcContract)
2828
, solcByCode :: [(Code, SolcContract)] -- for contracts with `immutable` vars.
2929
, sources :: SourceCache
30-
, unitTests :: [(Text, [(Test, [AbiType])])]
30+
, unitTests :: [(Text, [Sig])]
3131
, abiMap :: Map FunctionSelector Method
3232
, eventMap :: Map W256 Event
3333
, errorMap :: Map W256 SolError
@@ -47,11 +47,6 @@ data DappContext = DappContext
4747
, env :: Map Addr Contract
4848
}
4949

50-
data Test = ConcreteTest Text | SymbolicTest Text | InvariantTest Text
51-
52-
instance Show Test where
53-
show t = unpack $ extractSig t
54-
5550
dappInfo :: FilePath -> BuildOutput -> DappInfo
5651
dappInfo root (BuildOutput (Contracts cs) sources) =
5752
let
@@ -87,29 +82,28 @@ emptyDapp :: DappInfo
8782
emptyDapp = dappInfo "" mempty
8883

8984
-- Dapp unit tests are detected by searching within abi methods
90-
-- that begin with "test" or "prove", that are in a contract with
85+
-- that begin with "check" or "prove", that are in a contract with
9186
-- the "IS_TEST()" abi marker, for a given regular expression.
9287
--
9388
-- The regex is matched on the full test method name, including path
9489
-- and contract, i.e. "path/to/file.sol:TestContract.test_name()".
95-
--
96-
-- Tests beginning with "test" are interpreted as concrete tests, whereas
97-
-- tests beginning with "prove" are interpreted as symbolic tests.
9890

9991
unitTestMarkerAbi :: FunctionSelector
10092
unitTestMarkerAbi = abiKeccak (encodeUtf8 "IS_TEST()")
10193

102-
findAllUnitTests :: [SolcContract] -> [(Text, [(Test, [AbiType])])]
103-
findAllUnitTests = findUnitTests ".*:.*\\.(test|prove|invariant).*"
94+
findAllUnitTests :: [SolcContract] -> [(Text, [Sig])]
95+
findAllUnitTests = findUnitTests ".*:.*\\.(check|prove).*"
10496

105-
mkTest :: Text -> Maybe Test
106-
mkTest sig
107-
| "test" `isPrefixOf` sig = Just (ConcreteTest sig)
108-
| "prove" `isPrefixOf` sig = Just (SymbolicTest sig)
109-
| "invariant" `isPrefixOf` sig = Just (InvariantTest sig)
97+
mkSig :: Method -> Maybe Sig
98+
mkSig method
99+
| "prove" `isPrefixOf` testname = Just (Sig testname argtypes)
100+
| "check" `isPrefixOf` testname = Just (Sig testname argtypes)
110101
| otherwise = Nothing
102+
where
103+
testname = method.methodSignature
104+
argtypes = snd <$> method.inputs
111105

112-
findUnitTests :: Text -> ([SolcContract] -> [(Text, [(Test, [AbiType])])])
106+
findUnitTests :: Text -> ([SolcContract] -> [(Text, [Sig])])
113107
findUnitTests match =
114108
concatMap $ \c ->
115109
case Map.lookup unitTestMarkerAbi c.abiMap of
@@ -118,25 +112,16 @@ findUnitTests match =
118112
let testNames = unitTestMethodsFiltered (regexMatches match) c
119113
in [(c.contractName, testNames) | not (BS.null c.runtimeCode) && not (null testNames)]
120114

121-
unitTestMethodsFiltered :: (Text -> Bool) -> (SolcContract -> [(Test, [AbiType])])
115+
unitTestMethodsFiltered :: (Text -> Bool) -> (SolcContract -> [Sig])
122116
unitTestMethodsFiltered matcher c =
123-
let
124-
testName method = c.contractName <> "." <> (extractSig (fst method))
125-
in
126-
filter (matcher . testName) (unitTestMethods c)
117+
let testName (Sig n _) = c.contractName <> "." <> n
118+
in filter (matcher . testName) (unitTestMethods c)
127119

128-
unitTestMethods :: SolcContract -> [(Test, [AbiType])]
120+
unitTestMethods :: SolcContract -> [Sig]
129121
unitTestMethods =
130122
(.abiMap)
131123
>>> Map.elems
132-
>>> map (\f -> (mkTest f.methodSignature, snd <$> f.inputs))
133-
>>> filter (isJust . fst)
134-
>>> fmap (first fromJust)
135-
136-
extractSig :: Test -> Text
137-
extractSig (ConcreteTest sig) = sig
138-
extractSig (SymbolicTest sig) = sig
139-
extractSig (InvariantTest sig) = sig
124+
>>> mapMaybe mkSig
140125

141126
traceSrcMap :: DappInfo -> Trace -> Maybe SrcMap
142127
traceSrcMap dapp trace = srcMap dapp trace.contract trace.opIx

src/EVM/SymExec.hs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,14 @@ import EVM.Stepper qualified as Stepper
4040
import EVM.Traversals
4141
import EVM.Types
4242
import EVM.Concrete (createAddress)
43-
import EVM.FeeSchedule qualified as FeeSchedule
43+
import EVM.FeeSchedule (feeSchedule)
4444
import EVM.Format (indent, formatBinary)
4545
import GHC.Conc (getNumProcessors)
4646
import GHC.Generics (Generic)
4747
import Optics.Core
4848
import Options.Generic (ParseField, ParseFields, ParseRecord)
4949
import Witch (into, unsafeInto)
5050

51-
-- | A method name, and the (ordered) types of it's arguments
52-
data Sig = Sig Text [AbiType]
53-
5451
data LoopHeuristic
5552
= Naive
5653
| StackBased
@@ -233,7 +230,7 @@ loadSymVM x initStore addr callvalue cd create =
233230
, baseFee = 0
234231
, priorityFee = 0
235232
, maxCodeSize = 0xffffffff
236-
, schedule = FeeSchedule.berlin
233+
, schedule = feeSchedule
237234
, chainId = 1
238235
, create = create
239236
, txAccessList = mempty

0 commit comments

Comments
 (0)