ciri 0.0.0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitmodules +14 -0
- data/.rspec +2 -1
- data/.travis.yml +11 -4
- data/Gemfile.lock +3 -0
- data/README.md +44 -34
- data/Rakefile +47 -4
- data/ciri.gemspec +13 -12
- data/docker/Base +34 -0
- data/lib/ciri/actor.rb +223 -0
- data/lib/ciri/chain.rb +293 -0
- data/lib/ciri/chain/block.rb +47 -0
- data/lib/ciri/chain/header.rb +62 -0
- data/lib/ciri/chain/transaction.rb +145 -0
- data/lib/ciri/crypto.rb +58 -5
- data/lib/ciri/db/backend/memory.rb +68 -0
- data/lib/ciri/db/backend/rocks.rb +104 -0
- data/lib/ciri/db/backend/rocks_db.rb +278 -0
- data/lib/ciri/devp2p/peer.rb +10 -2
- data/lib/ciri/devp2p/protocol.rb +11 -3
- data/lib/ciri/devp2p/protocol_io.rb +6 -3
- data/lib/ciri/devp2p/rlpx.rb +1 -0
- data/lib/ciri/devp2p/rlpx/encryption_handshake.rb +1 -1
- data/lib/ciri/devp2p/rlpx/frame_io.rb +1 -1
- data/lib/ciri/devp2p/rlpx/message.rb +4 -4
- data/lib/ciri/devp2p/server.rb +14 -13
- data/lib/ciri/eth.rb +33 -0
- data/lib/ciri/eth/peer.rb +64 -0
- data/lib/ciri/eth/protocol_manage.rb +122 -0
- data/lib/ciri/eth/protocol_messages.rb +158 -0
- data/lib/ciri/eth/synchronizer.rb +188 -0
- data/lib/ciri/ethash.rb +123 -0
- data/lib/ciri/evm.rb +140 -0
- data/lib/ciri/evm/account.rb +50 -0
- data/lib/ciri/evm/block_info.rb +31 -0
- data/lib/ciri/evm/forks/frontier.rb +183 -0
- data/lib/ciri/evm/instruction.rb +92 -0
- data/lib/ciri/evm/machine_state.rb +81 -0
- data/lib/ciri/evm/op.rb +536 -0
- data/lib/ciri/evm/serialize.rb +60 -0
- data/lib/ciri/evm/sub_state.rb +64 -0
- data/lib/ciri/evm/vm.rb +379 -0
- data/lib/ciri/forks.rb +38 -0
- data/lib/ciri/forks/frontier.rb +43 -0
- data/lib/ciri/key.rb +7 -1
- data/lib/ciri/pow.rb +95 -0
- data/lib/ciri/rlp.rb +3 -53
- data/lib/ciri/rlp/decode.rb +100 -40
- data/lib/ciri/rlp/encode.rb +95 -34
- data/lib/ciri/rlp/serializable.rb +61 -91
- data/lib/ciri/types/address.rb +70 -0
- data/lib/ciri/types/errors.rb +36 -0
- data/lib/ciri/utils.rb +45 -13
- data/lib/ciri/utils/lib_c.rb +46 -0
- data/lib/ciri/utils/logger.rb +99 -0
- data/lib/ciri/utils/number.rb +67 -0
- data/lib/ciri/version.rb +1 -1
- metadata +67 -7
- 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
|
data/lib/ciri/evm/op.rb
ADDED
@@ -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
|