ciri 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +8 -3
- data/README.md +5 -0
- data/Rakefile +24 -2
- data/ciri-rlp/.gitignore +11 -0
- data/ciri-rlp/.rspec +3 -0
- data/ciri-rlp/.travis.yml +5 -0
- data/ciri-rlp/CODE_OF_CONDUCT.md +74 -0
- data/ciri-rlp/Gemfile +6 -0
- data/ciri-rlp/Gemfile.lock +39 -0
- data/ciri-rlp/LICENSE.txt +21 -0
- data/ciri-rlp/README.md +98 -0
- data/ciri-rlp/Rakefile +6 -0
- data/ciri-rlp/bin/console +14 -0
- data/ciri-rlp/bin/setup +8 -0
- data/ciri-rlp/ciri-rlp.gemspec +28 -0
- data/{lib → ciri-rlp/lib}/ciri/rlp.rb +2 -2
- data/ciri-rlp/lib/ciri/rlp/decode.rb +144 -0
- data/ciri-rlp/lib/ciri/rlp/encode.rb +140 -0
- data/ciri-rlp/lib/ciri/rlp/serializable.rb +241 -0
- data/ciri-rlp/lib/ciri/rlp/version.rb +5 -0
- data/ciri-rlp/spec/ciri/fixture_spec.rb +95 -0
- data/ciri-rlp/spec/ciri/rlp/decode_spec.rb +68 -0
- data/ciri-rlp/spec/ciri/rlp/encode_spec.rb +72 -0
- data/ciri-rlp/spec/ciri/rlp/serializable_spec.rb +147 -0
- data/ciri-rlp/spec/ciri/rlp_spec.rb +5 -0
- data/ciri-rlp/spec/spec_helper.rb +14 -0
- data/ciri-utils/.gitignore +11 -0
- data/ciri-utils/.rspec +3 -0
- data/ciri-utils/.travis.yml +5 -0
- data/ciri-utils/CODE_OF_CONDUCT.md +74 -0
- data/ciri-utils/Gemfile +6 -0
- data/ciri-utils/Gemfile.lock +37 -0
- data/ciri-utils/LICENSE.txt +21 -0
- data/ciri-utils/README.md +61 -0
- data/ciri-utils/Rakefile +6 -0
- data/ciri-utils/bin/console +14 -0
- data/ciri-utils/bin/setup +8 -0
- data/ciri-utils/ciri-utils.gemspec +28 -0
- data/{lib → ciri-utils/lib}/ciri/utils.rb +9 -33
- data/{lib → ciri-utils/lib}/ciri/utils/logger.rb +0 -0
- data/{lib → ciri-utils/lib}/ciri/utils/number.rb +15 -12
- data/ciri-utils/lib/ciri/utils/version.rb +5 -0
- data/ciri-utils/spec/ciri/utils_spec.rb +5 -0
- data/ciri-utils/spec/spec_helper.rb +14 -0
- data/ciri.gemspec +6 -3
- data/lib/ciri/bloom_filter.rb +83 -0
- data/lib/ciri/chain.rb +67 -130
- data/lib/ciri/chain/header.rb +2 -2
- data/lib/ciri/chain/header_chain.rb +136 -0
- data/lib/ciri/chain/transaction.rb +1 -1
- data/lib/ciri/crypto.rb +2 -2
- data/lib/ciri/db/account_db.rb +145 -0
- data/lib/ciri/db/backend/memory.rb +24 -1
- data/lib/ciri/devp2p/peer.rb +1 -1
- data/lib/ciri/devp2p/rlpx/connection.rb +5 -5
- data/lib/ciri/eth/peer.rb +3 -3
- data/lib/ciri/eth/protocol_manage.rb +3 -3
- data/lib/ciri/eth/protocol_messages.rb +27 -26
- data/lib/ciri/ethash.rb +18 -3
- data/lib/ciri/evm.rb +101 -56
- data/lib/ciri/{utils/lib_c.rb → evm/errors.rb} +28 -18
- data/lib/ciri/evm/instruction.rb +3 -1
- data/lib/ciri/evm/{serialize.rb → log_entry.rb} +9 -27
- data/lib/ciri/evm/machine_state.rb +21 -2
- data/lib/ciri/evm/op.rb +19 -16
- data/lib/ciri/evm/state.rb +61 -0
- data/lib/ciri/evm/vm.rb +78 -102
- data/lib/ciri/forks.rb +1 -4
- data/lib/ciri/forks/base.rb +55 -0
- data/lib/ciri/forks/frontier.rb +37 -10
- data/lib/ciri/forks/frontier/cost.rb +186 -0
- data/lib/ciri/key.rb +1 -1
- data/lib/ciri/pow.rb +1 -1
- data/lib/ciri/rlp/decode.rb +6 -3
- data/lib/ciri/rlp/encode.rb +10 -10
- data/lib/ciri/rlp/serializable.rb +12 -9
- data/lib/ciri/serialize.rb +58 -0
- data/lib/ciri/trie.rb +362 -0
- data/lib/ciri/trie/nibbles.rb +97 -0
- data/lib/ciri/trie/nodes.rb +187 -0
- data/lib/ciri/{evm → types}/account.rb +20 -13
- data/lib/ciri/types/address.rb +16 -11
- data/lib/ciri/types/number.rb +73 -0
- data/lib/ciri/types/receipt.rb +57 -0
- data/lib/ciri/version.rb +1 -1
- metadata +82 -19
- data/lib/ciri/evm/forks/frontier.rb +0 -183
@@ -21,25 +21,35 @@
|
|
21
21
|
# THE SOFTWARE.
|
22
22
|
|
23
23
|
|
24
|
-
require 'ffi'
|
25
|
-
|
26
24
|
module Ciri
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
25
|
+
class EVM
|
26
|
+
|
27
|
+
class Error < StandardError
|
28
|
+
end
|
29
|
+
|
30
|
+
class InvalidTransition < Error
|
31
|
+
end
|
32
|
+
|
33
|
+
class InvalidTransaction < Error
|
34
|
+
end
|
35
|
+
|
36
|
+
# VM errors
|
37
|
+
class VMError < Error
|
38
|
+
end
|
39
|
+
|
40
|
+
class InvalidOpCodeError < VMError
|
41
|
+
end
|
42
|
+
|
43
|
+
class GasNotEnoughError < VMError
|
44
|
+
end
|
45
|
+
|
46
|
+
class StackError < VMError
|
47
|
+
end
|
48
|
+
|
49
|
+
class InvalidJumpError < VMError
|
50
|
+
end
|
51
|
+
|
52
|
+
class ReturnError < VMError
|
43
53
|
end
|
44
54
|
|
45
55
|
end
|
data/lib/ciri/evm/instruction.rb
CHANGED
@@ -21,40 +21,22 @@
|
|
21
21
|
# THE SOFTWARE.
|
22
22
|
|
23
23
|
|
24
|
+
require 'ciri/rlp'
|
25
|
+
require 'ciri/utils'
|
24
26
|
require 'ciri/types/address'
|
27
|
+
require 'ciri/types/number'
|
25
28
|
|
26
29
|
module Ciri
|
27
30
|
class EVM
|
28
|
-
module Serialize
|
29
31
|
|
30
|
-
|
32
|
+
class LogEntry
|
33
|
+
include RLP::Serializable
|
34
|
+
schema [{address: Types::Address}, {topics: [Types::Int32]}, :data]
|
31
35
|
|
32
|
-
def
|
33
|
-
|
34
|
-
when Integer
|
35
|
-
Utils.big_endian_encode(item)
|
36
|
-
when Types::Address
|
37
|
-
item.to_s
|
38
|
-
else
|
39
|
-
item
|
40
|
-
end
|
36
|
+
def to_blooms
|
37
|
+
[address.to_s, *topics.map {|t| Utils.big_endian_encode(t, size: 32)}]
|
41
38
|
end
|
42
|
-
|
43
|
-
def deserialize(type, item)
|
44
|
-
if type == Integer && !item.is_a?(Integer)
|
45
|
-
Utils.big_endian_decode(item.to_s)
|
46
|
-
elsif type == Types::Address && !item.is_a?(Types::Address)
|
47
|
-
# check if address represent in Integer
|
48
|
-
item = Utils.big_endian_encode(item) if item.is_a?(Integer)
|
49
|
-
Types::Address.new(item.size >= 20 ? item[-20..-1] : ''.b)
|
50
|
-
elsif type.nil?
|
51
|
-
# get serialized word
|
52
|
-
serialize(item).rjust(32, "\x00".b)
|
53
|
-
else
|
54
|
-
item
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
39
|
end
|
40
|
+
|
59
41
|
end
|
60
42
|
end
|
@@ -21,13 +21,32 @@
|
|
21
21
|
# THE SOFTWARE.
|
22
22
|
|
23
23
|
|
24
|
-
|
24
|
+
require 'ciri/serialize'
|
25
|
+
require 'ciri/evm/errors'
|
25
26
|
|
26
27
|
module Ciri
|
27
28
|
class EVM
|
28
29
|
|
29
30
|
# represent current vm status, include stack, memory..
|
30
|
-
MachineState
|
31
|
+
class MachineState
|
32
|
+
|
33
|
+
attr_reader :remain_gas, :memory, :stack
|
34
|
+
attr_accessor :pc, :output, :memory_item
|
35
|
+
|
36
|
+
def initialize(remain_gas:, pc:, memory:, memory_item:, stack:, output: ''.b)
|
37
|
+
raise ArgumentError.new("remain_gas must more than 0") if remain_gas < 0
|
38
|
+
@remain_gas = remain_gas
|
39
|
+
@pc = pc
|
40
|
+
@memory = memory
|
41
|
+
@memory_item = memory_item
|
42
|
+
@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
|
+
end
|
31
50
|
|
32
51
|
# fetch a list of items from stack
|
33
52
|
def pop_list(count, type = nil)
|
data/lib/ciri/evm/op.rb
CHANGED
@@ -24,7 +24,6 @@
|
|
24
24
|
require 'ciri/utils'
|
25
25
|
require 'ciri/utils/number'
|
26
26
|
require 'ciri/types/address'
|
27
|
-
require_relative 'serialize'
|
28
27
|
|
29
28
|
module Ciri
|
30
29
|
class EVM
|
@@ -267,7 +266,7 @@ module Ciri
|
|
267
266
|
|
268
267
|
def_op :EXTCODESIZE, 0x3b, 0, 1 do |vm|
|
269
268
|
address = vm.pop(Address)
|
270
|
-
code_size = vm.
|
269
|
+
code_size = vm.get_account_code(address).size
|
271
270
|
vm.push code_size
|
272
271
|
end
|
273
272
|
|
@@ -275,8 +274,7 @@ module Ciri
|
|
275
274
|
address = vm.pop(Address)
|
276
275
|
mem_pos, data_pos, size = vm.pop_list(3, Integer)
|
277
276
|
|
278
|
-
|
279
|
-
code = account.code || ''.b
|
277
|
+
code = vm.get_account_code(address)
|
280
278
|
data_end_pos = data_pos + size - 1
|
281
279
|
data = if data_pos >= code.size
|
282
280
|
''.b
|
@@ -340,13 +338,13 @@ module Ciri
|
|
340
338
|
end
|
341
339
|
|
342
340
|
def_op :SLOAD, 0x54, 1, 1 do |vm|
|
343
|
-
key = vm.pop
|
341
|
+
key = vm.pop(Integer)
|
344
342
|
vm.push vm.fetch(vm.instruction.address, key)
|
345
343
|
end
|
346
344
|
|
347
345
|
def_op :SSTORE, 0x55, 2, 0 do |vm|
|
348
|
-
key = vm.pop
|
349
|
-
value = vm.pop
|
346
|
+
key = vm.pop(Integer)
|
347
|
+
value = vm.pop(Integer)
|
350
348
|
|
351
349
|
vm.store(vm.instruction.address, key, value)
|
352
350
|
end
|
@@ -374,7 +372,7 @@ module Ciri
|
|
374
372
|
end
|
375
373
|
|
376
374
|
def_op :GAS, 0x5a, 0, 1 do |vm|
|
377
|
-
vm.push vm.machine_state.
|
375
|
+
vm.push vm.machine_state.remain_gas
|
378
376
|
end
|
379
377
|
|
380
378
|
def_op :JUMPDEST, 0x5b, 0, 0
|
@@ -421,7 +419,7 @@ module Ciri
|
|
421
419
|
pos, size = vm.pop_list(2, Integer)
|
422
420
|
log_data = vm.memory_fetch(pos, size)
|
423
421
|
vm.extend_memory(pos, size)
|
424
|
-
topics = vm.pop_list(i)
|
422
|
+
topics = vm.pop_list(i, Integer)
|
425
423
|
vm.add_log_entry(topics, log_data)
|
426
424
|
end
|
427
425
|
end.call(i))
|
@@ -435,7 +433,7 @@ module Ciri
|
|
435
433
|
init = vm.memory_fetch(mem_pos, size)
|
436
434
|
vm.extend_memory(mem_pos, size)
|
437
435
|
|
438
|
-
contract_address = vm.create_contract(value: value, init: init)
|
436
|
+
contract_address, _ = vm.create_contract(value: value, init: init)
|
439
437
|
vm.push contract_address
|
440
438
|
end
|
441
439
|
|
@@ -504,7 +502,13 @@ module Ciri
|
|
504
502
|
end
|
505
503
|
|
506
504
|
STATICCALL = 0xfa
|
507
|
-
|
505
|
+
|
506
|
+
# TODO REVERT need to be implement in forks
|
507
|
+
def_op :REVERT, -0xfd, 2, 0 do |vm|
|
508
|
+
index, size = vm.pop_list(2, Integer)
|
509
|
+
vm.output = vm.memory_fetch(index, size)
|
510
|
+
vm.extend_memory(index, size)
|
511
|
+
end
|
508
512
|
|
509
513
|
def_op :INVALID, 0xfe, 0, 0 do |vm|
|
510
514
|
raise 'should not invoke INVALID'
|
@@ -514,7 +518,6 @@ module Ciri
|
|
514
518
|
refund_address = vm.pop(Address)
|
515
519
|
refund_account = vm.find_account(refund_address)
|
516
520
|
|
517
|
-
vm.sub_state.suicide_accounts << vm.instruction.address
|
518
521
|
contract_account = vm.find_account vm.instruction.address
|
519
522
|
|
520
523
|
if refund_address != vm.instruction.address
|
@@ -523,12 +526,12 @@ module Ciri
|
|
523
526
|
|
524
527
|
contract_account.balance = 0
|
525
528
|
|
526
|
-
vm.
|
527
|
-
vm.
|
529
|
+
vm.state.set_balance(refund_address, refund_account.balance)
|
530
|
+
vm.state.set_balance(vm.instruction.address, contract_account.balance)
|
528
531
|
|
529
532
|
# register changed accounts
|
530
|
-
vm.add_refund_account(
|
531
|
-
vm.add_suicide_account(
|
533
|
+
vm.add_refund_account(refund_address)
|
534
|
+
vm.add_suicide_account(vm.instruction.address)
|
532
535
|
end
|
533
536
|
|
534
537
|
end
|
@@ -0,0 +1,61 @@
|
|
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 'forwardable'
|
25
|
+
require 'ciri/db/account_db'
|
26
|
+
|
27
|
+
module Ciri
|
28
|
+
class EVM
|
29
|
+
class State
|
30
|
+
|
31
|
+
extend Forwardable
|
32
|
+
|
33
|
+
def_delegators :@account_db, :set_nonce, :increment_nonce, :set_balance, :add_balance, :touch_account,
|
34
|
+
:find_account, :delete_account, :account_dead?, :store, :fetch, :set_account_code, :get_account_code
|
35
|
+
|
36
|
+
def initialize(db, state_root: nil)
|
37
|
+
@db = db
|
38
|
+
@account_db = DB::AccountDB.new(db, root_hash: state_root)
|
39
|
+
end
|
40
|
+
|
41
|
+
def snapshot
|
42
|
+
[state_root, @db.dup]
|
43
|
+
end
|
44
|
+
|
45
|
+
def revert(snapshot)
|
46
|
+
state_root, db = snapshot
|
47
|
+
@db = db
|
48
|
+
@account_db = DB::AccountDB.new(db, root_hash: state_root)
|
49
|
+
end
|
50
|
+
|
51
|
+
def commit(snapshot)
|
52
|
+
true
|
53
|
+
end
|
54
|
+
|
55
|
+
def state_root
|
56
|
+
@account_db.root_hash
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/ciri/evm/vm.rb
CHANGED
@@ -21,11 +21,13 @@
|
|
21
21
|
# THE SOFTWARE.
|
22
22
|
|
23
23
|
|
24
|
+
require 'ciri/utils/logger'
|
25
|
+
require_relative 'errors'
|
24
26
|
require_relative 'machine_state'
|
25
27
|
require_relative 'instruction'
|
26
28
|
require_relative 'sub_state'
|
27
29
|
require_relative 'block_info'
|
28
|
-
require_relative '
|
30
|
+
require_relative 'log_entry'
|
29
31
|
|
30
32
|
module Ciri
|
31
33
|
class EVM
|
@@ -40,25 +42,12 @@ module Ciri
|
|
40
42
|
# other logic of EVM (include transaction logic) in EVM module.
|
41
43
|
class VM
|
42
44
|
|
43
|
-
class VMError < StandardError
|
44
|
-
end
|
45
|
-
class InvalidOpCodeError < VMError
|
46
|
-
end
|
47
|
-
class GasNotEnoughError < VMError
|
48
|
-
end
|
49
|
-
class StackError < VMError
|
50
|
-
end
|
51
|
-
class InvalidJumpError < VMError
|
52
|
-
end
|
53
|
-
class ReturnError < VMError
|
54
|
-
end
|
55
|
-
|
56
45
|
class << self
|
57
46
|
# this method provide a simpler interface to create VM and execute code
|
58
47
|
# VM.spawn(...) == VM.new(...)
|
59
48
|
# @return VM
|
60
|
-
def spawn(state:, gas_limit:, header: nil, block_info: nil, instruction
|
61
|
-
ms = MachineState.new(
|
49
|
+
def spawn(state:, gas_limit:, header: nil, block_info: nil, instruction: EVM::Instruction.new, fork_config:)
|
50
|
+
ms = MachineState.new(remain_gas: gas_limit, pc: 0, stack: [], memory: "\x00".b * 256, memory_item: 0)
|
62
51
|
|
63
52
|
block_info = block_info || header && BlockInfo.new(
|
64
53
|
coinbase: header.beneficiary,
|
@@ -84,17 +73,18 @@ module Ciri
|
|
84
73
|
|
85
74
|
# helper methods
|
86
75
|
include Utils::Logger
|
87
|
-
include Serialize
|
88
76
|
|
89
|
-
def_delegators :@machine_state, :stack, :pc, :pop, :push, :pop_list, :get_stack,
|
90
|
-
:
|
77
|
+
def_delegators :@machine_state, :stack, :pc, :pop, :push, :pop_list, :get_stack, :memory_item, :memory_item=,
|
78
|
+
:memory_store, :memory_fetch, :extend_memory, :remain_gas, :consume_gas
|
91
79
|
def_delegators :@instruction, :get_op, :get_code, :next_valid_instruction_pos, :get_data, :data, :sender
|
92
80
|
def_delegators :@sub_state, :add_refund_account, :add_touched_account, :add_suicide_account
|
81
|
+
def_delegators :@state, :find_account, :account_dead?, :store, :fetch, :set_account_code, :get_account_code
|
93
82
|
|
94
|
-
attr_reader :machine_state, :instruction, :sub_state, :block_info, :fork_config
|
83
|
+
attr_reader :state, :machine_state, :instruction, :sub_state, :block_info, :fork_config
|
95
84
|
attr_accessor :output, :exception
|
96
85
|
|
97
|
-
def initialize(state:, machine_state:, sub_state: nil, instruction:, block_info:,
|
86
|
+
def initialize(state:, machine_state:, sub_state: nil, instruction:, block_info:,
|
87
|
+
fork_config:, burn_gas_on_exception: true)
|
98
88
|
@state = state
|
99
89
|
@machine_state = machine_state
|
100
90
|
@instruction = instruction
|
@@ -102,31 +92,7 @@ module Ciri
|
|
102
92
|
@output = nil
|
103
93
|
@block_info = block_info
|
104
94
|
@fork_config = fork_config
|
105
|
-
|
106
|
-
|
107
|
-
# store data to address
|
108
|
-
def store(address, key, data)
|
109
|
-
data_is_blank = Ciri::Utils.blank_binary?(data)
|
110
|
-
# key_is_blank = Ciri::Utils.blank_binary?(key)
|
111
|
-
|
112
|
-
return unless data && !data_is_blank
|
113
|
-
|
114
|
-
# remove unnecessary null byte from key
|
115
|
-
key = serialize(key).gsub(/\A\0+/, ''.b)
|
116
|
-
key = "\x00".b if key.empty?
|
117
|
-
|
118
|
-
account = find_account address
|
119
|
-
account.storage[key] = serialize(data).rjust(32, "\x00".b)
|
120
|
-
update_account(account)
|
121
|
-
end
|
122
|
-
|
123
|
-
# fetch data from address
|
124
|
-
def fetch(address, key)
|
125
|
-
# remove unnecessary null byte from key
|
126
|
-
key = serialize(key).gsub(/\A\0+/, ''.b)
|
127
|
-
key = "\x00".b if key.empty?
|
128
|
-
|
129
|
-
find_account(address).storage[key] || ''.b
|
95
|
+
@burn_gas_on_exception = burn_gas_on_exception
|
130
96
|
end
|
131
97
|
|
132
98
|
# run vm
|
@@ -138,21 +104,22 @@ module Ciri
|
|
138
104
|
# low_level create_contract interface
|
139
105
|
# CREATE_CONTRACT op is based on this method
|
140
106
|
def create_contract(value:, init:)
|
141
|
-
|
107
|
+
caller_address = instruction.address
|
108
|
+
account = find_account(caller_address)
|
142
109
|
|
143
110
|
# return contract address 0 represent execution failed
|
144
111
|
return 0 unless account.balance >= value || instruction.execute_depth > 1024
|
145
112
|
|
146
|
-
|
113
|
+
state.increment_nonce(caller_address)
|
114
|
+
snapshot = state.snapshot
|
147
115
|
|
148
116
|
# generate contract_address
|
149
|
-
material = RLP.encode_simple([
|
117
|
+
material = RLP.encode_simple([caller_address.to_s, account.nonce])
|
150
118
|
contract_address = Utils.sha3(material)[-20..-1]
|
151
119
|
|
152
120
|
# initialize contract account
|
153
121
|
contract_account = find_account(contract_address)
|
154
|
-
contract_account.nonce = 1
|
155
|
-
contract_account.code = Utils::BLANK_SHA3
|
122
|
+
# contract_account.nonce = 1
|
156
123
|
|
157
124
|
# execute initialize code
|
158
125
|
create_contract_instruction = instruction.dup
|
@@ -160,34 +127,48 @@ module Ciri
|
|
160
127
|
create_contract_instruction.execute_depth += 1
|
161
128
|
create_contract_instruction.address = contract_address
|
162
129
|
|
130
|
+
# TODO refactoring: Maybe should use call_message to execute data
|
163
131
|
call_instruction(create_contract_instruction) do
|
164
132
|
execute
|
165
133
|
|
166
|
-
|
167
|
-
|
134
|
+
deposit_code_gas = fork_config.calculate_deposit_code_gas(output)
|
135
|
+
|
136
|
+
if deposit_code_gas > remain_gas
|
137
|
+
# deposit_code_gas not enough
|
138
|
+
contract_address = 0
|
139
|
+
elsif exception
|
140
|
+
state.touch_account(contract_address)
|
168
141
|
contract_address = 0
|
142
|
+
state.revert(snapshot)
|
169
143
|
else
|
170
144
|
# set contract code
|
171
|
-
|
145
|
+
set_account_code(contract_address, output)
|
146
|
+
# minus deposit_code_fee
|
147
|
+
machine_state.consume_gas deposit_code_gas
|
172
148
|
# transact value
|
173
149
|
account.balance -= value
|
174
150
|
contract_account.balance += value
|
151
|
+
|
152
|
+
state.set_balance(contract_address, contract_account.balance)
|
153
|
+
state.set_balance(caller_address, account.balance)
|
154
|
+
state.commit(snapshot)
|
175
155
|
end
|
156
|
+
[contract_address, exception]
|
176
157
|
end
|
177
|
-
|
178
|
-
# update account
|
179
|
-
update_account(contract_account)
|
180
|
-
update_account(account)
|
181
|
-
|
182
|
-
contract_address
|
183
158
|
end
|
184
159
|
|
185
160
|
# low level call message interface
|
186
161
|
# CALL, CALLCODE, DELEGATECALL ops is base on this method
|
187
|
-
def call_message(sender:, value:, receipt:, data:, code_address:)
|
162
|
+
def call_message(sender:, value:, receipt:, data:, code_address: receipt)
|
188
163
|
# return status code 0 represent execution failed
|
189
164
|
return [0, ''.b] unless value <= find_account(sender).balance && instruction.execute_depth <= 1024
|
190
165
|
|
166
|
+
state.increment_nonce(sender)
|
167
|
+
|
168
|
+
snapshot = state.snapshot
|
169
|
+
|
170
|
+
transact(sender: sender, value: value, to: receipt)
|
171
|
+
|
191
172
|
message_call_instruction = instruction.dup
|
192
173
|
message_call_instruction.address = receipt
|
193
174
|
message_call_instruction.sender = sender
|
@@ -196,54 +177,48 @@ module Ciri
|
|
196
177
|
message_call_instruction.execute_depth += 1
|
197
178
|
|
198
179
|
message_call_instruction.data = data
|
199
|
-
message_call_instruction.bytes_code =
|
180
|
+
message_call_instruction.bytes_code = get_account_code(code_address)
|
200
181
|
|
201
|
-
transact(sender: sender, value: value, to: receipt)
|
202
182
|
call_instruction(message_call_instruction) do
|
203
183
|
execute
|
204
|
-
|
205
|
-
|
184
|
+
|
185
|
+
if exception
|
186
|
+
state.revert(snapshot)
|
187
|
+
else
|
188
|
+
state.commit(snapshot)
|
189
|
+
end
|
190
|
+
|
191
|
+
[status, output || ''.b, exception]
|
206
192
|
end
|
207
193
|
end
|
208
194
|
|
195
|
+
def status
|
196
|
+
exception.nil? ? 0 : 1
|
197
|
+
end
|
198
|
+
|
209
199
|
# jump to pc
|
210
200
|
# only valid if current op code is allowed to modify pc
|
211
201
|
def jump_to(pc)
|
212
202
|
@jump_to = pc
|
213
203
|
end
|
214
204
|
|
215
|
-
def account_dead?(address)
|
216
|
-
Account.account_dead?(@state, address)
|
217
|
-
end
|
218
|
-
|
219
|
-
def find_account(address)
|
220
|
-
Account.find_account(@state, address)
|
221
|
-
end
|
222
|
-
|
223
|
-
# the only method which touch state
|
224
|
-
# VM do not consider state revert/commit, we let it to state implementation
|
225
|
-
def update_account(account)
|
226
|
-
address = account.address.to_s
|
227
|
-
@state[address] = account
|
228
|
-
add_touched_account(account)
|
229
|
-
end
|
230
|
-
|
231
205
|
def add_log_entry(topics, log_data)
|
232
|
-
sub_state.log_series <<
|
206
|
+
sub_state.log_series << LogEntry.new(address: instruction.address, topics: topics, data: log_data)
|
233
207
|
end
|
234
208
|
|
235
209
|
# transact value from sender to target address
|
236
210
|
def transact(sender:, value:, to:)
|
237
|
-
|
238
|
-
|
211
|
+
sender_account = find_account(sender)
|
212
|
+
to_account = find_account(to)
|
239
213
|
|
240
|
-
raise VMError.new("balance not enough") if
|
214
|
+
raise VMError.new("balance not enough") if sender_account.balance < value
|
241
215
|
|
242
|
-
|
243
|
-
|
216
|
+
sender_account.balance -= value
|
217
|
+
to_account.balance += value
|
244
218
|
|
245
|
-
|
246
|
-
|
219
|
+
state.set_nonce(sender, sender_account.nonce)
|
220
|
+
state.set_balance(sender, sender_account.balance)
|
221
|
+
state.set_balance(to, to_account.balance)
|
247
222
|
end
|
248
223
|
|
249
224
|
# call instruction
|
@@ -268,13 +243,14 @@ module Ciri
|
|
268
243
|
def execute
|
269
244
|
loop do
|
270
245
|
if (@exception ||= check_exception(@state, machine_state, instruction))
|
271
|
-
|
246
|
+
if @burn_gas_on_exception
|
247
|
+
debug("exception: #{@exception}, burn gas #{machine_state.remain_gas} to zero")
|
248
|
+
machine_state.consume_gas machine_state.remain_gas
|
249
|
+
end
|
272
250
|
return [EMPTY_SET, machine_state, SubState::EMPTY, instruction, EMPTY_SET]
|
273
251
|
elsif get_op(machine_state.pc) == OP::REVERT
|
274
252
|
o = halt
|
275
|
-
|
276
|
-
machine_state.gas_remain -= gas_cost
|
277
|
-
return [EMPTY_SET, machine_state, sub_state, instruction, o]
|
253
|
+
return [EMPTY_SET, machine_state, SubState::EMPTY, instruction, o]
|
278
254
|
elsif (o = halt) != EMPTY_SET
|
279
255
|
return [@state, machine_state, sub_state, instruction, o]
|
280
256
|
else
|
@@ -294,23 +270,23 @@ module Ciri
|
|
294
270
|
|
295
271
|
raise "can't find operation #{w}, pc #{ms.pc}" unless operation
|
296
272
|
|
297
|
-
op_cost = fork_config.
|
298
|
-
old_memory_cost = fork_config.
|
299
|
-
ms.
|
273
|
+
op_cost = fork_config.gas_of_operation(self)
|
274
|
+
old_memory_cost = fork_config.gas_of_memory(ms.memory_item)
|
275
|
+
ms.consume_gas op_cost
|
300
276
|
|
301
277
|
prev_sub_state = sub_state.dup
|
302
278
|
|
303
279
|
# call operation
|
304
280
|
operation.call(self)
|
305
281
|
# calculate gas_cost
|
306
|
-
new_memory_cost = fork_config.
|
282
|
+
new_memory_cost = fork_config.gas_of_memory(ms.memory_item)
|
307
283
|
memory_gas_cost = new_memory_cost - old_memory_cost
|
308
284
|
|
309
|
-
if ms.
|
310
|
-
ms.
|
285
|
+
if ms.remain_gas >= memory_gas_cost
|
286
|
+
ms.consume_gas memory_gas_cost
|
311
287
|
else
|
312
288
|
# memory gas_not_enough
|
313
|
-
@exception = GasNotEnoughError.new "gas not enough: gas remain:#{ms.
|
289
|
+
@exception = GasNotEnoughError.new "gas not enough: gas remain:#{ms.remain_gas} gas cost: #{memory_gas_cost}"
|
314
290
|
end
|
315
291
|
|
316
292
|
# revert sub_state and return if exception occur
|
@@ -356,8 +332,8 @@ module Ciri
|
|
356
332
|
InvalidOpCodeError.new "can't find op code #{w}"
|
357
333
|
when ms.stack.size < (consume = OP.input_count(w))
|
358
334
|
StackError.new "stack not enough: stack:#{ms.stack.size} next consume: #{consume}"
|
359
|
-
when ms.
|
360
|
-
GasNotEnoughError.new "gas not enough: gas remain:#{ms.
|
335
|
+
when ms.remain_gas < (gas_cost = fork_config.gas_of_operation(self))
|
336
|
+
GasNotEnoughError.new "gas not enough: gas remain:#{ms.remain_gas} gas cost: #{gas_cost}"
|
361
337
|
when w == OP::JUMP && instruction.destinations.include?(ms.get_stack(0, Integer))
|
362
338
|
InvalidJumpError.new "invalid jump dest #{ms.get_stack(0, Integer)}"
|
363
339
|
when w == OP::JUMPI && ms.get_stack(1, Integer) != 0 && instruction.destinations.include?(ms.get_stack(0, Integer))
|