ciri 0.0.2 → 0.0.3
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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rspec +0 -1
- data/Gemfile.lock +11 -7
- data/LICENSE.txt +201 -21
- data/README.md +78 -25
- data/Rakefile +45 -17
- data/bin/bundle +105 -0
- data/bin/htmldiff +29 -0
- data/bin/ldiff +29 -0
- data/bin/rake +29 -0
- data/bin/rspec +29 -0
- data/ciri-crypto/.gitignore +11 -0
- data/ciri-crypto/.rspec +3 -0
- data/ciri-crypto/.travis.yml +5 -0
- data/ciri-crypto/CODE_OF_CONDUCT.md +74 -0
- data/ciri-crypto/Gemfile +6 -0
- data/ciri-crypto/Gemfile.lock +43 -0
- data/ciri-crypto/LICENSE.txt +201 -0
- data/ciri-crypto/README.md +58 -0
- data/ciri-crypto/Rakefile +6 -0
- data/ciri-crypto/bin/console +14 -0
- data/ciri-crypto/bin/setup +8 -0
- data/ciri-crypto/ciri-crypto.gemspec +40 -0
- data/ciri-crypto/lib/ciri/crypto/errors.rb +29 -0
- data/ciri-crypto/lib/ciri/crypto/signature.rb +71 -0
- data/ciri-crypto/lib/ciri/crypto/version.rb +5 -0
- data/{lib → ciri-crypto/lib}/ciri/crypto.rb +16 -69
- data/ciri-crypto/spec/ciri/crypto_spec.rb +56 -0
- data/ciri-crypto/spec/spec_helper.rb +14 -0
- data/ciri-rlp/Gemfile.lock +5 -5
- data/ciri-rlp/LICENSE.txt +201 -21
- data/ciri-rlp/README.md +1 -1
- data/ciri-rlp/ciri-rlp.gemspec +3 -3
- data/ciri-rlp/lib/ciri/rlp/decode.rb +10 -16
- data/ciri-rlp/lib/ciri/rlp/encode.rb +10 -16
- data/ciri-rlp/lib/ciri/rlp/serializable.rb +10 -16
- data/ciri-rlp/lib/ciri/rlp.rb +10 -16
- data/ciri-rlp/spec/ciri/fixture_spec.rb +10 -16
- data/ciri-rlp/spec/ciri/rlp/serializable_spec.rb +10 -16
- data/ciri-utils/Gemfile.lock +4 -4
- data/ciri-utils/LICENSE.txt +201 -21
- data/ciri-utils/README.md +1 -1
- data/ciri-utils/ciri-utils.gemspec +2 -2
- data/ciri-utils/lib/ciri/utils/logger.rb +10 -16
- data/ciri-utils/lib/ciri/utils/number.rb +10 -16
- data/ciri-utils/lib/ciri/utils/version.rb +1 -1
- data/ciri-utils/lib/ciri/utils.rb +3 -3
- data/ciri.gemspec +4 -3
- data/docker/{Base → Dockerfile} +9 -3
- data/lib/ciri/actor.rb +10 -16
- data/lib/ciri/bloom_filter.rb +11 -17
- data/lib/ciri/chain/block.rb +10 -16
- data/lib/ciri/chain/header.rb +12 -18
- data/lib/ciri/chain/header_chain.rb +8 -22
- data/lib/ciri/chain/transaction.rb +38 -33
- data/lib/ciri/chain.rb +27 -26
- data/lib/ciri/core_ext.rb +61 -0
- data/lib/ciri/db/account_db.rb +25 -21
- data/lib/ciri/db/backend/memory.rb +10 -16
- data/lib/ciri/db/backend/rocks.rb +10 -16
- data/lib/ciri/db/backend/rocks_db.rb +10 -16
- data/lib/ciri/devp2p/peer.rb +10 -16
- data/lib/ciri/devp2p/protocol.rb +10 -16
- data/lib/ciri/devp2p/protocol_io.rb +10 -16
- data/lib/ciri/devp2p/rlpx/connection.rb +10 -16
- data/lib/ciri/devp2p/rlpx/encryption_handshake.rb +13 -19
- data/lib/ciri/devp2p/rlpx/error.rb +10 -16
- data/lib/ciri/devp2p/rlpx/frame_io.rb +10 -16
- data/lib/ciri/devp2p/rlpx/message.rb +10 -16
- data/lib/ciri/devp2p/rlpx/node.rb +10 -16
- data/lib/ciri/devp2p/rlpx/protocol_handshake.rb +10 -16
- data/lib/ciri/devp2p/rlpx/protocol_messages.rb +10 -16
- data/lib/ciri/devp2p/rlpx/secrets.rb +10 -16
- data/lib/ciri/devp2p/rlpx.rb +10 -16
- data/lib/ciri/devp2p/server.rb +10 -16
- data/lib/ciri/eth/peer.rb +10 -16
- data/lib/ciri/eth/protocol_manage.rb +10 -16
- data/lib/ciri/eth/protocol_messages.rb +10 -16
- data/lib/ciri/eth/synchronizer.rb +10 -16
- data/lib/ciri/eth.rb +10 -16
- data/lib/ciri/ethash.rb +10 -16
- data/lib/ciri/evm/block_info.rb +25 -17
- data/lib/ciri/evm/errors.rb +13 -16
- data/lib/ciri/evm/execution_context.rb +136 -0
- data/lib/ciri/evm/instruction.rb +17 -24
- data/lib/ciri/evm/log_entry.rb +12 -18
- data/lib/ciri/evm/machine_state.rb +28 -33
- data/lib/ciri/evm/op.rb +52 -89
- data/lib/ciri/evm/op_call.rb +114 -0
- data/lib/ciri/evm/precompile_contract.rb +102 -0
- data/lib/ciri/evm/state.rb +28 -21
- data/lib/ciri/evm/sub_state.rb +18 -24
- data/lib/ciri/evm/vm.rb +128 -190
- data/lib/ciri/evm.rb +77 -85
- data/lib/ciri/forks/base.rb +28 -16
- data/lib/ciri/forks/byzantium.rb +43 -0
- data/lib/ciri/forks/config.rb +36 -0
- data/lib/ciri/forks/frontier/cost.rb +42 -33
- data/lib/ciri/forks/frontier.rb +47 -18
- data/lib/ciri/forks/homestead/cost.rb +195 -0
- data/lib/ciri/forks/homestead.rb +46 -0
- data/lib/ciri/forks.rb +12 -22
- data/lib/ciri/key.rb +14 -3
- data/lib/ciri/pow.rb +11 -17
- data/lib/ciri/rlp/decode.rb +10 -16
- data/lib/ciri/rlp/encode.rb +10 -16
- data/lib/ciri/rlp/serializable.rb +10 -16
- data/lib/ciri/serialize.rb +14 -17
- data/lib/ciri/trie/nibbles.rb +10 -16
- data/lib/ciri/trie/nodes.rb +12 -17
- data/lib/ciri/trie.rb +12 -18
- data/lib/ciri/types/account.rb +15 -17
- data/lib/ciri/types/address.rb +11 -17
- data/lib/ciri/types/errors.rb +10 -16
- data/lib/ciri/types/receipt.rb +12 -18
- data/lib/ciri/types/uint.rb +79 -0
- data/lib/ciri/version.rb +1 -1
- data/lib/ciri.rb +10 -16
- metadata +54 -10
- data/lib/ciri/types/number.rb +0 -73
|
@@ -1,26 +1,21 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# Copyright
|
|
3
|
+
# Copyright 2018 Jiang Jinyang <https://justjjy.com>
|
|
4
4
|
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
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:
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
11
8
|
#
|
|
12
|
-
#
|
|
13
|
-
# all copies or substantial portions of the Software.
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
14
10
|
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
-
# THE SOFTWARE.
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
22
16
|
|
|
23
17
|
|
|
18
|
+
require 'ciri/utils/logger'
|
|
24
19
|
require 'ciri/serialize'
|
|
25
20
|
require 'ciri/evm/errors'
|
|
26
21
|
|
|
@@ -29,23 +24,13 @@ module Ciri
|
|
|
29
24
|
|
|
30
25
|
# represent current vm status, include stack, memory..
|
|
31
26
|
class MachineState
|
|
27
|
+
include Utils::Logger
|
|
32
28
|
|
|
33
|
-
attr_reader :
|
|
34
|
-
attr_accessor :pc, :output, :memory_item
|
|
29
|
+
attr_reader :memory, :stack
|
|
35
30
|
|
|
36
|
-
def initialize(
|
|
37
|
-
raise ArgumentError.new("remain_gas must more than 0") if remain_gas < 0
|
|
38
|
-
@remain_gas = remain_gas
|
|
39
|
-
@pc = pc
|
|
31
|
+
def initialize(memory: ''.b, stack: [])
|
|
40
32
|
@memory = memory
|
|
41
|
-
@memory_item = memory_item
|
|
42
33
|
@stack = stack
|
|
43
|
-
@output = output
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def consume_gas(gas)
|
|
47
|
-
raise GasNotEnoughError.new("can't consume gas to negative, remain_gas: #{remain_gas}, consumed: #{gas}") if gas > remain_gas
|
|
48
|
-
@remain_gas -= gas
|
|
49
34
|
end
|
|
50
35
|
|
|
51
36
|
# fetch a list of items from stack
|
|
@@ -72,7 +57,7 @@ module Ciri
|
|
|
72
57
|
|
|
73
58
|
# store data to memory
|
|
74
59
|
def memory_store(start, size, data)
|
|
75
|
-
if start < memory.size && start + size - 1 < memory.size
|
|
60
|
+
if size > 0 && start < memory.size && start + size - 1 < memory.size
|
|
76
61
|
memory[start..(start + size - 1)] = Serialize.serialize(data).rjust(size, "\x00".b)
|
|
77
62
|
end
|
|
78
63
|
end
|
|
@@ -87,10 +72,20 @@ module Ciri
|
|
|
87
72
|
end
|
|
88
73
|
end
|
|
89
74
|
|
|
75
|
+
def memory_item
|
|
76
|
+
Utils.ceil_div(memory.size, 32)
|
|
77
|
+
end
|
|
78
|
+
|
|
90
79
|
# extend vm memory, used for memory_gas calculation
|
|
91
|
-
def extend_memory(pos, size)
|
|
92
|
-
if size != 0 && (
|
|
93
|
-
|
|
80
|
+
def extend_memory(context, pos, size)
|
|
81
|
+
if size != 0 && (new_item = Utils.ceil_div(pos + size, 32)) > memory_item
|
|
82
|
+
debug("extend memory: from #{memory_item} -> #{new_item}")
|
|
83
|
+
old_cost_gas = context.fork_schema.gas_of_memory memory_item
|
|
84
|
+
new_cost_gas = context.fork_schema.gas_of_memory new_item
|
|
85
|
+
context.consume_gas(new_cost_gas - old_cost_gas)
|
|
86
|
+
|
|
87
|
+
extend_size = (new_item - memory_item) * 32
|
|
88
|
+
self.memory << "\x00".b * extend_size
|
|
94
89
|
end
|
|
95
90
|
end
|
|
96
91
|
|
data/lib/ciri/evm/op.rb
CHANGED
|
@@ -1,29 +1,24 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# Copyright
|
|
3
|
+
# Copyright 2018 Jiang Jinyang <https://justjjy.com>
|
|
4
4
|
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
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:
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
11
8
|
#
|
|
12
|
-
#
|
|
13
|
-
# all copies or substantial portions of the Software.
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
14
10
|
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
-
# THE SOFTWARE.
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
22
16
|
|
|
23
17
|
|
|
24
18
|
require 'ciri/utils'
|
|
25
19
|
require 'ciri/utils/number'
|
|
26
20
|
require 'ciri/types/address'
|
|
21
|
+
require_relative 'op_call'
|
|
27
22
|
|
|
28
23
|
module Ciri
|
|
29
24
|
class EVM
|
|
@@ -206,7 +201,8 @@ module Ciri
|
|
|
206
201
|
# 20s: sha3
|
|
207
202
|
def_op :SHA3, 0x20, 2, 1 do |vm|
|
|
208
203
|
pos, size = vm.pop_list(2, Integer)
|
|
209
|
-
|
|
204
|
+
vm.extend_memory(pos, size)
|
|
205
|
+
hashed = Ciri::Utils.keccak vm.memory_fetch(pos, size)
|
|
210
206
|
vm.extend_memory(pos, size)
|
|
211
207
|
vm.push hashed
|
|
212
208
|
end
|
|
@@ -246,8 +242,8 @@ module Ciri
|
|
|
246
242
|
def_op :CALLDATACOPY, 0x37, 3, 0 do |vm|
|
|
247
243
|
mem_pos, data_pos, size = vm.pop_list(3, Integer)
|
|
248
244
|
data = vm.get_data(data_pos, size)
|
|
249
|
-
vm.memory_store(mem_pos, size, data)
|
|
250
245
|
vm.extend_memory(mem_pos, size)
|
|
246
|
+
vm.memory_store(mem_pos, size, data)
|
|
251
247
|
end
|
|
252
248
|
|
|
253
249
|
def_op :CODESIZE, 0x38, 0, 1 do |vm|
|
|
@@ -257,6 +253,7 @@ module Ciri
|
|
|
257
253
|
def_op :CODECOPY, 0x39, 3, 0 do |vm|
|
|
258
254
|
mem_pos, code_pos, size = vm.pop_list(3, Integer)
|
|
259
255
|
data = vm.get_code(code_pos, size)
|
|
256
|
+
vm.extend_memory(mem_pos, size)
|
|
260
257
|
vm.memory_store(mem_pos, size, data)
|
|
261
258
|
end
|
|
262
259
|
|
|
@@ -283,6 +280,7 @@ module Ciri
|
|
|
283
280
|
else
|
|
284
281
|
code[data_pos..data_end_pos]
|
|
285
282
|
end
|
|
283
|
+
vm.extend_memory(mem_pos, size)
|
|
286
284
|
vm.memory_store(mem_pos, size, data)
|
|
287
285
|
end
|
|
288
286
|
|
|
@@ -290,7 +288,14 @@ module Ciri
|
|
|
290
288
|
RETURNDATACOPY = 0x3e
|
|
291
289
|
|
|
292
290
|
# 40s: block information
|
|
293
|
-
BLOCKHASH
|
|
291
|
+
def_op :BLOCKHASH, 0x40, 1, 1 do |vm|
|
|
292
|
+
height = vm.pop(Integer)
|
|
293
|
+
# cause current block hash do not exists in chain
|
|
294
|
+
# here we compute distance of parent height and ancestor height
|
|
295
|
+
# and use parent_hash to find ancestor hash
|
|
296
|
+
distance = vm.block_info.number - height - 1
|
|
297
|
+
vm.push vm.state.get_ancestor_hash(vm.block_info.parent_hash, distance)
|
|
298
|
+
end
|
|
294
299
|
|
|
295
300
|
def_op :COINBASE, 0x41, 0, 1 do |vm|
|
|
296
301
|
vm.push vm.block_info.coinbase
|
|
@@ -319,22 +324,22 @@ module Ciri
|
|
|
319
324
|
|
|
320
325
|
def_op :MLOAD, 0x51, 1, 1 do |vm|
|
|
321
326
|
index = vm.pop(Integer)
|
|
322
|
-
vm.push vm.memory_fetch(index, 32)
|
|
323
327
|
vm.extend_memory(index, 32)
|
|
328
|
+
vm.push vm.memory_fetch(index, 32)
|
|
324
329
|
end
|
|
325
330
|
|
|
326
331
|
def_op :MSTORE, 0x52, 2, 0 do |vm|
|
|
327
332
|
index = vm.pop(Integer)
|
|
328
333
|
data = vm.pop
|
|
329
|
-
vm.memory_store(index, 32, data)
|
|
330
334
|
vm.extend_memory(index, 32)
|
|
335
|
+
vm.memory_store(index, 32, data)
|
|
331
336
|
end
|
|
332
337
|
|
|
333
338
|
def_op :MSTORE8, 0x53, 2, 0 do |vm|
|
|
334
339
|
index = vm.pop(Integer)
|
|
335
340
|
data = vm.pop(Integer)
|
|
336
|
-
vm.memory_store(index, 1, data % 256)
|
|
337
341
|
vm.extend_memory(index, 8)
|
|
342
|
+
vm.memory_store(index, 1, data % 256)
|
|
338
343
|
end
|
|
339
344
|
|
|
340
345
|
def_op :SLOAD, 0x54, 1, 1 do |vm|
|
|
@@ -356,10 +361,12 @@ module Ciri
|
|
|
356
361
|
|
|
357
362
|
def_op :JUMPI, 0x57, 2, 0 do |vm|
|
|
358
363
|
dest, cond = vm.pop_list(2, Integer)
|
|
364
|
+
# if cond is non zero jump to dest, else just goto next pc
|
|
359
365
|
if cond != 0
|
|
360
366
|
vm.jump_to(dest)
|
|
361
367
|
else
|
|
362
|
-
|
|
368
|
+
# clear jump_to
|
|
369
|
+
vm.jump_to(nil)
|
|
363
370
|
end
|
|
364
371
|
end
|
|
365
372
|
|
|
@@ -372,7 +379,7 @@ module Ciri
|
|
|
372
379
|
end
|
|
373
380
|
|
|
374
381
|
def_op :GAS, 0x5a, 0, 1 do |vm|
|
|
375
|
-
vm.push vm.
|
|
382
|
+
vm.push vm.remain_gas
|
|
376
383
|
end
|
|
377
384
|
|
|
378
385
|
def_op :JUMPDEST, 0x5b, 0, 0
|
|
@@ -417,8 +424,8 @@ module Ciri
|
|
|
417
424
|
def_op name, 0xa0 + i, i + 2, 0, &(proc do |i|
|
|
418
425
|
proc do |vm|
|
|
419
426
|
pos, size = vm.pop_list(2, Integer)
|
|
420
|
-
log_data = vm.memory_fetch(pos, size)
|
|
421
427
|
vm.extend_memory(pos, size)
|
|
428
|
+
log_data = vm.memory_fetch(pos, size)
|
|
422
429
|
topics = vm.pop_list(i, Integer)
|
|
423
430
|
vm.add_log_entry(topics, log_data)
|
|
424
431
|
end
|
|
@@ -430,75 +437,39 @@ module Ciri
|
|
|
430
437
|
value = vm.pop(Integer)
|
|
431
438
|
mem_pos, size = vm.pop_list(2, Integer)
|
|
432
439
|
|
|
433
|
-
init = vm.memory_fetch(mem_pos, size)
|
|
434
440
|
vm.extend_memory(mem_pos, size)
|
|
435
441
|
|
|
436
|
-
|
|
437
|
-
vm.
|
|
442
|
+
# have not enough money
|
|
443
|
+
if vm.find_account(vm.instruction.address).balance < value
|
|
444
|
+
vm.push(0)
|
|
445
|
+
else
|
|
446
|
+
init = vm.memory_fetch(mem_pos, size)
|
|
447
|
+
create_gas = vm.remain_gas
|
|
448
|
+
vm.consume_gas(create_gas)
|
|
449
|
+
child_context = vm.execution_context.child_context(gas_limit: create_gas)
|
|
450
|
+
contract_address, _ = vm.create_contract(value: value, init: init, touch_nonce: true, context: child_context)
|
|
451
|
+
vm.execution_context.return_gas(child_context.remain_gas)
|
|
452
|
+
|
|
453
|
+
vm.push contract_address
|
|
454
|
+
end
|
|
438
455
|
end
|
|
439
456
|
|
|
440
457
|
def_op :CALL, 0xf1, 7, 1 do |vm|
|
|
441
|
-
vm
|
|
442
|
-
target = vm.pop(Address)
|
|
443
|
-
value = vm.pop(Integer)
|
|
444
|
-
input_mem_pos, input_size = vm.pop_list(2, Integer)
|
|
445
|
-
output_mem_pos, output_mem_size = vm.pop_list(2, Integer)
|
|
446
|
-
|
|
447
|
-
data = vm.memory_fetch(input_mem_pos, input_size)
|
|
448
|
-
vm.extend_memory(input_mem_pos, input_size)
|
|
449
|
-
|
|
450
|
-
status, output = vm.call_message(sender: vm.instruction.address, value: value,
|
|
451
|
-
data: data, receipt: target, code_address: target)
|
|
452
|
-
|
|
453
|
-
output_size = [output_mem_size, output.size].min
|
|
454
|
-
vm.memory_store(output_mem_pos, output_size, output)
|
|
455
|
-
vm.extend_memory(output_mem_pos, output_size)
|
|
456
|
-
vm.push status
|
|
458
|
+
OPCall::Call.new.call(vm)
|
|
457
459
|
end
|
|
458
460
|
|
|
459
461
|
def_op :CALLCODE, 0xf2, 7, 1 do |vm|
|
|
460
|
-
|
|
461
|
-
# skip item
|
|
462
|
-
vm.pop
|
|
463
|
-
target = vm.pop(Address)
|
|
464
|
-
value = vm.pop(Integer)
|
|
465
|
-
input_mem_pos, input_size = vm.pop_list(2, Integer)
|
|
466
|
-
output_mem_pos, output_mem_size = vm.pop_list(2, Integer)
|
|
467
|
-
|
|
468
|
-
data = vm.memory_fetch(input_mem_pos, input_size)
|
|
469
|
-
vm.extend_memory(input_mem_pos, input_size)
|
|
470
|
-
|
|
471
|
-
status, output = vm.call_message(sender: vm.instruction.address, value: value,
|
|
472
|
-
data: data, receipt: vm.instruction.address, code_address: target)
|
|
473
|
-
|
|
474
|
-
output_size = [output_mem_size, output.size].min
|
|
475
|
-
vm.memory_store(output_mem_pos, output_size, output)
|
|
476
|
-
vm.extend_memory(output_mem_pos, output_size)
|
|
477
|
-
vm.push status
|
|
462
|
+
OPCall::CallCode.new.call(vm)
|
|
478
463
|
end
|
|
479
464
|
|
|
480
465
|
def_op :RETURN, 0xf3, 2, 0 do |vm|
|
|
481
466
|
index, size = vm.pop_list(2, Integer)
|
|
482
|
-
vm.output = vm.memory_fetch(index, size)
|
|
483
467
|
vm.extend_memory(index, size)
|
|
468
|
+
vm.set_output vm.memory_fetch(index, size)
|
|
484
469
|
end
|
|
485
470
|
|
|
486
|
-
def_op :DELEGATECALL, 0xf4, 6, 1 do |vm|
|
|
487
|
-
vm
|
|
488
|
-
target = vm.pop(Address)
|
|
489
|
-
input_mem_pos, input_size = vm.pop_list(2, Integer)
|
|
490
|
-
output_mem_pos, output_mem_size = vm.pop_list(2, Integer)
|
|
491
|
-
|
|
492
|
-
data = vm.memory_fetch(input_mem_pos, input_size)
|
|
493
|
-
vm.extend_memory(input_mem_pos, input_size)
|
|
494
|
-
|
|
495
|
-
status, output = vm.call_message(sender: vm.instruction.sender, value: vm.instruction.value,
|
|
496
|
-
data: data, receipt: vm.instruction.address, code_address: target)
|
|
497
|
-
|
|
498
|
-
output_size = [output_mem_size, output.size].min
|
|
499
|
-
vm.memory_store(output_mem_pos, output_size, output)
|
|
500
|
-
vm.extend_memory(output_mem_pos, output_size)
|
|
501
|
-
vm.push status
|
|
471
|
+
def_op :DELEGATECALL, -0xf4, 6, 1 do |vm|
|
|
472
|
+
OPCall::DelegateCall.new.call(vm)
|
|
502
473
|
end
|
|
503
474
|
|
|
504
475
|
STATICCALL = 0xfa
|
|
@@ -516,18 +487,10 @@ module Ciri
|
|
|
516
487
|
|
|
517
488
|
def_op :SELFDESTRUCT, 0xff, 1, 0 do |vm|
|
|
518
489
|
refund_address = vm.pop(Address)
|
|
519
|
-
refund_account = vm.find_account(refund_address)
|
|
520
|
-
|
|
521
490
|
contract_account = vm.find_account vm.instruction.address
|
|
522
491
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
end
|
|
526
|
-
|
|
527
|
-
contract_account.balance = 0
|
|
528
|
-
|
|
529
|
-
vm.state.set_balance(refund_address, refund_account.balance)
|
|
530
|
-
vm.state.set_balance(vm.instruction.address, contract_account.balance)
|
|
492
|
+
vm.state.add_balance(refund_address, contract_account.balance)
|
|
493
|
+
vm.state.set_balance(vm.instruction.address, 0)
|
|
531
494
|
|
|
532
495
|
# register changed accounts
|
|
533
496
|
vm.add_refund_account(refund_address)
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright 2018 Jiang Jinyang <https://justjjy.com>
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
require 'ciri/types/address'
|
|
19
|
+
|
|
20
|
+
module Ciri
|
|
21
|
+
class EVM
|
|
22
|
+
# handle EVM call operations
|
|
23
|
+
module OPCall
|
|
24
|
+
class Base
|
|
25
|
+
|
|
26
|
+
include Types
|
|
27
|
+
|
|
28
|
+
def call(vm)
|
|
29
|
+
raise NotImplementedError
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def extract_call_argument(vm)
|
|
33
|
+
gas = vm.pop(Integer)
|
|
34
|
+
to = vm.pop(Address)
|
|
35
|
+
value = vm.pop(Integer)
|
|
36
|
+
input_mem_pos, input_size = vm.pop_list(2, Integer)
|
|
37
|
+
output_mem_pos, output_mem_size = vm.pop_list(2, Integer)
|
|
38
|
+
|
|
39
|
+
# extend input output memory
|
|
40
|
+
vm.extend_memory(input_mem_pos, input_size)
|
|
41
|
+
vm.extend_memory(output_mem_pos, output_mem_size)
|
|
42
|
+
|
|
43
|
+
data = vm.memory_fetch(input_mem_pos, input_size)
|
|
44
|
+
[gas, to, value, data, output_mem_pos, output_mem_size]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def call_message(vm:, gas:, sender:, value:, data:, to:, code_address: to, output_mem_pos:, output_mem_size:)
|
|
48
|
+
context = vm.execution_context
|
|
49
|
+
child_gas_limit, child_gas_fee = context.fork_schema.gas_of_call(vm: vm,
|
|
50
|
+
gas: gas, to: to, value: value)
|
|
51
|
+
context.consume_gas(child_gas_fee)
|
|
52
|
+
if context.depth + 1 > 1024
|
|
53
|
+
context.return_gas(child_gas_limit)
|
|
54
|
+
vm.push 0
|
|
55
|
+
return
|
|
56
|
+
end
|
|
57
|
+
child_context = context.child_context(gas_limit: child_gas_limit)
|
|
58
|
+
child_context.instruction.sender = sender
|
|
59
|
+
child_context.instruction.value = value
|
|
60
|
+
child_context.instruction.data = data
|
|
61
|
+
child_context.instruction.address = to
|
|
62
|
+
child_context.instruction.bytes_code = vm.state.get_account_code(code_address)
|
|
63
|
+
status, output = vm.call_message(code_address: code_address, context: child_context)
|
|
64
|
+
|
|
65
|
+
context.return_gas(child_context.remain_gas)
|
|
66
|
+
output_size = [output_mem_size, output.size].min
|
|
67
|
+
vm.extend_memory(output_mem_pos, output_size)
|
|
68
|
+
vm.memory_store(output_mem_pos, output_size, output)
|
|
69
|
+
vm.push status
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
class Call < Base
|
|
74
|
+
def call(vm)
|
|
75
|
+
gas, to, value, data, output_mem_pos, output_mem_size = extract_call_argument(vm)
|
|
76
|
+
call_message(vm: vm, sender: vm.instruction.address, value: value, gas: gas, to: to,
|
|
77
|
+
data: data, code_address: to, output_mem_pos: output_mem_pos, output_mem_size: output_mem_size)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
class CallCode < Base
|
|
82
|
+
def call(vm)
|
|
83
|
+
gas, to, value, data, output_mem_pos, output_mem_size = extract_call_argument(vm)
|
|
84
|
+
call_message(vm: vm, sender: vm.instruction.address, value: value, gas: gas, to: vm.instruction.address,
|
|
85
|
+
data: data, code_address: to, output_mem_pos: output_mem_pos, output_mem_size: output_mem_size)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
class DelegateCall < Base
|
|
90
|
+
def call(vm)
|
|
91
|
+
gas, to, data, output_mem_pos, output_mem_size = extract_call_argument(vm)
|
|
92
|
+
call_message(vm: vm, sender: vm.instruction.sender, value: vm.instruction.value, gas: gas,
|
|
93
|
+
to: vm.instruction.address, data: data, code_address: to,
|
|
94
|
+
output_mem_pos: output_mem_pos, output_mem_size: output_mem_size)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def extract_call_argument(vm)
|
|
98
|
+
gas = vm.pop(Integer)
|
|
99
|
+
to = vm.pop(Address)
|
|
100
|
+
input_mem_pos, input_size = vm.pop_list(2, Integer)
|
|
101
|
+
output_mem_pos, output_mem_size = vm.pop_list(2, Integer)
|
|
102
|
+
|
|
103
|
+
# extend input output memory
|
|
104
|
+
vm.extend_memory(input_mem_pos, input_size)
|
|
105
|
+
vm.extend_memory(output_mem_pos, output_mem_size)
|
|
106
|
+
|
|
107
|
+
data = vm.memory_fetch(input_mem_pos, input_size)
|
|
108
|
+
[gas, to, data, output_mem_pos, output_mem_size]
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright 2018 Jiang Jinyang <https://justjjy.com>
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
require 'ciri/core_ext'
|
|
19
|
+
require 'ciri/crypto'
|
|
20
|
+
require 'digest'
|
|
21
|
+
|
|
22
|
+
using Ciri::CoreExt
|
|
23
|
+
|
|
24
|
+
module Ciri
|
|
25
|
+
class EVM
|
|
26
|
+
module PrecompileContract
|
|
27
|
+
|
|
28
|
+
class ECRecover
|
|
29
|
+
GAS_ECRECOVER = 3000
|
|
30
|
+
|
|
31
|
+
def call(vm)
|
|
32
|
+
vm.consume_gas(GAS_ECRECOVER)
|
|
33
|
+
message_hash = vm.instruction.data[0...32].pad_zero(32)
|
|
34
|
+
|
|
35
|
+
v = vm.instruction.data[32...64].decode_big_endian
|
|
36
|
+
r = vm.instruction.data[64...96].decode_big_endian
|
|
37
|
+
s = vm.instruction.data[96...128].decode_big_endian
|
|
38
|
+
unless valid_vrs?(v, r, s)
|
|
39
|
+
return vm.set_exception(Error.new("invalid vrs"))
|
|
40
|
+
end
|
|
41
|
+
raw_v = v - 27
|
|
42
|
+
begin
|
|
43
|
+
signature = Ciri::Crypto::Signature.new(vrs: [raw_v, r, s])
|
|
44
|
+
key = Ciri::Key.ecdsa_recover(message_hash, signature)
|
|
45
|
+
rescue StandardError => e
|
|
46
|
+
return vm.set_exception(e)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
vm.set_output(key.to_address.to_s)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def valid_vrs?(v, r, s)
|
|
53
|
+
return false unless r < Ciri::Crypto::SECP256K1N
|
|
54
|
+
return false unless s < Ciri::Crypto::SECP256K1N
|
|
55
|
+
return false unless v == 28 || v == 27
|
|
56
|
+
true
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
class SHA256
|
|
61
|
+
GAS_SHA256 = 60
|
|
62
|
+
GAS_SHA256WORD = 12
|
|
63
|
+
|
|
64
|
+
def call(vm)
|
|
65
|
+
input_bytes = vm.instruction.data
|
|
66
|
+
word_count = input_bytes.size.ceil_div(32) / 32
|
|
67
|
+
gas_fee = GAS_SHA256 + word_count * GAS_SHA256WORD
|
|
68
|
+
vm.consume_gas(gas_fee)
|
|
69
|
+
vm.set_output input_bytes.keccak
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
class RIPEMD160
|
|
74
|
+
GAS_RIPEMD160 = 600
|
|
75
|
+
GAS_RIPEMD160WORD = 120
|
|
76
|
+
|
|
77
|
+
def call(vm)
|
|
78
|
+
input_bytes = vm.instruction.data
|
|
79
|
+
word_count = input_bytes.size.ceil_div(32) / 32
|
|
80
|
+
gas_fee = GAS_RIPEMD160 + word_count * GAS_RIPEMD160WORD
|
|
81
|
+
vm.consume_gas(gas_fee)
|
|
82
|
+
vm.set_output Digest::RMD160.digest(input_bytes).pad_zero(32)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
class Identity
|
|
87
|
+
GAS_IDENTITY = 15
|
|
88
|
+
GAS_IDENTITYWORD = 3
|
|
89
|
+
|
|
90
|
+
def call(vm)
|
|
91
|
+
input_bytes = vm.instruction.data
|
|
92
|
+
word_count = input_bytes.size.ceil_div(32) / 32
|
|
93
|
+
gas_fee = GAS_IDENTITY + word_count * GAS_IDENTITYWORD
|
|
94
|
+
vm.consume_gas(gas_fee)
|
|
95
|
+
computation.output = input_bytes
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
data/lib/ciri/evm/state.rb
CHANGED
|
@@ -1,24 +1,18 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# Copyright
|
|
3
|
+
# Copyright 2018 Jiang Jinyang <https://justjjy.com>
|
|
4
4
|
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
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:
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
11
8
|
#
|
|
12
|
-
#
|
|
13
|
-
# all copies or substantial portions of the Software.
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
14
10
|
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
-
# THE SOFTWARE.
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
22
16
|
|
|
23
17
|
|
|
24
18
|
require 'forwardable'
|
|
@@ -31,11 +25,25 @@ module Ciri
|
|
|
31
25
|
extend Forwardable
|
|
32
26
|
|
|
33
27
|
def_delegators :@account_db, :set_nonce, :increment_nonce, :set_balance, :add_balance, :touch_account,
|
|
34
|
-
:find_account, :delete_account, :account_dead?, :store, :fetch,
|
|
28
|
+
:find_account, :delete_account, :account_dead?, :store, :fetch,
|
|
29
|
+
:set_account_code, :get_account_code, :account_exist?
|
|
35
30
|
|
|
36
|
-
def initialize(db, state_root: nil)
|
|
31
|
+
def initialize(db, state_root: nil, chain: nil)
|
|
37
32
|
@db = db
|
|
38
33
|
@account_db = DB::AccountDB.new(db, root_hash: state_root)
|
|
34
|
+
@chain = chain
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# get ancestor hash
|
|
38
|
+
def get_ancestor_hash(current_hash, ancestor_distance)
|
|
39
|
+
if ancestor_distance > 256 || ancestor_distance < 0
|
|
40
|
+
''.b
|
|
41
|
+
elsif ancestor_distance == 0
|
|
42
|
+
current_hash
|
|
43
|
+
else
|
|
44
|
+
parent_hash = @chain.get_header(current_hash).parent_hash
|
|
45
|
+
get_ancestor_hash(parent_hash, ancestor_distance - 1)
|
|
46
|
+
end
|
|
39
47
|
end
|
|
40
48
|
|
|
41
49
|
def snapshot
|
|
@@ -43,9 +51,8 @@ module Ciri
|
|
|
43
51
|
end
|
|
44
52
|
|
|
45
53
|
def revert(snapshot)
|
|
46
|
-
state_root,
|
|
47
|
-
@
|
|
48
|
-
@account_db = DB::AccountDB.new(db, root_hash: state_root)
|
|
54
|
+
state_root, _db = snapshot
|
|
55
|
+
@account_db = DB::AccountDB.new(@db, root_hash: state_root)
|
|
49
56
|
end
|
|
50
57
|
|
|
51
58
|
def commit(snapshot)
|