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
data/lib/ciri/evm.rb
ADDED
@@ -0,0 +1,140 @@
|
|
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 'evm/op'
|
25
|
+
require_relative 'evm/vm'
|
26
|
+
require_relative 'evm/account'
|
27
|
+
require 'ciri/forks'
|
28
|
+
|
29
|
+
module Ciri
|
30
|
+
class EVM
|
31
|
+
|
32
|
+
BLOCK_REWARD = 3 * 10.pow(18) # 3 ether
|
33
|
+
|
34
|
+
attr_reader :state
|
35
|
+
|
36
|
+
def initialize(state:)
|
37
|
+
@state = state
|
38
|
+
end
|
39
|
+
|
40
|
+
# run block
|
41
|
+
def finalize_block(block)
|
42
|
+
# validate block
|
43
|
+
# transition
|
44
|
+
# apply_changes
|
45
|
+
end
|
46
|
+
|
47
|
+
def validate_block(block)
|
48
|
+
# valid ommers
|
49
|
+
# valid transactions(block.gas_used == transactions...gas)
|
50
|
+
# Reward miner, ommers(reward == block reward + ommers reward)
|
51
|
+
# apply changes
|
52
|
+
# verify state and block nonce
|
53
|
+
# 1. parent header root == trie(state[i]) 当前状态的 root 相等, 返回 state[i] otherwise state[0]
|
54
|
+
end
|
55
|
+
|
56
|
+
# transition block
|
57
|
+
# block -> new block(mining)
|
58
|
+
# return new_block and status change
|
59
|
+
def transition(block)
|
60
|
+
# execute transactions, we don't need to valid transactions, it should be done before evm(in Chain module).
|
61
|
+
block.transactions.each do |transaction|
|
62
|
+
execute_transaction(transaction, header: block.header)
|
63
|
+
end
|
64
|
+
# status transfer
|
65
|
+
# state[c].balance += mining reward
|
66
|
+
# ommers: state[u.c].balance += uncle reward
|
67
|
+
#
|
68
|
+
# block.nonce
|
69
|
+
# block.mix
|
70
|
+
# R[i].gas_used = gas_used(state[i - 1], block.transactions[i]) + R[i - 1].gas_used
|
71
|
+
# R[i].logs = logs(state[i - 1], block.transactions[i])
|
72
|
+
# R[i].z = z(state[i - 1], block.transactions[i])
|
73
|
+
end
|
74
|
+
|
75
|
+
# execute transaction
|
76
|
+
# @param t Transaction
|
77
|
+
# @param header Chain::Header
|
78
|
+
def execute_transaction(t, header: nil, block_info: nil, ignore_exception: false)
|
79
|
+
instruction = Instruction.new(
|
80
|
+
origin: t.sender,
|
81
|
+
price: t.gas_price,
|
82
|
+
sender: t.sender,
|
83
|
+
value: t.value,
|
84
|
+
header: header,
|
85
|
+
execute_depth: 0,
|
86
|
+
)
|
87
|
+
|
88
|
+
if t.contract_creation?
|
89
|
+
instruction.bytes_code = t.data
|
90
|
+
instruction.address = t.sender
|
91
|
+
else
|
92
|
+
if (account = find_account t.to)
|
93
|
+
instruction.bytes_code = account.code
|
94
|
+
instruction.address = account.address
|
95
|
+
end
|
96
|
+
instruction.data = t.data
|
97
|
+
end
|
98
|
+
|
99
|
+
@vm = VM.spawn(
|
100
|
+
state: state,
|
101
|
+
gas_limit: t.gas_limit,
|
102
|
+
instruction: instruction,
|
103
|
+
header: header,
|
104
|
+
block_info: block_info,
|
105
|
+
fork_config: Ciri::Forks.detect_fork(header: header, number: block_info&.number)
|
106
|
+
)
|
107
|
+
|
108
|
+
if t.contract_creation?
|
109
|
+
# contract creation
|
110
|
+
@vm.create_contract(value: instruction.value, init: instruction.bytes_code)
|
111
|
+
else
|
112
|
+
# transact ether
|
113
|
+
begin
|
114
|
+
@vm.transact(sender: t.sender, value: t.value, to: t.to)
|
115
|
+
rescue VM::VMError
|
116
|
+
raise unless ignore_exception
|
117
|
+
return nil
|
118
|
+
end
|
119
|
+
@vm.run(ignore_exception: ignore_exception)
|
120
|
+
end
|
121
|
+
nil
|
122
|
+
end
|
123
|
+
|
124
|
+
def logs_hash
|
125
|
+
return nil unless @vm
|
126
|
+
Utils.sha3(RLP.encode_simple(@vm.sub_state.log_series))
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def account_dead?(address)
|
132
|
+
Account.account_dead?(state, address)
|
133
|
+
end
|
134
|
+
|
135
|
+
def find_account(address)
|
136
|
+
Account.find_account(state, address)
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,50 @@
|
|
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
|
+
|
26
|
+
module Ciri
|
27
|
+
class EVM
|
28
|
+
|
29
|
+
Account = Struct.new(:address, :balance, :code, :nonce, :storage, keyword_init: true) do
|
30
|
+
# EMPTY(σ,a) ≡ σ[a]c =KEC()∧σ[a]n =0∧σ[a]b =0
|
31
|
+
def empty?
|
32
|
+
code == Utils::BLANK_SHA3 && nonce == 0 && balance == 0
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.new_empty(address)
|
36
|
+
Account.new(address: address, balance: 0, nonce: 0, storage: {})
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.find_account(state, address)
|
40
|
+
state[address.to_s] || new_empty(address.to_s)
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.account_dead?(state, address)
|
44
|
+
account = state[address.to_s]
|
45
|
+
account.nil? || account.empty?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,31 @@
|
|
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
|
+
module Ciri
|
25
|
+
class EVM
|
26
|
+
|
27
|
+
# Block Info
|
28
|
+
BlockInfo = Struct.new(:coinbase, :difficulty, :gas_limit, :number, :timestamp, keyword_init: true)
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,183 @@
|
|
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/evm/op'
|
25
|
+
|
26
|
+
module Ciri
|
27
|
+
class EVM
|
28
|
+
module Forks
|
29
|
+
module Frontier
|
30
|
+
|
31
|
+
module Cost
|
32
|
+
# fee schedule, start with G
|
33
|
+
G_ZERO = 0
|
34
|
+
G_BASE = 2
|
35
|
+
G_VERYLOW = 3
|
36
|
+
G_LOW = 5
|
37
|
+
G_MID = 8
|
38
|
+
G_HIGH = 10
|
39
|
+
G_EXTCODE = 700
|
40
|
+
G_BALANCE = 400
|
41
|
+
G_SLOAD = 50
|
42
|
+
G_JUMPDEST = 1
|
43
|
+
G_SSET = 20000
|
44
|
+
G_RESET = 5000
|
45
|
+
R_SCLEAR = 15000
|
46
|
+
R_SELFDESTRUCT = 24000
|
47
|
+
G_SELFDESTRUCT = 0
|
48
|
+
G_CREATE = 32000
|
49
|
+
G_CODEDEPOSIT = 200
|
50
|
+
G_CALL = 700
|
51
|
+
G_CALLVALUE = 9000
|
52
|
+
G_CALLSTIPEND = 2300
|
53
|
+
G_NEWACCOUNT = 25000
|
54
|
+
G_EXP = 10
|
55
|
+
G_EXPBYTE = 10
|
56
|
+
G_MEMORY = 3
|
57
|
+
G_TXCREATE = 32000
|
58
|
+
G_TXDATAZERO = 4
|
59
|
+
G_TXDATANONZERO = 68
|
60
|
+
G_TRANSACTION = 21000
|
61
|
+
G_LOG = 375
|
62
|
+
G_LOGDATA = 8
|
63
|
+
G_TOPIC = 375
|
64
|
+
G_SHA3 = 30
|
65
|
+
G_SHA3WORD = 6
|
66
|
+
G_COPY = 3
|
67
|
+
G_BLOCKHASH = 20
|
68
|
+
G_QUADDIVISOR = 100
|
69
|
+
|
70
|
+
# operation code by group, for later calculation
|
71
|
+
W_ZERO = [OP::STOP, OP::RETURN, OP::REVERT]
|
72
|
+
W_BASE = [OP::ADDRESS, OP::ORIGIN, OP::CALLER, OP::CALLVALUE, OP::CALLDATASIZE, OP::CODESIZE, OP::GASPRICE,
|
73
|
+
OP::COINBASE, OP::TIMESTAMP, OP::NUMBER, OP::DIFFICULTY, OP::GASLIMIT, OP::RETURNDATASIZE,
|
74
|
+
OP::POP, OP::PC, OP::MSIZE, OP::GAS]
|
75
|
+
W_VERYLOW = [OP::ADD, OP::SUB, OP::NOT, OP::LT, OP::GT, OP::SLT, OP::SGT, OP::EQ, OP::ISZERO, OP::AND, OP::OR,
|
76
|
+
OP::XOR, OP::BYTE, OP::CALLDATALOAD, OP::MLOAD, OP::MSTORE, OP::MSTORE8,
|
77
|
+
*(1..32).map {|i| OP.get(OP::PUSH1 + i - 1).code}, # push1 - push32
|
78
|
+
*(1..16).map {|i| OP.get(OP::DUP1 + i - 1).code}, # dup1 - dup16
|
79
|
+
*(1..16).map {|i| OP.get(OP::SWAP1 + i - 1).code}] # swap1 - swap16
|
80
|
+
W_LOW = [OP::MUL, OP::DIV, OP::SDIV, OP::MOD, OP::SMOD, OP::SIGNEXTEND]
|
81
|
+
W_MID = [OP::ADDMOD, OP::MULMOD, OP::JUMP]
|
82
|
+
W_HIGH = [OP::JUMPI]
|
83
|
+
W_EXTCODE = [OP::EXTCODESIZE]
|
84
|
+
|
85
|
+
|
86
|
+
class << self
|
87
|
+
# C(σ,μ,I)
|
88
|
+
# calculate cost of current operation
|
89
|
+
def cost_of_operation(vm)
|
90
|
+
ms = vm.machine_state
|
91
|
+
instruction = vm.instruction
|
92
|
+
w = instruction.get_op(ms.pc)
|
93
|
+
if w == OP::SSTORE
|
94
|
+
cost_of_sstore(vm)
|
95
|
+
elsif w == OP::EXP && ms.get_stack(1, Integer) == 0
|
96
|
+
G_EXP
|
97
|
+
elsif w == OP::EXP && (x = ms.get_stack(1, Integer)) > 0
|
98
|
+
G_EXP + G_EXPBYTE * Utils.ceil_div(x.bit_length, 8)
|
99
|
+
elsif w == OP::CALLDATACOPY || w == OP::CODECOPY || w == OP::RETURNDATACOPY
|
100
|
+
G_VERYLOW + G_COPY * Utils.ceil_div(ms.get_stack(2, Integer), 32)
|
101
|
+
elsif w == OP::EXTCODECOPY
|
102
|
+
G_EXTCODE + G_COPY * Utils.ceil_div(ms.get_stack(3, Integer), 32)
|
103
|
+
elsif (OP::LOG0..OP::LOG4).include? w
|
104
|
+
G_LOG + G_LOGDATA * ms.get_stack(1, Integer) + (w - OP::LOG0) * G_TOPIC
|
105
|
+
elsif w == OP::CALL || w == OP::CALLCODE || w == OP::DELEGATECALL
|
106
|
+
1# cost_of_call(state, ms)
|
107
|
+
elsif w == OP::SELFDESTRUCT
|
108
|
+
cost_of_self_destruct(vm)
|
109
|
+
elsif w == OP::CREATE
|
110
|
+
G_CREATE
|
111
|
+
elsif w == OP::SHA3
|
112
|
+
G_SHA3 + G_SHA3WORD * Utils.ceil_div(ms.get_stack(1, Integer), 32)
|
113
|
+
elsif w == OP::JUMPDEST
|
114
|
+
G_JUMPDEST
|
115
|
+
elsif w == OP::SLOAD
|
116
|
+
G_SLOAD
|
117
|
+
elsif W_ZERO.include? w
|
118
|
+
G_ZERO
|
119
|
+
elsif W_BASE.include? w
|
120
|
+
G_BASE
|
121
|
+
elsif W_VERYLOW.include? w
|
122
|
+
G_VERYLOW
|
123
|
+
elsif W_LOW.include? w
|
124
|
+
G_LOW
|
125
|
+
elsif W_MID.include? w
|
126
|
+
G_MID
|
127
|
+
elsif W_HIGH.include? w
|
128
|
+
G_HIGH
|
129
|
+
elsif W_EXTCODE.include? w
|
130
|
+
G_EXTCODE
|
131
|
+
elsif w == OP::BALANCE
|
132
|
+
G_BALANCE
|
133
|
+
elsif w == OP::BLOCKHASH
|
134
|
+
G_BLOCKHASH
|
135
|
+
else
|
136
|
+
raise "can't compute cost for unknown op #{w}"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def cost_of_memory(i)
|
141
|
+
G_MEMORY * i + (i ** 2) / 512
|
142
|
+
end
|
143
|
+
|
144
|
+
def intrinsic_gas_of_transaction(t)
|
145
|
+
gas = (t.data.each_byte || '').reduce(0) {|sum, i| sum + i.zero? ? G_TXDATAZERO : G_TXDATANONZERO}
|
146
|
+
gas + (t.to.empty? ? G_TXCREATE : 0) + G_TRANSACTION
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
def cost_of_self_destruct(vm)
|
152
|
+
G_SELFDESTRUCT
|
153
|
+
end
|
154
|
+
|
155
|
+
def cost_of_call
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
def cost_of_sstore(vm)
|
160
|
+
ms = vm.machine_state
|
161
|
+
instruction = vm.instruction
|
162
|
+
|
163
|
+
key = ms.stack[0]
|
164
|
+
value = ms.stack[1]
|
165
|
+
account = vm.find_account instruction.address
|
166
|
+
|
167
|
+
value_exists = !Ciri::Utils.blank_binary?(value)
|
168
|
+
has_key = account && account.storage[key]
|
169
|
+
|
170
|
+
if value_exists && !has_key
|
171
|
+
G_SSET
|
172
|
+
else
|
173
|
+
G_RESET
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,92 @@
|
|
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
|
+
module Ciri
|
25
|
+
class EVM
|
26
|
+
|
27
|
+
# represent instruction
|
28
|
+
Instruction = Struct.new(:address, :origin, :price, :data, :sender, :value, :bytes_code, :header, :execute_depth,
|
29
|
+
keyword_init: true) do
|
30
|
+
|
31
|
+
def initialize(*args)
|
32
|
+
super
|
33
|
+
self.data ||= ''.b
|
34
|
+
self.value ||= 0
|
35
|
+
self.bytes_code ||= ''.b
|
36
|
+
self.execute_depth ||= 0
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_op(pos)
|
40
|
+
return OP::INVALID if pos >= (bytes_code || ''.b).size
|
41
|
+
bytes_code[pos].ord
|
42
|
+
end
|
43
|
+
|
44
|
+
# get data from instruction
|
45
|
+
def get_code(pos, size = 1)
|
46
|
+
if size > 0 && pos < bytes_code.size && pos + size - 1 < bytes_code.size
|
47
|
+
bytes_code[pos..(pos + size - 1)]
|
48
|
+
else
|
49
|
+
"\x00".b * size
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def get_data(pos, size)
|
54
|
+
if pos < data.size && size > 0
|
55
|
+
data[pos..(pos + size - 1)].ljust(size, "\x00".b)
|
56
|
+
else
|
57
|
+
"\x00".b * size
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# valid destinations of bytes_code
|
62
|
+
def destinations
|
63
|
+
@destinations ||= destinations_by_index(bytes_code, 0)
|
64
|
+
end
|
65
|
+
|
66
|
+
def next_valid_instruction_pos(pos, op_code)
|
67
|
+
if (OP::PUSH1..OP::PUSH32).include?(op_code)
|
68
|
+
pos + op_code - OP::PUSH1 + 2
|
69
|
+
else
|
70
|
+
pos + 1
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def destinations_by_index(bytes_code, i)
|
77
|
+
destinations = []
|
78
|
+
loop do
|
79
|
+
if i > bytes_code.size
|
80
|
+
break
|
81
|
+
elsif bytes_code[i] == OP::JUMPDEST
|
82
|
+
destinations << i
|
83
|
+
end
|
84
|
+
i = next_valid_instruction_pos(i, bytes_code[i])
|
85
|
+
end
|
86
|
+
destinations
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|