ciri 0.0.3 → 0.0.4
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/.travis.yml +2 -2
- data/Gemfile.lock +6 -6
- data/README.md +68 -48
- data/Rakefile +16 -11
- data/ciri-crypto/lib/ciri/crypto/signature.rb +7 -5
- data/ciri-rlp/ciri-rlp.gemspec +1 -1
- data/ciri-rlp/lib/ciri/rlp.rb +1 -1
- data/ciri-rlp/lib/ciri/rlp/decode.rb +23 -7
- data/ciri-rlp/lib/ciri/rlp/encode.rb +8 -2
- data/ciri-rlp/lib/ciri/rlp/serializable.rb +14 -4
- data/ciri-rlp/lib/ciri/rlp/version.rb +1 -1
- data/ciri-rlp/spec/ciri/fixture_spec.rb +2 -2
- data/ciri-utils/Gemfile.lock +1 -1
- data/ciri-utils/lib/ciri/utils/version.rb +1 -1
- data/ciri.gemspec +4 -4
- data/lib/ciri/chain/header.rb +13 -11
- data/lib/ciri/chain/header_chain.rb +1 -10
- data/lib/ciri/chain/transaction.rb +5 -23
- data/lib/ciri/db/account_db.rb +0 -4
- data/lib/ciri/db/backend/errors.rb +27 -0
- data/lib/ciri/db/backend/memory.rb +10 -12
- data/lib/ciri/db/backend/rocks.rb +13 -6
- data/lib/ciri/db/backend/rocks_db.rb +4 -0
- data/lib/ciri/evm.rb +6 -1
- data/lib/ciri/evm/execution_context.rb +6 -2
- data/lib/ciri/evm/instruction.rb +0 -1
- data/lib/ciri/evm/op.rb +11 -5
- data/lib/ciri/evm/op/errors.rb +37 -0
- data/lib/ciri/evm/state.rb +1 -1
- data/lib/ciri/evm/sub_state.rb +6 -6
- data/lib/ciri/evm/vm.rb +53 -33
- data/lib/ciri/forks.rb +4 -0
- data/lib/ciri/forks/base.rb +28 -0
- data/lib/ciri/forks/byzantium.rb +45 -11
- data/lib/ciri/forks/byzantium/opcodes.rb +37 -0
- data/lib/ciri/forks/constantinople.rb +29 -0
- data/lib/ciri/forks/frontier.rb +49 -29
- data/lib/ciri/forks/frontier/cost.rb +91 -95
- data/lib/ciri/forks/frontier/opcodes.rb +99 -0
- data/lib/ciri/forks/frontier/transaction.rb +62 -0
- data/lib/ciri/forks/homestead.rb +31 -7
- data/lib/ciri/forks/homestead/opcodes.rb +37 -0
- data/lib/ciri/forks/homestead/transaction.rb +43 -0
- data/lib/ciri/forks/spurious_dragon.rb +55 -0
- data/lib/ciri/forks/spurious_dragon/cost.rb +91 -0
- data/lib/ciri/forks/spurious_dragon/transaction.rb +44 -0
- data/lib/ciri/forks/tangerine_whistle.rb +37 -0
- data/lib/ciri/forks/tangerine_whistle/cost.rb +98 -0
- data/lib/ciri/rlp/decode.rb +4 -4
- data/lib/ciri/rlp/encode.rb +2 -2
- data/lib/ciri/version.rb +1 -1
- metadata +22 -10
- data/lib/ciri/forks/homestead/cost.rb +0 -195
@@ -21,7 +21,7 @@ module Ciri
|
|
21
21
|
module Forks
|
22
22
|
module Frontier
|
23
23
|
|
24
|
-
|
24
|
+
class Cost
|
25
25
|
|
26
26
|
include Ciri::EVM::OP
|
27
27
|
|
@@ -79,115 +79,111 @@ module Ciri
|
|
79
79
|
W_EXTCODE = [EXTCODESIZE]
|
80
80
|
|
81
81
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
G_BLOCKHASH
|
133
|
-
else
|
134
|
-
raise "can't compute cost for unknown op #{w}"
|
135
|
-
end
|
82
|
+
# C(σ,μ,I)
|
83
|
+
# calculate cost of current operation
|
84
|
+
def gas_of_operation(vm)
|
85
|
+
ms = vm.machine_state
|
86
|
+
instruction = vm.instruction
|
87
|
+
w = instruction.get_op(vm.pc)
|
88
|
+
if w == SSTORE
|
89
|
+
cost_of_sstore(vm)
|
90
|
+
elsif w == EXP && ms.get_stack(1, Integer) == 0
|
91
|
+
G_EXP
|
92
|
+
elsif w == EXP && (x = ms.get_stack(1, Integer)) > 0
|
93
|
+
G_EXP + G_EXPBYTE * Utils.ceil_div(x.bit_length, 8)
|
94
|
+
elsif w == CALLDATACOPY || w == CODECOPY || w == RETURNDATACOPY
|
95
|
+
G_VERYLOW + G_COPY * Utils.ceil_div(ms.get_stack(2, Integer), 32)
|
96
|
+
elsif w == EXTCODECOPY
|
97
|
+
G_EXTCODE + G_COPY * Utils.ceil_div(ms.get_stack(3, Integer), 32)
|
98
|
+
elsif (LOG0..LOG4).include? w
|
99
|
+
G_LOG + G_LOGDATA * ms.get_stack(1, Integer) + (w - LOG0) * G_TOPIC
|
100
|
+
elsif w == CALL || w == CALLCODE || w == DELEGATECALL
|
101
|
+
G_CALL
|
102
|
+
elsif w == SELFDESTRUCT
|
103
|
+
cost_of_self_destruct(vm)
|
104
|
+
elsif w == CREATE
|
105
|
+
G_CREATE
|
106
|
+
elsif w == SHA3
|
107
|
+
G_SHA3 + G_SHA3WORD * Utils.ceil_div(ms.get_stack(1, Integer), 32)
|
108
|
+
elsif w == JUMPDEST
|
109
|
+
G_JUMPDEST
|
110
|
+
elsif w == SLOAD
|
111
|
+
G_SLOAD
|
112
|
+
elsif W_ZERO.include? w
|
113
|
+
G_ZERO
|
114
|
+
elsif W_BASE.include? w
|
115
|
+
G_BASE
|
116
|
+
elsif W_VERYLOW.include? w
|
117
|
+
G_VERYLOW
|
118
|
+
elsif W_LOW.include? w
|
119
|
+
G_LOW
|
120
|
+
elsif W_MID.include? w
|
121
|
+
G_MID
|
122
|
+
elsif W_HIGH.include? w
|
123
|
+
G_HIGH
|
124
|
+
elsif W_EXTCODE.include? w
|
125
|
+
G_EXTCODE
|
126
|
+
elsif w == BALANCE
|
127
|
+
G_BALANCE
|
128
|
+
elsif w == BLOCKHASH
|
129
|
+
G_BLOCKHASH
|
130
|
+
else
|
131
|
+
raise "can't compute cost for unknown op #{w}"
|
136
132
|
end
|
133
|
+
end
|
137
134
|
|
138
|
-
|
139
|
-
|
140
|
-
|
135
|
+
def gas_of_memory(i)
|
136
|
+
G_MEMORY * i + (i ** 2) / 512
|
137
|
+
end
|
141
138
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
139
|
+
def intrinsic_gas_of_transaction(t)
|
140
|
+
gas = (t.data.each_byte || '').reduce(0) {|sum, i| sum + (i.zero? ? G_TXDATAZERO : G_TXDATANONZERO)}
|
141
|
+
# gas + (t.to.empty? ? G_TXCREATE : 0) + G_TRANSACTION
|
142
|
+
gas + G_TRANSACTION
|
143
|
+
end
|
147
144
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
145
|
+
def gas_of_call(vm:, gas:, to:, value:)
|
146
|
+
# TODO handle gas calculation for all categories calls
|
147
|
+
account_exists = vm.account_exist?(to)
|
148
|
+
transfer_gas_fee = value > 0 ? G_CALLVALUE : 0
|
149
|
+
create_gas_fee = !account_exists ? G_NEWACCOUNT : 0
|
150
|
+
extra_gas = transfer_gas_fee + create_gas_fee
|
154
151
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
152
|
+
total_fee = gas + extra_gas
|
153
|
+
child_gas_limit = gas + (value > 0 ? G_CALLSTIPEND : 0)
|
154
|
+
[child_gas_limit, total_fee]
|
155
|
+
end
|
159
156
|
|
160
|
-
|
157
|
+
private
|
161
158
|
|
162
|
-
|
163
|
-
|
164
|
-
|
159
|
+
def cost_of_self_destruct(vm)
|
160
|
+
G_SELFDESTRUCT
|
161
|
+
end
|
165
162
|
|
166
|
-
|
167
|
-
|
168
|
-
|
163
|
+
def cost_of_sstore(vm)
|
164
|
+
ms = vm.machine_state
|
165
|
+
instruction = vm.instruction
|
169
166
|
|
170
|
-
|
171
|
-
|
167
|
+
key = ms.get_stack(0, Integer)
|
168
|
+
value = ms.get_stack(1, Integer)
|
172
169
|
|
173
|
-
|
174
|
-
|
170
|
+
current_is_empty = vm.fetch(instruction.address, key).zero?
|
171
|
+
value_is_empty = value.nil? || value.zero?
|
175
172
|
|
176
|
-
|
177
|
-
|
173
|
+
gas_cost = if current_is_empty && !value_is_empty
|
174
|
+
G_SSET
|
175
|
+
else
|
176
|
+
G_RESET
|
177
|
+
end
|
178
|
+
gas_refund = if !current_is_empty && value_is_empty
|
179
|
+
R_SCLEAR
|
178
180
|
else
|
179
|
-
|
181
|
+
0
|
180
182
|
end
|
181
|
-
gas_refund = if !current_is_empty && value_is_empty
|
182
|
-
R_SCLEAR
|
183
|
-
else
|
184
|
-
0
|
185
|
-
end
|
186
|
-
|
187
|
-
[gas_cost, gas_refund]
|
188
|
-
end
|
189
183
|
|
184
|
+
[gas_cost, gas_refund]
|
190
185
|
end
|
186
|
+
|
191
187
|
end
|
192
188
|
|
193
189
|
end
|
@@ -0,0 +1,99 @@
|
|
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/evm/op'
|
19
|
+
|
20
|
+
module Ciri
|
21
|
+
module Forks
|
22
|
+
module Frontier
|
23
|
+
|
24
|
+
include Ciri::EVM::OP
|
25
|
+
|
26
|
+
OPCODES = [
|
27
|
+
STOP,
|
28
|
+
ADD,
|
29
|
+
MUL,
|
30
|
+
SUB,
|
31
|
+
DIV,
|
32
|
+
SDIV,
|
33
|
+
MOD,
|
34
|
+
SMOD,
|
35
|
+
ADDMOD,
|
36
|
+
MULMOD,
|
37
|
+
EXP,
|
38
|
+
SIGNEXTEND,
|
39
|
+
LT,
|
40
|
+
GT,
|
41
|
+
SLT,
|
42
|
+
SGT,
|
43
|
+
EQ,
|
44
|
+
ISZERO,
|
45
|
+
AND,
|
46
|
+
OR,
|
47
|
+
XOR,
|
48
|
+
NOT,
|
49
|
+
BYTE,
|
50
|
+
SHA3,
|
51
|
+
ADDRESS,
|
52
|
+
BALANCE,
|
53
|
+
ORIGIN,
|
54
|
+
CALLER,
|
55
|
+
CALLVALUE,
|
56
|
+
CALLDATALOAD,
|
57
|
+
CALLDATASIZE,
|
58
|
+
CALLDATACOPY,
|
59
|
+
CODESIZE,
|
60
|
+
CODECOPY,
|
61
|
+
GASPRICE,
|
62
|
+
EXTCODESIZE,
|
63
|
+
EXTCODECOPY,
|
64
|
+
BLOCKHASH,
|
65
|
+
COINBASE,
|
66
|
+
TIMESTAMP,
|
67
|
+
NUMBER,
|
68
|
+
DIFFICULTY,
|
69
|
+
GASLIMIT,
|
70
|
+
POP,
|
71
|
+
MLOAD,
|
72
|
+
MSTORE,
|
73
|
+
MSTORE8,
|
74
|
+
SLOAD,
|
75
|
+
SSTORE,
|
76
|
+
JUMP,
|
77
|
+
JUMPI,
|
78
|
+
PC,
|
79
|
+
MSIZE,
|
80
|
+
GAS,
|
81
|
+
JUMPDEST,
|
82
|
+
*(PUSH1..PUSH32),
|
83
|
+
*(DUP1..DUP16),
|
84
|
+
*(SWAP1..SWAP16),
|
85
|
+
*(LOG0..LOG4),
|
86
|
+
CREATE,
|
87
|
+
CALL,
|
88
|
+
CALLCODE,
|
89
|
+
RETURN,
|
90
|
+
INVALID,
|
91
|
+
SELFDESTRUCT,
|
92
|
+
].map do |op|
|
93
|
+
[op, Ciri::EVM::OP.get(op)]
|
94
|
+
end.to_h.freeze
|
95
|
+
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,62 @@
|
|
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/chain/transaction'
|
19
|
+
|
20
|
+
module Ciri
|
21
|
+
module Forks
|
22
|
+
module Frontier
|
23
|
+
class Transaction < Chain::Transaction
|
24
|
+
|
25
|
+
def validate!
|
26
|
+
validate_sender!
|
27
|
+
|
28
|
+
raise InvalidError.new('signature rvs error') unless signature.valid?
|
29
|
+
raise InvalidError.new('gas_price overflow') unless UInt256.valid?(gas_price)
|
30
|
+
raise InvalidError.new('nonce overflow') unless UInt256.valid?(nonce)
|
31
|
+
raise InvalidError.new('gas_limit overflow') unless UInt256.valid?(gas_limit)
|
32
|
+
raise InvalidError.new('value overflow') unless UInt256.valid?(value)
|
33
|
+
|
34
|
+
unless v >= v_min && v <= v_max
|
35
|
+
raise InvalidError.new("v can be only 27 or 28 in frontier schema, found: #{v}")
|
36
|
+
end
|
37
|
+
|
38
|
+
validate_intrinsic_gas!
|
39
|
+
end
|
40
|
+
|
41
|
+
def v_min
|
42
|
+
27
|
43
|
+
end
|
44
|
+
|
45
|
+
def v_max
|
46
|
+
28
|
47
|
+
end
|
48
|
+
|
49
|
+
def validate_intrinsic_gas!
|
50
|
+
begin
|
51
|
+
fork_schema = Schema.new
|
52
|
+
intrinsic_gas = fork_schema.intrinsic_gas_of_transaction(self)
|
53
|
+
rescue StandardError
|
54
|
+
raise InvalidError.new 'intrinsic gas calculation error'
|
55
|
+
end
|
56
|
+
raise InvalidError.new 'intrinsic gas not enough' unless intrinsic_gas <= gas_limit
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/ciri/forks/homestead.rb
CHANGED
@@ -17,27 +17,51 @@
|
|
17
17
|
|
18
18
|
require_relative 'base'
|
19
19
|
require_relative 'frontier'
|
20
|
+
require_relative 'homestead/transaction'
|
21
|
+
require_relative 'homestead/opcodes'
|
20
22
|
|
21
23
|
module Ciri
|
22
24
|
module Forks
|
25
|
+
# Homestead fork
|
26
|
+
# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-606.md
|
23
27
|
module Homestead
|
24
28
|
class Schema < Forks::Frontier::Schema
|
25
29
|
|
26
|
-
include Forks::Frontier
|
30
|
+
include Forks::Frontier
|
27
31
|
|
28
32
|
def initialize(support_dao_fork:)
|
29
33
|
@support_dao_fork = support_dao_fork
|
34
|
+
super()
|
30
35
|
end
|
31
36
|
|
32
37
|
def intrinsic_gas_of_transaction(t)
|
33
|
-
gas = (t.data.each_byte || '').reduce(0) {|sum, i| sum + (i.zero? ? G_TXDATAZERO : G_TXDATANONZERO)}
|
34
|
-
gas + (t.to.empty? ? G_TXCREATE : 0) + G_TRANSACTION
|
38
|
+
gas = (t.data.each_byte || '').reduce(0) {|sum, i| sum + (i.zero? ? Cost::G_TXDATAZERO : Cost::G_TXDATANONZERO)}
|
39
|
+
gas + (t.to.empty? ? Cost::G_TXCREATE : 0) + Cost::G_TRANSACTION
|
35
40
|
end
|
36
41
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
42
|
+
def calculate_difficulty(header, parent_header)
|
43
|
+
# https://github.com/ethereum/EIPs/blob/984cf5de90bbf5fbe7e49be227b0c2f9567e661e/EIPS/eip-2.md
|
44
|
+
difficulty_time_factor = [1 - (header.timestamp - parent_header.timestamp) / 10, -99].max
|
45
|
+
x = parent_header.difficulty / 2048
|
46
|
+
|
47
|
+
# difficulty bomb
|
48
|
+
height = header.number
|
49
|
+
height_factor = 2 ** (height / 100000 - 2)
|
50
|
+
|
51
|
+
difficulty = (parent_header.difficulty + x * difficulty_time_factor + height_factor).to_i
|
52
|
+
[header.difficulty, difficulty].max
|
53
|
+
end
|
54
|
+
|
55
|
+
def transaction_class
|
56
|
+
Transaction
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_operation(op)
|
60
|
+
OPCODES[op]
|
61
|
+
end
|
62
|
+
|
63
|
+
def exception_on_deposit_code_gas_not_enough
|
64
|
+
true
|
41
65
|
end
|
42
66
|
|
43
67
|
end
|
@@ -0,0 +1,37 @@
|
|
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/evm/op'
|
19
|
+
require 'ciri/forks/frontier/opcodes'
|
20
|
+
|
21
|
+
module Ciri
|
22
|
+
module Forks
|
23
|
+
module Homestead
|
24
|
+
|
25
|
+
include Ciri::EVM::OP
|
26
|
+
|
27
|
+
UPDATE_OPCODES = [
|
28
|
+
DELEGATECALL,
|
29
|
+
].map do |op|
|
30
|
+
[op, Ciri::EVM::OP.get(op)]
|
31
|
+
end.to_h.freeze
|
32
|
+
|
33
|
+
OPCODES = Frontier::OPCODES.merge(UPDATE_OPCODES).freeze
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|