ciri 0.0.0 → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +14 -0
  3. data/.rspec +2 -1
  4. data/.travis.yml +11 -4
  5. data/Gemfile.lock +3 -0
  6. data/README.md +44 -34
  7. data/Rakefile +47 -4
  8. data/ciri.gemspec +13 -12
  9. data/docker/Base +34 -0
  10. data/lib/ciri/actor.rb +223 -0
  11. data/lib/ciri/chain.rb +293 -0
  12. data/lib/ciri/chain/block.rb +47 -0
  13. data/lib/ciri/chain/header.rb +62 -0
  14. data/lib/ciri/chain/transaction.rb +145 -0
  15. data/lib/ciri/crypto.rb +58 -5
  16. data/lib/ciri/db/backend/memory.rb +68 -0
  17. data/lib/ciri/db/backend/rocks.rb +104 -0
  18. data/lib/ciri/db/backend/rocks_db.rb +278 -0
  19. data/lib/ciri/devp2p/peer.rb +10 -2
  20. data/lib/ciri/devp2p/protocol.rb +11 -3
  21. data/lib/ciri/devp2p/protocol_io.rb +6 -3
  22. data/lib/ciri/devp2p/rlpx.rb +1 -0
  23. data/lib/ciri/devp2p/rlpx/encryption_handshake.rb +1 -1
  24. data/lib/ciri/devp2p/rlpx/frame_io.rb +1 -1
  25. data/lib/ciri/devp2p/rlpx/message.rb +4 -4
  26. data/lib/ciri/devp2p/server.rb +14 -13
  27. data/lib/ciri/eth.rb +33 -0
  28. data/lib/ciri/eth/peer.rb +64 -0
  29. data/lib/ciri/eth/protocol_manage.rb +122 -0
  30. data/lib/ciri/eth/protocol_messages.rb +158 -0
  31. data/lib/ciri/eth/synchronizer.rb +188 -0
  32. data/lib/ciri/ethash.rb +123 -0
  33. data/lib/ciri/evm.rb +140 -0
  34. data/lib/ciri/evm/account.rb +50 -0
  35. data/lib/ciri/evm/block_info.rb +31 -0
  36. data/lib/ciri/evm/forks/frontier.rb +183 -0
  37. data/lib/ciri/evm/instruction.rb +92 -0
  38. data/lib/ciri/evm/machine_state.rb +81 -0
  39. data/lib/ciri/evm/op.rb +536 -0
  40. data/lib/ciri/evm/serialize.rb +60 -0
  41. data/lib/ciri/evm/sub_state.rb +64 -0
  42. data/lib/ciri/evm/vm.rb +379 -0
  43. data/lib/ciri/forks.rb +38 -0
  44. data/lib/ciri/forks/frontier.rb +43 -0
  45. data/lib/ciri/key.rb +7 -1
  46. data/lib/ciri/pow.rb +95 -0
  47. data/lib/ciri/rlp.rb +3 -53
  48. data/lib/ciri/rlp/decode.rb +100 -40
  49. data/lib/ciri/rlp/encode.rb +95 -34
  50. data/lib/ciri/rlp/serializable.rb +61 -91
  51. data/lib/ciri/types/address.rb +70 -0
  52. data/lib/ciri/types/errors.rb +36 -0
  53. data/lib/ciri/utils.rb +45 -13
  54. data/lib/ciri/utils/lib_c.rb +46 -0
  55. data/lib/ciri/utils/logger.rb +99 -0
  56. data/lib/ciri/utils/number.rb +67 -0
  57. data/lib/ciri/version.rb +1 -1
  58. metadata +67 -7
  59. data/lib/ciri/devp2p/actor.rb +0 -224
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2018, by Jiang Jinyang. <https://justjjy.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+
24
+ require_relative 'serialize'
25
+
26
+ module Ciri
27
+ class EVM
28
+
29
+ # represent current vm status, include stack, memory..
30
+ MachineState = Struct.new(:gas_remain, :pc, :memory, :memory_item, :stack, :output, keyword_init: true) do
31
+
32
+ # fetch a list of items from stack
33
+ def pop_list(count, type = nil)
34
+ count.times.map {pop(type)}
35
+ end
36
+
37
+ # pop a item from stack
38
+ def pop(type = nil)
39
+ item = stack.shift
40
+ item && Serialize.deserialize(type, item)
41
+ end
42
+
43
+ # get item from stack
44
+ def get_stack(index, type = nil)
45
+ item = stack[index]
46
+ item && Serialize.deserialize(type, item)
47
+ end
48
+
49
+ # push into stack
50
+ def push(item)
51
+ stack.unshift(item)
52
+ end
53
+
54
+ # store data to memory
55
+ def memory_store(start, size, data)
56
+ if start < memory.size && start + size - 1 < memory.size
57
+ memory[start..(start + size - 1)] = Serialize.serialize(data).rjust(size, "\x00".b)
58
+ end
59
+ end
60
+
61
+ # fetch data from memory
62
+ def memory_fetch(start, size)
63
+ if size > 0 && start < memory.size && start + size - 1 < memory.size
64
+ memory[start..(start + size - 1)]
65
+ else
66
+ # prevent size is too large
67
+ "\x00".b * [size, memory.size].min
68
+ end
69
+ end
70
+
71
+ # extend vm memory, used for memory_gas calculation
72
+ def extend_memory(pos, size)
73
+ if size != 0 && (i = Utils.ceil_div(pos + size, 32)) > memory_item
74
+ self.memory_item = i
75
+ end
76
+ end
77
+
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,536 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2018, by Jiang Jinyang. <https://justjjy.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+
24
+ require 'ciri/utils'
25
+ require 'ciri/utils/number'
26
+ require 'ciri/types/address'
27
+ require_relative 'serialize'
28
+
29
+ module Ciri
30
+ class EVM
31
+
32
+ # OP module include all EVM operations
33
+ module OP
34
+ include Types
35
+
36
+ OPERATIONS = {}
37
+
38
+ Operation = Struct.new(:name, :code, :inputs, :outputs, :handler, keyword_init: true) do
39
+ def call(*args)
40
+ handler.call(*args) if handler
41
+ end
42
+ end
43
+
44
+ class << self
45
+ # define VM operation
46
+ # this method also defined a constant under OP module
47
+ def def_op(name, code, inputs, outputs, &handler)
48
+ OPERATIONS[code] = Operation.new(name: name.to_s, code: code, inputs: inputs, outputs: outputs,
49
+ handler: handler).freeze
50
+ const_set(name, code)
51
+ code
52
+ end
53
+
54
+ def get(code)
55
+ OPERATIONS[code]
56
+ end
57
+
58
+ def input_count(code)
59
+ get(code)&.inputs
60
+ end
61
+
62
+ def output_count(code)
63
+ get(code)&.outputs
64
+ end
65
+ end
66
+
67
+ MAX_INT = Utils::Number::UINT_256_CEILING
68
+
69
+ # basic operations
70
+ def_op :STOP, 0x00, 0, 0
71
+ def_op :ADD, 0x01, 2, 1 do |vm|
72
+ a, b = vm.pop_list(2, Integer)
73
+ vm.push((a + b) % MAX_INT)
74
+ end
75
+
76
+ def_op :MUL, 0x02, 2, 1 do |vm|
77
+ a, b = vm.pop_list(2, Integer)
78
+ vm.push((a * b) % MAX_INT)
79
+ end
80
+
81
+ def_op :SUB, 0x03, 2, 1 do |vm|
82
+ a, b = vm.pop_list(2, Integer)
83
+ vm.push((a - b) % MAX_INT)
84
+ end
85
+
86
+ def_op :DIV, 0x04, 2, 1 do |vm|
87
+ a, b = vm.pop_list(2, Integer)
88
+ vm.push((b.zero? ? 0 : a / b) % MAX_INT)
89
+ end
90
+
91
+ def_op :SDIV, 0x05, 2, 1 do |vm|
92
+ a, b = vm.pop_list(2, Integer).map {|n| Utils::Number.unsigned_to_signed n}
93
+ value = b.zero? ? 0 : a.abs / b.abs
94
+ pos = (a > 0) ^ (b > 0) ? -1 : 1
95
+ vm.push(Utils::Number.signed_to_unsigned(value * pos) % MAX_INT)
96
+ end
97
+
98
+ def_op :MOD, 0x06, 2, 1 do |vm|
99
+ a, b = vm.pop_list(2, Integer)
100
+ vm.push(b.zero? ? 0 : a % b)
101
+ end
102
+
103
+ def_op :SMOD, 0x07, 2, 1 do |vm|
104
+ a, b = vm.pop_list(2, Integer).map {|n| Utils::Number.unsigned_to_signed n}
105
+ value = b.zero? ? 0 : a.abs % b.abs
106
+ pos = a > 0 ? 1 : -1
107
+ vm.push(Utils::Number.signed_to_unsigned(value * pos))
108
+ end
109
+
110
+ def_op :ADDMOD, 0x08, 3, 1 do |vm|
111
+ a, b, c = vm.pop_list(3, Integer)
112
+ value = c.zero? ? 0 : (a + b) % c
113
+ vm.push(value % MAX_INT)
114
+ end
115
+
116
+ def_op :MULMOD, 0x09, 3, 1 do |vm|
117
+ a, b, c = vm.pop_list(3, Integer)
118
+ vm.push(c.zero? ? 0 : (a * b) % c)
119
+ end
120
+
121
+ def_op :EXP, 0x0a, 2, 1 do |vm|
122
+ base, x = vm.pop_list(2, Integer)
123
+ vm.push(base.pow(x, MAX_INT))
124
+ end
125
+
126
+ # not sure how to handle signextend, copy algorithm from py-evm
127
+ def_op :SIGNEXTEND, 0x0b, 2, 1 do |vm|
128
+ bits, value = vm.pop_list(2, Integer)
129
+
130
+ if bits <= 31
131
+ testbit = bits * 8 + 7
132
+ sign_bit = (1 << testbit)
133
+
134
+ if value & sign_bit > 0
135
+ result = value | (MAX_INT - sign_bit)
136
+ else
137
+ result = value & (sign_bit - 1)
138
+ end
139
+
140
+ else
141
+ result = value
142
+ end
143
+
144
+ vm.push(result % MAX_INT)
145
+ end
146
+
147
+ def_op :LT, 0x10, 2, 1 do |vm|
148
+ a, b = vm.pop_list(2, Integer)
149
+ vm.push a < b ? 1 : 0
150
+ end
151
+
152
+ def_op :GT, 0x11, 2, 1 do |vm|
153
+ a, b = vm.pop_list(2, Integer)
154
+ vm.push a > b ? 1 : 0
155
+ end
156
+
157
+ def_op :SLT, 0x12, 2, 1 do |vm|
158
+ a, b = vm.pop_list(2, Integer).map {|i| Utils::Number.unsigned_to_signed i}
159
+ vm.push a < b ? 1 : 0
160
+ end
161
+
162
+ def_op :SGT, 0x13, 2, 1 do |vm|
163
+ a, b = vm.pop_list(2, Integer).map {|i| Utils::Number.unsigned_to_signed i}
164
+ vm.push a > b ? 1 : 0
165
+ end
166
+
167
+ def_op :EQ, 0x14, 2, 1 do |vm|
168
+ a, b = vm.pop_list(2, Integer)
169
+ vm.push a == b ? 1 : 0
170
+ end
171
+
172
+ def_op :ISZERO, 0x15, 1, 1 do |vm|
173
+ a = vm.pop(Integer)
174
+ vm.push a == 0 ? 1 : 0
175
+ end
176
+
177
+ def_op :AND, 0x16, 2, 1 do |vm|
178
+ a, b = vm.pop_list(2, Integer)
179
+ vm.push a & b
180
+ end
181
+
182
+ def_op :OR, 0x17, 2, 1 do |vm|
183
+ a, b = vm.pop_list(2, Integer)
184
+ vm.push a | b
185
+ end
186
+
187
+ def_op :XOR, 0x18, 2, 1 do |vm|
188
+ a, b = vm.pop_list(2, Integer)
189
+ vm.push a ^ b
190
+ end
191
+
192
+ def_op :NOT, 0x19, 1, 1 do |vm|
193
+ signed_number = Utils::Number.unsigned_to_signed vm.pop(Integer)
194
+ vm.push Utils::Number.signed_to_unsigned(~signed_number)
195
+ end
196
+
197
+ def_op :BYTE, 0x1a, 2, 1 do |vm|
198
+ pos, value = vm.pop_list(2, Integer)
199
+ if pos >= 32
200
+ result = 0
201
+ else
202
+ result = (value / 256.pow(31 - pos)) % 256
203
+ end
204
+ vm.push result
205
+ end
206
+
207
+ # 20s: sha3
208
+ def_op :SHA3, 0x20, 2, 1 do |vm|
209
+ pos, size = vm.pop_list(2, Integer)
210
+ hashed = Ciri::Utils.sha3 vm.memory_fetch(pos, size)
211
+ vm.extend_memory(pos, size)
212
+ vm.push hashed
213
+ end
214
+
215
+ # 30s: environment operations
216
+ def_op :ADDRESS, 0x30, 0, 1 do |vm|
217
+ vm.push(vm.instruction.address)
218
+ end
219
+
220
+ def_op :BALANCE, 0x31, 1, 1 do |vm|
221
+ address = vm.pop(Address)
222
+ account = vm.find_account(address)
223
+ vm.push(account.balance)
224
+ end
225
+
226
+ def_op :ORIGIN, 0x32, 0, 1 do |vm|
227
+ vm.push vm.instruction.origin
228
+ end
229
+
230
+ def_op :CALLER, 0x33, 0, 1 do |vm|
231
+ vm.push vm.instruction.sender
232
+ end
233
+
234
+ def_op :CALLVALUE, 0x34, 0, 1 do |vm|
235
+ vm.push vm.instruction.value
236
+ end
237
+
238
+ def_op :CALLDATALOAD, 0x35, 1, 1 do |vm|
239
+ start = vm.pop(Integer)
240
+ vm.push(vm.get_data(start, 32))
241
+ end
242
+
243
+ def_op :CALLDATASIZE, 0x36, 0, 1 do |vm|
244
+ vm.push vm.instruction.data.size
245
+ end
246
+
247
+ def_op :CALLDATACOPY, 0x37, 3, 0 do |vm|
248
+ mem_pos, data_pos, size = vm.pop_list(3, Integer)
249
+ data = vm.get_data(data_pos, size)
250
+ vm.memory_store(mem_pos, size, data)
251
+ vm.extend_memory(mem_pos, size)
252
+ end
253
+
254
+ def_op :CODESIZE, 0x38, 0, 1 do |vm|
255
+ vm.push vm.instruction.bytes_code.size
256
+ end
257
+
258
+ def_op :CODECOPY, 0x39, 3, 0 do |vm|
259
+ mem_pos, code_pos, size = vm.pop_list(3, Integer)
260
+ data = vm.get_code(code_pos, size)
261
+ vm.memory_store(mem_pos, size, data)
262
+ end
263
+
264
+ def_op :GASPRICE, 0x3a, 0, 1 do |vm|
265
+ vm.push vm.instruction.price
266
+ end
267
+
268
+ def_op :EXTCODESIZE, 0x3b, 0, 1 do |vm|
269
+ address = vm.pop(Address)
270
+ code_size = vm.find_account(address).code&.size || 0
271
+ vm.push code_size
272
+ end
273
+
274
+ def_op :EXTCODECOPY, 0x3c, 4, 0 do |vm|
275
+ address = vm.pop(Address)
276
+ mem_pos, data_pos, size = vm.pop_list(3, Integer)
277
+
278
+ account = vm.find_account(address)
279
+ code = account.code || ''.b
280
+ data_end_pos = data_pos + size - 1
281
+ data = if data_pos >= code.size
282
+ ''.b
283
+ elsif data_end_pos >= code.size
284
+ code[data_pos..-1]
285
+ else
286
+ code[data_pos..data_end_pos]
287
+ end
288
+ vm.memory_store(mem_pos, size, data)
289
+ end
290
+
291
+ RETURNDATASIZE = 0x3d
292
+ RETURNDATACOPY = 0x3e
293
+
294
+ # 40s: block information
295
+ BLOCKHASH = 0x40
296
+
297
+ def_op :COINBASE, 0x41, 0, 1 do |vm|
298
+ vm.push vm.block_info.coinbase
299
+ end
300
+
301
+ def_op :TIMESTAMP, 0x42, 0, 1 do |vm|
302
+ vm.push vm.block_info.timestamp
303
+ end
304
+
305
+ def_op :NUMBER, 0x43, 0, 1 do |vm|
306
+ vm.push vm.block_info.number
307
+ end
308
+
309
+ def_op :DIFFICULTY, 0x44, 0, 1 do |vm|
310
+ vm.push vm.block_info.difficulty
311
+ end
312
+
313
+ def_op :GASLIMIT, 0x45, 0, 1 do |vm|
314
+ vm.push vm.block_info.gas_limit
315
+ end
316
+
317
+ # 50s: Stack, Memory, Storage and Flow Operations
318
+ def_op :POP, 0x50, 1, 0 do |vm|
319
+ vm.pop
320
+ end
321
+
322
+ def_op :MLOAD, 0x51, 1, 1 do |vm|
323
+ index = vm.pop(Integer)
324
+ vm.push vm.memory_fetch(index, 32)
325
+ vm.extend_memory(index, 32)
326
+ end
327
+
328
+ def_op :MSTORE, 0x52, 2, 0 do |vm|
329
+ index = vm.pop(Integer)
330
+ data = vm.pop
331
+ vm.memory_store(index, 32, data)
332
+ vm.extend_memory(index, 32)
333
+ end
334
+
335
+ def_op :MSTORE8, 0x53, 2, 0 do |vm|
336
+ index = vm.pop(Integer)
337
+ data = vm.pop(Integer)
338
+ vm.memory_store(index, 1, data % 256)
339
+ vm.extend_memory(index, 8)
340
+ end
341
+
342
+ def_op :SLOAD, 0x54, 1, 1 do |vm|
343
+ key = vm.pop
344
+ vm.push vm.fetch(vm.instruction.address, key)
345
+ end
346
+
347
+ def_op :SSTORE, 0x55, 2, 0 do |vm|
348
+ key = vm.pop
349
+ value = vm.pop
350
+
351
+ vm.store(vm.instruction.address, key, value)
352
+ end
353
+
354
+ def_op :JUMP, 0x56, 1, 0 do |vm|
355
+ pc = vm.pop(Integer)
356
+ vm.jump_to(pc)
357
+ end
358
+
359
+ def_op :JUMPI, 0x57, 2, 0 do |vm|
360
+ dest, cond = vm.pop_list(2, Integer)
361
+ if cond != 0
362
+ vm.jump_to(dest)
363
+ else
364
+ vm.jump_to(vm.pc + 1)
365
+ end
366
+ end
367
+
368
+ def_op :PC, 0x58, 0, 1 do |vm|
369
+ vm.push vm.pc
370
+ end
371
+
372
+ def_op :MSIZE, 0x59, 0, 1 do |vm|
373
+ vm.push 32 * vm.memory_item
374
+ end
375
+
376
+ def_op :GAS, 0x5a, 0, 1 do |vm|
377
+ vm.push vm.machine_state.gas_remain
378
+ end
379
+
380
+ def_op :JUMPDEST, 0x5b, 0, 0
381
+
382
+ # 60s & 70s: Push Operations
383
+ # PUSH1 - PUSH32
384
+ (1..32).each do |i|
385
+ name = "PUSH#{i}"
386
+ def_op name, 0x60 + i - 1, 0, 1, &(proc do |byte_size|
387
+ proc do |vm|
388
+ vm.push vm.get_code(vm.pc + 1, byte_size)
389
+ end
390
+ end.call(i))
391
+ end
392
+
393
+ # 80s: Duplication Operations
394
+ # DUP1 - DUP16
395
+ (1..16).each do |i|
396
+ name = "DUP#{i}"
397
+ def_op name, 0x80 + i - 1, i, i + 1, &(proc do |i|
398
+ proc do |vm|
399
+ vm.push vm.stack[i - 1].dup
400
+ end
401
+ end.call(i))
402
+ end
403
+
404
+ # 90s: Exchange Operations
405
+ # SWAP1 - SWAP16
406
+ (1..16).each do |i|
407
+ name = "SWAP#{i}"
408
+ def_op name, 0x90 + i - 1, i + 1, i + 1, &(proc do |i|
409
+ proc do |vm|
410
+ vm.stack[0], vm.stack[i] = vm.stack[i], vm.stack[0]
411
+ end
412
+ end.call(i))
413
+ end
414
+
415
+ # a0s: Logging Operations
416
+ # LOG0 - LOG4
417
+ (0..4).each do |i|
418
+ name = "LOG#{i}"
419
+ def_op name, 0xa0 + i, i + 2, 0, &(proc do |i|
420
+ proc do |vm|
421
+ pos, size = vm.pop_list(2, Integer)
422
+ log_data = vm.memory_fetch(pos, size)
423
+ vm.extend_memory(pos, size)
424
+ topics = vm.pop_list(i)
425
+ vm.add_log_entry(topics, log_data)
426
+ end
427
+ end.call(i))
428
+ end
429
+
430
+ # f0s: System operations
431
+ def_op :CREATE, 0xf0, 3, 1 do |vm|
432
+ value = vm.pop(Integer)
433
+ mem_pos, size = vm.pop_list(2, Integer)
434
+
435
+ init = vm.memory_fetch(mem_pos, size)
436
+ vm.extend_memory(mem_pos, size)
437
+
438
+ contract_address = vm.create_contract(value: value, init: init)
439
+ vm.push contract_address
440
+ end
441
+
442
+ def_op :CALL, 0xf1, 7, 1 do |vm|
443
+ vm.pop
444
+ target = vm.pop(Address)
445
+ value = vm.pop(Integer)
446
+ input_mem_pos, input_size = vm.pop_list(2, Integer)
447
+ output_mem_pos, output_mem_size = vm.pop_list(2, Integer)
448
+
449
+ data = vm.memory_fetch(input_mem_pos, input_size)
450
+ vm.extend_memory(input_mem_pos, input_size)
451
+
452
+ status, output = vm.call_message(sender: vm.instruction.address, value: value,
453
+ data: data, receipt: target, code_address: target)
454
+
455
+ output_size = [output_mem_size, output.size].min
456
+ vm.memory_store(output_mem_pos, output_size, output)
457
+ vm.extend_memory(output_mem_pos, output_size)
458
+ vm.push status
459
+ end
460
+
461
+ def_op :CALLCODE, 0xf2, 7, 1 do |vm|
462
+ # this method consume 7 items from stack, but seems not all of them are used
463
+ # skip item
464
+ vm.pop
465
+ target = vm.pop(Address)
466
+ value = vm.pop(Integer)
467
+ input_mem_pos, input_size = vm.pop_list(2, Integer)
468
+ output_mem_pos, output_mem_size = vm.pop_list(2, Integer)
469
+
470
+ data = vm.memory_fetch(input_mem_pos, input_size)
471
+ vm.extend_memory(input_mem_pos, input_size)
472
+
473
+ status, output = vm.call_message(sender: vm.instruction.address, value: value,
474
+ data: data, receipt: vm.instruction.address, code_address: target)
475
+
476
+ output_size = [output_mem_size, output.size].min
477
+ vm.memory_store(output_mem_pos, output_size, output)
478
+ vm.extend_memory(output_mem_pos, output_size)
479
+ vm.push status
480
+ end
481
+
482
+ def_op :RETURN, 0xf3, 2, 0 do |vm|
483
+ index, size = vm.pop_list(2, Integer)
484
+ vm.output = vm.memory_fetch(index, size)
485
+ vm.extend_memory(index, size)
486
+ end
487
+
488
+ def_op :DELEGATECALL, 0xf4, 6, 1 do |vm|
489
+ vm.pop
490
+ target = vm.pop(Address)
491
+ input_mem_pos, input_size = vm.pop_list(2, Integer)
492
+ output_mem_pos, output_mem_size = vm.pop_list(2, Integer)
493
+
494
+ data = vm.memory_fetch(input_mem_pos, input_size)
495
+ vm.extend_memory(input_mem_pos, input_size)
496
+
497
+ status, output = vm.call_message(sender: vm.instruction.sender, value: vm.instruction.value,
498
+ data: data, receipt: vm.instruction.address, code_address: target)
499
+
500
+ output_size = [output_mem_size, output.size].min
501
+ vm.memory_store(output_mem_pos, output_size, output)
502
+ vm.extend_memory(output_mem_pos, output_size)
503
+ vm.push status
504
+ end
505
+
506
+ STATICCALL = 0xfa
507
+ REVERT = 0xfd
508
+
509
+ def_op :INVALID, 0xfe, 0, 0 do |vm|
510
+ raise 'should not invoke INVALID'
511
+ end
512
+
513
+ def_op :SELFDESTRUCT, 0xff, 1, 0 do |vm|
514
+ refund_address = vm.pop(Address)
515
+ refund_account = vm.find_account(refund_address)
516
+
517
+ vm.sub_state.suicide_accounts << vm.instruction.address
518
+ contract_account = vm.find_account vm.instruction.address
519
+
520
+ if refund_address != vm.instruction.address
521
+ refund_account.balance += contract_account.balance
522
+ end
523
+
524
+ contract_account.balance = 0
525
+
526
+ vm.update_account(refund_account)
527
+ vm.update_account(contract_account)
528
+
529
+ # register changed accounts
530
+ vm.add_refund_account(refund_account)
531
+ vm.add_suicide_account(contract_account)
532
+ end
533
+
534
+ end
535
+ end
536
+ end