ciri 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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