ciri 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/lib/ciri/evm/sub_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
|
module Ciri
|
@@ -27,17 +21,17 @@ module Ciri
|
|
27
21
|
# sub state contained changed accounts and log_series
|
28
22
|
class SubState
|
29
23
|
|
30
|
-
EMPTY = SubState.new.freeze
|
31
|
-
|
32
24
|
attr_reader :suicide_accounts, :log_series, :touched_accounts, :refunds
|
33
25
|
|
34
26
|
def initialize(suicide_accounts: [], log_series: [], touched_accounts: [], refunds: [])
|
35
|
-
@suicide_accounts =
|
27
|
+
@suicide_accounts = suicide_accounts
|
36
28
|
@log_series = log_series
|
37
|
-
@touched_accounts =
|
38
|
-
@refunds =
|
29
|
+
@touched_accounts = touched_accounts
|
30
|
+
@refunds = refunds
|
39
31
|
end
|
40
32
|
|
33
|
+
EMPTY = SubState.new.freeze
|
34
|
+
|
41
35
|
# support safety copy
|
42
36
|
def initialize_copy(orig)
|
43
37
|
super
|
@@ -48,15 +42,15 @@ module Ciri
|
|
48
42
|
end
|
49
43
|
|
50
44
|
def add_refund_account(account)
|
51
|
-
@refunds
|
45
|
+
@refunds << account
|
52
46
|
end
|
53
47
|
|
54
48
|
def add_touched_account(account)
|
55
|
-
@touched_accounts
|
49
|
+
@touched_accounts << account
|
56
50
|
end
|
57
51
|
|
58
52
|
def add_suicide_account(account)
|
59
|
-
@suicide_accounts
|
53
|
+
@suicide_accounts << account
|
60
54
|
end
|
61
55
|
end
|
62
56
|
|
data/lib/ciri/evm/vm.rb
CHANGED
@@ -1,34 +1,31 @@
|
|
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/logger'
|
19
|
+
require 'ciri/core_ext'
|
25
20
|
require_relative 'errors'
|
21
|
+
require_relative 'execution_context'
|
26
22
|
require_relative 'machine_state'
|
27
23
|
require_relative 'instruction'
|
28
24
|
require_relative 'sub_state'
|
29
25
|
require_relative 'block_info'
|
30
26
|
require_relative 'log_entry'
|
31
27
|
|
28
|
+
using Ciri::CoreExt
|
32
29
|
module Ciri
|
33
30
|
class EVM
|
34
31
|
|
@@ -42,57 +39,30 @@ module Ciri
|
|
42
39
|
# other logic of EVM (include transaction logic) in EVM module.
|
43
40
|
class VM
|
44
41
|
|
45
|
-
class << self
|
46
|
-
# this method provide a simpler interface to create VM and execute code
|
47
|
-
# VM.spawn(...) == VM.new(...)
|
48
|
-
# @return VM
|
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)
|
51
|
-
|
52
|
-
block_info = block_info || header && BlockInfo.new(
|
53
|
-
coinbase: header.beneficiary,
|
54
|
-
difficulty: header.difficulty,
|
55
|
-
gas_limit: header.gas_limit,
|
56
|
-
number: header.number,
|
57
|
-
timestamp: header.timestamp
|
58
|
-
)
|
59
|
-
|
60
|
-
vm = VM.new(
|
61
|
-
state: state,
|
62
|
-
machine_state: ms,
|
63
|
-
block_info: block_info,
|
64
|
-
instruction: instruction,
|
65
|
-
fork_config: fork_config
|
66
|
-
)
|
67
|
-
yield vm if block_given?
|
68
|
-
vm
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
42
|
extend Forwardable
|
73
43
|
|
74
44
|
# helper methods
|
75
45
|
include Utils::Logger
|
76
46
|
|
77
|
-
def_delegators
|
78
|
-
:memory_store, :memory_fetch, :extend_memory
|
79
|
-
def_delegators
|
80
|
-
|
81
|
-
def_delegators :@state, :find_account, :account_dead?, :store, :fetch, :set_account_code, :get_account_code
|
47
|
+
def_delegators :machine_state, :stack, :pop, :push, :pop_list, :get_stack, :memory_item, :memory_item=,
|
48
|
+
:memory_store, :memory_fetch, :extend_memory
|
49
|
+
def_delegators :state, :find_account, :account_dead?, :store, :fetch,
|
50
|
+
:set_account_code, :get_account_code, :account_exist?
|
82
51
|
|
83
|
-
|
84
|
-
|
52
|
+
# delegate methods to current execution_context
|
53
|
+
def_delegators :execution_context, :instruction, :sub_state, :machine_state, :block_info, :fork_schema,
|
54
|
+
:pc, :output, :exception, :set_output, :set_exception, :set_pc, :status, :depth,
|
55
|
+
:gas_limit, :refund_gas, :reset_refund_gas, :consume_gas, :remain_gas, :jump_to, :jump_pc
|
56
|
+
def_delegators :instruction, :get_op, :get_code, :next_valid_instruction_pos, :get_data, :data, :sender, :destinations
|
57
|
+
def_delegators :sub_state, :add_refund_account, :add_touched_account, :add_suicide_account
|
85
58
|
|
86
|
-
|
87
|
-
|
59
|
+
attr_reader :state, :execution_context, :burn_gas_on_exception, :max_depth, :stack_size
|
60
|
+
|
61
|
+
def initialize(state:, burn_gas_on_exception: true, max_depth: 1024, stack_size: 1024)
|
88
62
|
@state = state
|
89
|
-
@machine_state = machine_state
|
90
|
-
@instruction = instruction
|
91
|
-
@sub_state = sub_state || SubState.new
|
92
|
-
@output = nil
|
93
|
-
@block_info = block_info
|
94
|
-
@fork_config = fork_config
|
95
63
|
@burn_gas_on_exception = burn_gas_on_exception
|
64
|
+
@max_depth = max_depth
|
65
|
+
@stack_size = stack_size
|
96
66
|
end
|
97
67
|
|
98
68
|
# run vm
|
@@ -103,54 +73,52 @@ module Ciri
|
|
103
73
|
|
104
74
|
# low_level create_contract interface
|
105
75
|
# CREATE_CONTRACT op is based on this method
|
106
|
-
def create_contract(
|
107
|
-
caller_address = instruction.
|
76
|
+
def create_contract(context: self.execution_context)
|
77
|
+
caller_address = context.instruction.sender
|
78
|
+
value = context.instruction.value
|
108
79
|
account = find_account(caller_address)
|
109
80
|
|
110
81
|
# return contract address 0 represent execution failed
|
111
|
-
return 0 unless account.balance >= value ||
|
112
|
-
|
113
|
-
state.increment_nonce(caller_address)
|
82
|
+
return 0 unless account.balance >= value || depth > max_depth
|
114
83
|
snapshot = state.snapshot
|
115
84
|
|
116
85
|
# generate contract_address
|
117
|
-
material = RLP.encode_simple([caller_address.to_s, account.nonce])
|
118
|
-
contract_address = Utils.
|
86
|
+
material = RLP.encode_simple([caller_address.to_s, account.nonce - 1])
|
87
|
+
contract_address = Utils.keccak(material)[-20..-1]
|
88
|
+
|
89
|
+
transact(sender: caller_address, value: value, to: contract_address)
|
119
90
|
|
120
91
|
# initialize contract account
|
121
92
|
contract_account = find_account(contract_address)
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
call_instruction(create_contract_instruction) do
|
132
|
-
execute
|
93
|
+
context.instruction.address = contract_address
|
94
|
+
with_context(context) do
|
95
|
+
if contract_account.has_code? || contract_account.nonce > 0
|
96
|
+
err = ContractCollisionError.new("address #{contract_address.to_hex} collision")
|
97
|
+
debug(err.message)
|
98
|
+
set_exception(err)
|
99
|
+
else
|
100
|
+
execute
|
101
|
+
end
|
133
102
|
|
134
|
-
deposit_code_gas =
|
103
|
+
deposit_code_gas = fork_schema.calculate_deposit_code_gas(output)
|
135
104
|
|
136
105
|
if deposit_code_gas > remain_gas
|
137
106
|
# deposit_code_gas not enough
|
138
107
|
contract_address = 0
|
139
108
|
elsif exception
|
140
|
-
state.touch_account(contract_address)
|
109
|
+
# state.touch_account(contract_address)
|
141
110
|
contract_address = 0
|
111
|
+
if burn_gas_on_exception
|
112
|
+
debug("exception: #{exception}, burn gas #{remain_gas} to zero... op code: 0x#{get_op(pc).to_s(16)}")
|
113
|
+
consume_gas remain_gas
|
114
|
+
end
|
115
|
+
execution_context.revert
|
142
116
|
state.revert(snapshot)
|
143
117
|
else
|
144
118
|
# set contract code
|
145
119
|
set_account_code(contract_address, output)
|
146
120
|
# minus deposit_code_fee
|
147
|
-
|
148
|
-
# transact value
|
149
|
-
account.balance -= value
|
150
|
-
contract_account.balance += value
|
151
|
-
|
152
|
-
state.set_balance(contract_address, contract_account.balance)
|
153
|
-
state.set_balance(caller_address, account.balance)
|
121
|
+
consume_gas deposit_code_gas
|
154
122
|
state.commit(snapshot)
|
155
123
|
end
|
156
124
|
[contract_address, exception]
|
@@ -159,30 +127,34 @@ module Ciri
|
|
159
127
|
|
160
128
|
# low level call message interface
|
161
129
|
# CALL, CALLCODE, DELEGATECALL ops is base on this method
|
162
|
-
def call_message(
|
130
|
+
def call_message(context: self.execution_context, code_address: context.instruction.address)
|
131
|
+
address = context.instruction.address
|
132
|
+
value = context.instruction.value
|
133
|
+
sender = context.instruction.sender
|
163
134
|
# return status code 0 represent execution failed
|
164
|
-
return [0, ''.b] unless value <= find_account(sender).balance &&
|
165
|
-
|
166
|
-
state.increment_nonce(sender)
|
135
|
+
return [0, ''.b] unless value <= find_account(sender).balance && depth <= max_depth
|
167
136
|
|
168
137
|
snapshot = state.snapshot
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
call_instruction(message_call_instruction) do
|
183
|
-
execute
|
138
|
+
transact(sender: sender, value: value, to: address)
|
139
|
+
# enter new execution context
|
140
|
+
with_context(context) do
|
141
|
+
begin
|
142
|
+
if (precompile_contract = fork_schema.find_precompile_contract(code_address))
|
143
|
+
precompile_contract.call(self)
|
144
|
+
else
|
145
|
+
execute
|
146
|
+
end
|
147
|
+
rescue GasNotEnoughError => e
|
148
|
+
set_exception(e)
|
149
|
+
end
|
184
150
|
|
185
151
|
if exception
|
152
|
+
if burn_gas_on_exception
|
153
|
+
debug("exception: #{exception}, burn gas #{remain_gas} to zero... op code: 0x#{get_op(pc).to_s(16)}")
|
154
|
+
consume_gas remain_gas
|
155
|
+
end
|
156
|
+
execution_context.revert
|
157
|
+
|
186
158
|
state.revert(snapshot)
|
187
159
|
else
|
188
160
|
state.commit(snapshot)
|
@@ -192,16 +164,6 @@ module Ciri
|
|
192
164
|
end
|
193
165
|
end
|
194
166
|
|
195
|
-
def status
|
196
|
-
exception.nil? ? 0 : 1
|
197
|
-
end
|
198
|
-
|
199
|
-
# jump to pc
|
200
|
-
# only valid if current op code is allowed to modify pc
|
201
|
-
def jump_to(pc)
|
202
|
-
@jump_to = pc
|
203
|
-
end
|
204
|
-
|
205
167
|
def add_log_entry(topics, log_data)
|
206
168
|
sub_state.log_series << LogEntry.new(address: instruction.address, topics: topics, data: log_data)
|
207
169
|
end
|
@@ -209,50 +171,23 @@ module Ciri
|
|
209
171
|
# transact value from sender to target address
|
210
172
|
def transact(sender:, value:, to:)
|
211
173
|
sender_account = find_account(sender)
|
212
|
-
to_account = find_account(to)
|
213
|
-
|
214
174
|
raise VMError.new("balance not enough") if sender_account.balance < value
|
215
|
-
|
216
|
-
|
217
|
-
to_account.balance += value
|
218
|
-
|
219
|
-
state.set_nonce(sender, sender_account.nonce)
|
220
|
-
state.set_balance(sender, sender_account.balance)
|
221
|
-
state.set_balance(to, to_account.balance)
|
222
|
-
end
|
223
|
-
|
224
|
-
# call instruction
|
225
|
-
def call_instruction(new_instruction)
|
226
|
-
origin_instruction = instruction
|
227
|
-
origin_pc = pc
|
228
|
-
@instruction = new_instruction
|
229
|
-
@machine_state.pc = 0
|
230
|
-
|
231
|
-
return_value = yield
|
232
|
-
|
233
|
-
@instruction = origin_instruction
|
234
|
-
@machine_state.pc = origin_pc
|
235
|
-
# clear up state
|
236
|
-
@exception = nil
|
237
|
-
@output = ''.b
|
238
|
-
return_value
|
175
|
+
state.add_balance(sender, -value)
|
176
|
+
state.add_balance(to, value)
|
239
177
|
end
|
240
178
|
|
241
179
|
# Execute instruction with states
|
242
180
|
# Ξ(σ,g,I,T) ≡ (σ′,μ′ ,A,o)
|
243
181
|
def execute
|
244
182
|
loop do
|
245
|
-
if
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
end
|
250
|
-
return [EMPTY_SET, machine_state, SubState::EMPTY, instruction, EMPTY_SET]
|
251
|
-
elsif get_op(machine_state.pc) == OP::REVERT
|
183
|
+
if exception || set_exception(check_exception(@state, machine_state, instruction))
|
184
|
+
debug("check exception: #{exception}")
|
185
|
+
return
|
186
|
+
elsif get_op(pc) == OP::REVERT
|
252
187
|
o = halt
|
253
|
-
return
|
188
|
+
return
|
254
189
|
elsif (o = halt) != EMPTY_SET
|
255
|
-
return
|
190
|
+
return
|
256
191
|
else
|
257
192
|
operate
|
258
193
|
next
|
@@ -260,55 +195,60 @@ module Ciri
|
|
260
195
|
end
|
261
196
|
end
|
262
197
|
|
198
|
+
def with_context(new_context)
|
199
|
+
origin_context = execution_context
|
200
|
+
@execution_context = new_context
|
201
|
+
return_value = yield
|
202
|
+
@execution_context = origin_context
|
203
|
+
return_value
|
204
|
+
end
|
205
|
+
|
206
|
+
def extend_memory(pos, size)
|
207
|
+
machine_state.extend_memory(execution_context, pos, size)
|
208
|
+
end
|
209
|
+
|
263
210
|
private
|
264
211
|
|
265
212
|
# O(σ, μ, A, I) ≡ (σ′, μ′, A′, I)
|
266
213
|
def operate
|
267
|
-
|
268
|
-
w = get_op(ms.pc)
|
214
|
+
w = get_op(pc)
|
269
215
|
operation = OP.get(w)
|
270
216
|
|
271
|
-
raise "can't find operation #{w}, pc #{
|
217
|
+
raise "can't find operation #{w}, pc #{pc}" unless operation
|
272
218
|
|
273
|
-
op_cost =
|
274
|
-
old_memory_cost = fork_config.gas_of_memory(ms.memory_item)
|
275
|
-
ms.consume_gas op_cost
|
219
|
+
op_cost, op_refund = fork_schema.gas_of_operation(self)
|
276
220
|
|
277
|
-
|
221
|
+
debug("depth: #{depth} pc: #{pc} #{operation.name} gas: #{op_cost} stack: #{stack.size} logs: #{sub_state.log_series.size}")
|
278
222
|
|
279
|
-
|
280
|
-
|
281
|
-
# calculate gas_cost
|
282
|
-
new_memory_cost = fork_config.gas_of_memory(ms.memory_item)
|
283
|
-
memory_gas_cost = new_memory_cost - old_memory_cost
|
223
|
+
consume_gas op_cost
|
224
|
+
refund_gas op_refund if op_refund && op_refund > 0
|
284
225
|
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
226
|
+
# call operation
|
227
|
+
begin
|
228
|
+
operation.call(self)
|
229
|
+
rescue VMError => e
|
230
|
+
set_exception(e)
|
290
231
|
end
|
291
232
|
|
292
233
|
# revert sub_state and return if exception occur
|
293
234
|
if exception
|
294
|
-
|
235
|
+
execution_context.revert
|
295
236
|
return
|
296
237
|
end
|
297
238
|
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
end
|
239
|
+
set_pc case
|
240
|
+
when w == OP::JUMP
|
241
|
+
jump_pc
|
242
|
+
when w == OP::JUMPI && jump_pc
|
243
|
+
jump_pc
|
244
|
+
else
|
245
|
+
next_valid_instruction_pos(pc, w)
|
246
|
+
end
|
307
247
|
end
|
308
248
|
|
309
249
|
# determinate halt or not halt
|
310
250
|
def halt
|
311
|
-
w = get_op(
|
251
|
+
w = get_op(pc)
|
312
252
|
if w == OP::RETURN || w == OP::REVERT
|
313
253
|
operate
|
314
254
|
output
|
@@ -324,27 +264,25 @@ module Ciri
|
|
324
264
|
|
325
265
|
# check status
|
326
266
|
def check_exception(state, ms, instruction)
|
327
|
-
w = instruction.get_op(
|
267
|
+
w = instruction.get_op(pc)
|
328
268
|
case
|
329
|
-
when w == OP::INVALID
|
330
|
-
InvalidOpCodeError.new "can't find op code #{w}"
|
331
|
-
when OP.input_count(w).nil?
|
332
|
-
InvalidOpCodeError.new "can't find op code #{w}"
|
269
|
+
when w == OP::INVALID || OP.input_count(w).nil?
|
270
|
+
InvalidOpCodeError.new "can't find op code 0x#{w.to_s(16)} pc: #{pc}"
|
333
271
|
when ms.stack.size < (consume = OP.input_count(w))
|
334
272
|
StackError.new "stack not enough: stack:#{ms.stack.size} next consume: #{consume}"
|
335
|
-
when
|
336
|
-
GasNotEnoughError.new "gas not enough: gas remain:#{
|
337
|
-
when w == OP::JUMP &&
|
273
|
+
when remain_gas < (gas_cost = fork_schema.gas_of_operation(self).yield_self {|gas_cost, _| gas_cost})
|
274
|
+
GasNotEnoughError.new "gas not enough: gas remain:#{remain_gas} gas cost: #{gas_cost}"
|
275
|
+
when w == OP::JUMP && !destinations.include?(ms.get_stack(0, Integer))
|
338
276
|
InvalidJumpError.new "invalid jump dest #{ms.get_stack(0, Integer)}"
|
339
|
-
when w == OP::JUMPI && ms.get_stack(1, Integer) != 0 &&
|
277
|
+
when w == OP::JUMPI && ms.get_stack(1, Integer) != 0 && !destinations.include?(ms.get_stack(0, Integer))
|
340
278
|
InvalidJumpError.new "invalid condition jump dest #{ms.get_stack(0, Integer)}"
|
341
279
|
when w == OP::RETURNDATACOPY && ms.get_stack(1, Integer) + ms.get_stack(2, Integer) > ms.output.size
|
342
280
|
ReturnError.new "return data copy error"
|
343
|
-
when stack.size - OP.input_count(w) + OP.output_count(w) >
|
344
|
-
StackError.new "stack size reach
|
281
|
+
when stack.size - OP.input_count(w) + OP.output_count(w) > stack_size
|
282
|
+
StackError.new "stack size reach #{stack_size} limit"
|
345
283
|
# A condition in yellow paper but I can't understand..: (¬Iw ∧W(w,μ))
|
346
|
-
when
|
347
|
-
StackError.new "call depth reach
|
284
|
+
when depth > max_depth
|
285
|
+
StackError.new "call depth reach #{max_depth} limit"
|
348
286
|
else
|
349
287
|
nil
|
350
288
|
end
|