-
Notifications
You must be signed in to change notification settings - Fork 396
/
Copy pathEvents.hs
112 lines (99 loc) · 4.14 KB
/
Events.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
{-# LANGUAGE ImplicitParams #-}
{-# LANGUAGE GADTs #-}
module Echidna.Events where
import Data.ByteString (ByteString)
import Data.ByteString qualified as BS
import Data.ByteString.Lazy (fromStrict)
import Data.Map (Map)
import Data.Map qualified as Map
import Data.Maybe (fromJust, catMaybes, maybeToList)
import Data.Text (pack, Text)
import Data.Tree (flatten)
import Data.Tree.Zipper (fromForest, TreePos, Empty)
import Data.Vector (fromList)
import EVM (traceForest)
import EVM.ABI (Event(..), Indexed(..), decodeAbiValue, AbiType(..), AbiValue(..))
import EVM.Dapp (DappContext(..), DappInfo(..))
import EVM.Expr (maybeLitWordSimp)
import EVM.Format (showValues, showError, contractNamePart)
import EVM.Solidity (SolcContract(..))
import EVM.Types
import Echidna.Symbolic (forceWord, forceBuf)
type EventMap = Map W256 Event
type Events = [Text]
emptyEvents :: TreePos Empty a
emptyEvents = fromForest []
extractEvents :: Bool -> DappInfo -> VM Concrete s -> Events
extractEvents decodeErrors dappInfo vm =
let forest = traceForest vm
in maybeToList (decodeRevert decodeErrors vm)
++ concatMap ((catMaybes . flatten) . fmap showTrace) forest
where
showTrace trace =
let ?context = DappContext { info = dappInfo, contracts = vm.env.contracts, labels = vm.labels } in
let codehash' = fromJust $ maybeLitWordSimp trace.contract.codehash
maybeContractName = maybeContractNameFromCodeHash dappInfo codehash'
in case trace.tracedata of
EventTrace addr bytes (topic:_) ->
case Map.lookup (forceWord topic) dappInfo.eventMap of
Just (Event name _ types) ->
-- TODO this is where indexed types are filtered out
-- they are filtered out for a reason as they only contain
-- the topic hash which is printed super verbose by dapptools
Just $
name
<> showValues [t | (_, t, NotIndexed) <- types] bytes
<> " from: "
<> maybe mempty (<> "@") maybeContractName
<> pack (show $ forceWord addr)
Nothing -> Just $ pack $ show (forceWord topic)
ErrorTrace e ->
case e of
Revert out ->
Just $
"error Revert "
<> showError out
<> maybe "" (": " <>) (maybeHumanPanic (forceBuf out))
<> maybe "" (" from: " <>) maybeContractName
_ ->
Just $ "error " <> pack (show e)
_ -> Nothing
maybeHumanPanic bs =
case BS.splitAt 4 bs of
("\x4e\x48\x7b\x71", d) ->
Just $ humanPanic $ decodePanic d
_ -> Nothing
maybeContractNameFromCodeHash :: DappInfo -> W256 -> Maybe Text
maybeContractNameFromCodeHash info codeHash = contractToName <$> maybeContract
where maybeContract = snd <$> Map.lookup codeHash info.solcByHash
contractToName c = contractNamePart c.contractName
decodeRevert :: Bool -> VM Concrete s -> Maybe Text
decodeRevert decodeErrors vm =
case vm.result of
Just (VMFailure (Revert (ConcreteBuf bs))) -> decodeRevertMsg decodeErrors bs
_ -> Nothing
decodeRevertMsg :: Bool -> ByteString -> Maybe Text
decodeRevertMsg decodeErrors bs =
case BS.splitAt 4 bs of
("\x08\xc3\x79\xa0", d) | decodeErrors ->
Just $ "Error" <> (pack . show $ decodeAbiValue (AbiTupleType (fromList [AbiStringType])) (fromStrict d))
("\x4e\x48\x7b\x71", d) ->
Just $ "Panic(" <> (pack . show $ decodePanic d) <> "): " <> humanPanic (decodePanic d)
_ -> Nothing
decodePanic :: ByteString -> AbiValue
decodePanic v = decodeAbiValue (AbiUIntType 256) (fromStrict v)
humanPanic :: AbiValue -> Text
humanPanic (AbiUInt _ code) =
case code of
0x01 -> "Using assert"
0x11 -> "SafeMath over-/under-flows"
0x12 -> "Divide by 0"
0x21 -> "Conversion into non-existent enum type"
0x22 -> "Incorrectly encoded storage byte array"
0x31 -> "pop() on an empty array"
0x32 -> "Index out of bounds exception"
0x41 -> "Allocating too much memory or creating a too large array"
0x51 -> "Calling a zero-initialized variable of internal function type"
_ -> "Unknown panic error code"
humanPanic _ =
error "Shouldn't happen, improve types to make this branch go away"