an intermediate symbolic execution engine for EVM bytecode
1{-# LANGUAGE LambdaCase #-}
2
3module Opcode where
4
5import Data.Word
6import Data.ByteString (ByteString)
7import qualified Data.ByteString as BS
8import Prelude hiding (LT, GT, EQ)
9
10data Opcode
11 = STOP | ADD | MUL | SUB | DIV | SDIV | MOD | SMOD
12 | ADDMOD | MULMOD | EXP | SIGNEXTEND
13 | LT | GT | SLT | SGT | EQ | ISZERO
14 | AND | OR | XOR | NOT | BYTE | SHL | SHR | SAR
15 | SHA3
16 | ADDRESS | BALANCE | ORIGIN | CALLER | CALLVALUE
17 | CALLDATALOAD | CALLDATASIZE | CALLDATACOPY
18 | CODESIZE | CODECOPY
19 | GASPRICE | EXTCODESIZE | EXTCODECOPY | RETURNDATASIZE | RETURNDATACOPY
20 | EXTCODEHASH
21 | BLOCKHASH | COINBASE | TIMESTAMP | NUMBER | DIFFICULTY | GASLIMIT
22 | CHAINID | SELFBALANCE | BASEFEE
23 | POP | MLOAD | MSTORE | MSTORE8 | SLOAD | SSTORE | JUMP | JUMPI
24 | PC | MSIZE | GAS | JUMPDEST
25 | PUSH1 | PUSH2 | PUSH3 | PUSH4 | PUSH5 | PUSH6 | PUSH7 | PUSH8
26 | PUSH9 | PUSH10 | PUSH11 | PUSH12 | PUSH13 | PUSH14 | PUSH15 | PUSH16
27 | PUSH17 | PUSH18 | PUSH19 | PUSH20 | PUSH21 | PUSH22 | PUSH23 | PUSH24
28 | PUSH25 | PUSH26 | PUSH27 | PUSH28 | PUSH29 | PUSH30 | PUSH31 | PUSH32
29 | DUP1 | DUP2 | DUP3 | DUP4 | DUP5 | DUP6 | DUP7 | DUP8
30 | DUP9 | DUP10 | DUP11 | DUP12 | DUP13 | DUP14 | DUP15 | DUP16
31 | SWAP1 | SWAP2 | SWAP3 | SWAP4 | SWAP5 | SWAP6 | SWAP7 | SWAP8
32 | SWAP9 | SWAP10 | SWAP11 | SWAP12 | SWAP13 | SWAP14 | SWAP15 | SWAP16
33 | LOG0 | LOG1 | LOG2 | LOG3 | LOG4
34 | CREATE | CALL | CALLCODE | RETURN | DELEGATECALL | CREATE2
35 | STATICCALL | REVERT | INVALID | SELFDESTRUCT
36 | UNKNOWN Word8
37 deriving (Show, Eq)
38
39decodeOpcode :: Word8 -> Opcode
40decodeOpcode = \case
41 0x00 -> STOP
42 0x01 -> ADD
43 0x02 -> MUL
44 0x03 -> SUB
45 0x04 -> DIV
46 0x05 -> SDIV
47 0x06 -> MOD
48 0x07 -> SMOD
49 0x08 -> ADDMOD
50 0x09 -> MULMOD
51 0x0a -> EXP
52 0x0b -> SIGNEXTEND
53 0x10 -> LT
54 0x11 -> GT
55 0x12 -> SLT
56 0x13 -> SGT
57 0x14 -> EQ
58 0x15 -> ISZERO
59 0x16 -> AND
60 0x17 -> OR
61 0x18 -> XOR
62 0x19 -> NOT
63 0x1a -> BYTE
64 0x1b -> SHL
65 0x1c -> SHR
66 0x1d -> SAR
67 0x20 -> SHA3
68 0x30 -> ADDRESS
69 0x31 -> BALANCE
70 0x32 -> ORIGIN
71 0x33 -> CALLER
72 0x34 -> CALLVALUE
73 0x35 -> CALLDATALOAD
74 0x36 -> CALLDATASIZE
75 0x37 -> CALLDATACOPY
76 0x38 -> CODESIZE
77 0x39 -> CODECOPY
78 0x3a -> GASPRICE
79 0x3b -> EXTCODESIZE
80 0x3c -> EXTCODECOPY
81 0x3d -> RETURNDATASIZE
82 0x3e -> RETURNDATACOPY
83 0x3f -> EXTCODEHASH
84 0x40 -> BLOCKHASH
85 0x41 -> COINBASE
86 0x42 -> TIMESTAMP
87 0x43 -> NUMBER
88 0x44 -> DIFFICULTY
89 0x45 -> GASLIMIT
90 0x46 -> CHAINID
91 0x47 -> SELFBALANCE
92 0x48 -> BASEFEE
93 0x50 -> POP
94 0x51 -> MLOAD
95 0x52 -> MSTORE
96 0x53 -> MSTORE8
97 0x54 -> SLOAD
98 0x55 -> SSTORE
99 0x56 -> JUMP
100 0x57 -> JUMPI
101 0x58 -> PC
102 0x59 -> MSIZE
103 0x5a -> GAS
104 0x5b -> JUMPDEST
105 0x60 -> PUSH1
106 0x61 -> PUSH2
107 0x62 -> PUSH3
108 0x63 -> PUSH4
109 0x64 -> PUSH5
110 0x65 -> PUSH6
111 0x66 -> PUSH7
112 0x67 -> PUSH8
113 0x68 -> PUSH9
114 0x69 -> PUSH10
115 0x6a -> PUSH11
116 0x6b -> PUSH12
117 0x6c -> PUSH13
118 0x6d -> PUSH14
119 0x6e -> PUSH15
120 0x6f -> PUSH16
121 0x70 -> PUSH17
122 0x71 -> PUSH18
123 0x72 -> PUSH19
124 0x73 -> PUSH20
125 0x74 -> PUSH21
126 0x75 -> PUSH22
127 0x76 -> PUSH23
128 0x77 -> PUSH24
129 0x78 -> PUSH25
130 0x79 -> PUSH26
131 0x7a -> PUSH27
132 0x7b -> PUSH28
133 0x7c -> PUSH29
134 0x7d -> PUSH30
135 0x7e -> PUSH31
136 0x7f -> PUSH32
137 0x80 -> DUP1
138 0x81 -> DUP2
139 0x82 -> DUP3
140 0x83 -> DUP4
141 0x84 -> DUP5
142 0x85 -> DUP6
143 0x86 -> DUP7
144 0x87 -> DUP8
145 0x88 -> DUP9
146 0x89 -> DUP10
147 0x8a -> DUP11
148 0x8b -> DUP12
149 0x8c -> DUP13
150 0x8d -> DUP14
151 0x8e -> DUP15
152 0x8f -> DUP16
153 0x90 -> SWAP1
154 0x91 -> SWAP2
155 0x92 -> SWAP3
156 0x93 -> SWAP4
157 0x94 -> SWAP5
158 0x95 -> SWAP6
159 0x96 -> SWAP7
160 0x97 -> SWAP8
161 0x98 -> SWAP9
162 0x99 -> SWAP10
163 0x9a -> SWAP11
164 0x9b -> SWAP12
165 0x9c -> SWAP13
166 0x9d -> SWAP14
167 0x9e -> SWAP15
168 0x9f -> SWAP16
169 0xa0 -> LOG0
170 0xa1 -> LOG1
171 0xa2 -> LOG2
172 0xa3 -> LOG3
173 0xa4 -> LOG4
174 0xf0 -> CREATE
175 0xf1 -> CALL
176 0xf2 -> CALLCODE
177 0xf3 -> RETURN
178 0xf4 -> DELEGATECALL
179 0xf5 -> CREATE2
180 0xfa -> STATICCALL
181 0xfd -> REVERT
182 0xfe -> INVALID
183 0xff -> SELFDESTRUCT
184 b -> UNKNOWN b
185
186pushBytes :: Opcode -> Int
187pushBytes PUSH1 = 1
188pushBytes PUSH2 = 2
189pushBytes PUSH3 = 3
190pushBytes PUSH4 = 4
191pushBytes PUSH5 = 5
192pushBytes PUSH6 = 6
193pushBytes PUSH7 = 7
194pushBytes PUSH8 = 8
195pushBytes PUSH9 = 9
196pushBytes PUSH10 = 10
197pushBytes PUSH11 = 11
198pushBytes PUSH12 = 12
199pushBytes PUSH13 = 13
200pushBytes PUSH14 = 14
201pushBytes PUSH15 = 15
202pushBytes PUSH16 = 16
203pushBytes PUSH17 = 17
204pushBytes PUSH18 = 18
205pushBytes PUSH19 = 19
206pushBytes PUSH20 = 20
207pushBytes PUSH21 = 21
208pushBytes PUSH22 = 22
209pushBytes PUSH23 = 23
210pushBytes PUSH24 = 24
211pushBytes PUSH25 = 25
212pushBytes PUSH26 = 26
213pushBytes PUSH27 = 27
214pushBytes PUSH28 = 28
215pushBytes PUSH29 = 29
216pushBytes PUSH30 = 30
217pushBytes PUSH31 = 31
218pushBytes PUSH32 = 32
219pushBytes _ = 0
220
221isPush :: Opcode -> Bool
222isPush op = pushBytes op > 0
223
224dupDepth :: Opcode -> Maybe Int
225dupDepth DUP1 = Just 1
226dupDepth DUP2 = Just 2
227dupDepth DUP3 = Just 3
228dupDepth DUP4 = Just 4
229dupDepth DUP5 = Just 5
230dupDepth DUP6 = Just 6
231dupDepth DUP7 = Just 7
232dupDepth DUP8 = Just 8
233dupDepth DUP9 = Just 9
234dupDepth DUP10 = Just 10
235dupDepth DUP11 = Just 11
236dupDepth DUP12 = Just 12
237dupDepth DUP13 = Just 13
238dupDepth DUP14 = Just 14
239dupDepth DUP15 = Just 15
240dupDepth DUP16 = Just 16
241dupDepth _ = Nothing
242
243swapDepth :: Opcode -> Maybe Int
244swapDepth SWAP1 = Just 1
245swapDepth SWAP2 = Just 2
246swapDepth SWAP3 = Just 3
247swapDepth SWAP4 = Just 4
248swapDepth SWAP5 = Just 5
249swapDepth SWAP6 = Just 6
250swapDepth SWAP7 = Just 7
251swapDepth SWAP8 = Just 8
252swapDepth SWAP9 = Just 9
253swapDepth SWAP10 = Just 10
254swapDepth SWAP11 = Just 11
255swapDepth SWAP12 = Just 12
256swapDepth SWAP13 = Just 13
257swapDepth SWAP14 = Just 14
258swapDepth SWAP15 = Just 15
259swapDepth SWAP16 = Just 16
260swapDepth _ = Nothing
261
262readBytecode :: ByteString -> Int -> Maybe Word8
263readBytecode code pc
264 | pc >= 0 && pc < BS.length code = Just (BS.index code pc)
265 | otherwise = Nothing
266
267readBytes :: ByteString -> Int -> Int -> Integer
268readBytes code start n = go 0 0
269 where
270 go acc i
271 | i >= n = acc
272 | otherwise = case readBytecode code (start + i) of
273 Just b -> go (acc * 256 + fromIntegral b) (i + 1)
274 Nothing -> acc