ciri 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -2
  3. data/Gemfile.lock +6 -6
  4. data/README.md +68 -48
  5. data/Rakefile +16 -11
  6. data/ciri-crypto/lib/ciri/crypto/signature.rb +7 -5
  7. data/ciri-rlp/ciri-rlp.gemspec +1 -1
  8. data/ciri-rlp/lib/ciri/rlp.rb +1 -1
  9. data/ciri-rlp/lib/ciri/rlp/decode.rb +23 -7
  10. data/ciri-rlp/lib/ciri/rlp/encode.rb +8 -2
  11. data/ciri-rlp/lib/ciri/rlp/serializable.rb +14 -4
  12. data/ciri-rlp/lib/ciri/rlp/version.rb +1 -1
  13. data/ciri-rlp/spec/ciri/fixture_spec.rb +2 -2
  14. data/ciri-utils/Gemfile.lock +1 -1
  15. data/ciri-utils/lib/ciri/utils/version.rb +1 -1
  16. data/ciri.gemspec +4 -4
  17. data/lib/ciri/chain/header.rb +13 -11
  18. data/lib/ciri/chain/header_chain.rb +1 -10
  19. data/lib/ciri/chain/transaction.rb +5 -23
  20. data/lib/ciri/db/account_db.rb +0 -4
  21. data/lib/ciri/db/backend/errors.rb +27 -0
  22. data/lib/ciri/db/backend/memory.rb +10 -12
  23. data/lib/ciri/db/backend/rocks.rb +13 -6
  24. data/lib/ciri/db/backend/rocks_db.rb +4 -0
  25. data/lib/ciri/evm.rb +6 -1
  26. data/lib/ciri/evm/execution_context.rb +6 -2
  27. data/lib/ciri/evm/instruction.rb +0 -1
  28. data/lib/ciri/evm/op.rb +11 -5
  29. data/lib/ciri/evm/op/errors.rb +37 -0
  30. data/lib/ciri/evm/state.rb +1 -1
  31. data/lib/ciri/evm/sub_state.rb +6 -6
  32. data/lib/ciri/evm/vm.rb +53 -33
  33. data/lib/ciri/forks.rb +4 -0
  34. data/lib/ciri/forks/base.rb +28 -0
  35. data/lib/ciri/forks/byzantium.rb +45 -11
  36. data/lib/ciri/forks/byzantium/opcodes.rb +37 -0
  37. data/lib/ciri/forks/constantinople.rb +29 -0
  38. data/lib/ciri/forks/frontier.rb +49 -29
  39. data/lib/ciri/forks/frontier/cost.rb +91 -95
  40. data/lib/ciri/forks/frontier/opcodes.rb +99 -0
  41. data/lib/ciri/forks/frontier/transaction.rb +62 -0
  42. data/lib/ciri/forks/homestead.rb +31 -7
  43. data/lib/ciri/forks/homestead/opcodes.rb +37 -0
  44. data/lib/ciri/forks/homestead/transaction.rb +43 -0
  45. data/lib/ciri/forks/spurious_dragon.rb +55 -0
  46. data/lib/ciri/forks/spurious_dragon/cost.rb +91 -0
  47. data/lib/ciri/forks/spurious_dragon/transaction.rb +44 -0
  48. data/lib/ciri/forks/tangerine_whistle.rb +37 -0
  49. data/lib/ciri/forks/tangerine_whistle/cost.rb +98 -0
  50. data/lib/ciri/rlp/decode.rb +4 -4
  51. data/lib/ciri/rlp/encode.rb +2 -2
  52. data/lib/ciri/version.rb +1 -1
  53. metadata +22 -10
  54. 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
- module Cost
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
- class << self
83
- include Ciri::EVM::OP
84
-
85
- # C(σ,μ,I)
86
- # calculate cost of current operation
87
- def cost_of_operation(vm)
88
- ms = vm.machine_state
89
- instruction = vm.instruction
90
- w = instruction.get_op(vm.pc)
91
- if w == SSTORE
92
- cost_of_sstore(vm)
93
- elsif w == EXP && ms.get_stack(1, Integer) == 0
94
- G_EXP
95
- elsif w == EXP && (x = ms.get_stack(1, Integer)) > 0
96
- G_EXP + G_EXPBYTE * Utils.ceil_div(x.bit_length, 8)
97
- elsif w == CALLDATACOPY || w == CODECOPY || w == RETURNDATACOPY
98
- G_VERYLOW + G_COPY * Utils.ceil_div(ms.get_stack(2, Integer), 32)
99
- elsif w == EXTCODECOPY
100
- G_EXTCODE + G_COPY * Utils.ceil_div(ms.get_stack(3, Integer), 32)
101
- elsif (LOG0..LOG4).include? w
102
- G_LOG + G_LOGDATA * ms.get_stack(1, Integer) + (w - LOG0) * G_TOPIC
103
- elsif w == CALL || w == CALLCODE || w == DELEGATECALL
104
- G_CALL
105
- elsif w == SELFDESTRUCT
106
- cost_of_self_destruct(vm)
107
- elsif w == CREATE
108
- G_CREATE
109
- elsif w == SHA3
110
- G_SHA3 + G_SHA3WORD * Utils.ceil_div(ms.get_stack(1, Integer), 32)
111
- elsif w == JUMPDEST
112
- G_JUMPDEST
113
- elsif w == SLOAD
114
- G_SLOAD
115
- elsif W_ZERO.include? w
116
- G_ZERO
117
- elsif W_BASE.include? w
118
- G_BASE
119
- elsif W_VERYLOW.include? w
120
- G_VERYLOW
121
- elsif W_LOW.include? w
122
- G_LOW
123
- elsif W_MID.include? w
124
- G_MID
125
- elsif W_HIGH.include? w
126
- G_HIGH
127
- elsif W_EXTCODE.include? w
128
- G_EXTCODE
129
- elsif w == BALANCE
130
- G_BALANCE
131
- elsif w == BLOCKHASH
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
- def cost_of_memory(i)
139
- G_MEMORY * i + (i ** 2) / 512
140
- end
135
+ def gas_of_memory(i)
136
+ G_MEMORY * i + (i ** 2) / 512
137
+ end
141
138
 
142
- def intrinsic_gas_of_transaction(t)
143
- gas = (t.data.each_byte || '').reduce(0) {|sum, i| sum + (i.zero? ? G_TXDATAZERO : G_TXDATANONZERO)}
144
- # gas + (t.to.empty? ? G_TXCREATE : 0) + G_TRANSACTION
145
- gas + G_TRANSACTION
146
- end
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
- def gas_of_call(vm:, gas:, to:, value:)
149
- # TODO handle gas calculation for all categories calls
150
- account_exists = vm.account_exist?(to)
151
- transfer_gas_fee = value > 0 ? G_CALLVALUE : 0
152
- create_gas_fee = !account_exists ? G_NEWACCOUNT : 0
153
- extra_gas = transfer_gas_fee + create_gas_fee
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
- total_fee = gas + extra_gas
156
- child_gas_limit = gas + (value > 0 ? G_CALLSTIPEND : 0)
157
- [child_gas_limit, total_fee]
158
- end
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
- private
157
+ private
161
158
 
162
- def cost_of_self_destruct(vm)
163
- G_SELFDESTRUCT
164
- end
159
+ def cost_of_self_destruct(vm)
160
+ G_SELFDESTRUCT
161
+ end
165
162
 
166
- def cost_of_sstore(vm)
167
- ms = vm.machine_state
168
- instruction = vm.instruction
163
+ def cost_of_sstore(vm)
164
+ ms = vm.machine_state
165
+ instruction = vm.instruction
169
166
 
170
- key = ms.get_stack(0, Integer)
171
- value = ms.get_stack(1, Integer)
167
+ key = ms.get_stack(0, Integer)
168
+ value = ms.get_stack(1, Integer)
172
169
 
173
- current_is_empty = vm.fetch(instruction.address, key).zero?
174
- value_is_empty = value.nil? || value.zero?
170
+ current_is_empty = vm.fetch(instruction.address, key).zero?
171
+ value_is_empty = value.nil? || value.zero?
175
172
 
176
- gas_cost = if current_is_empty && !value_is_empty
177
- G_SSET
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
- G_RESET
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
@@ -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::Cost
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
- # chain difficulty method
38
- # https://github.com/ethereum/EIPs/blob/984cf5de90bbf5fbe7e49be227b0c2f9567e661e/EIPS/eip-2.md
39
- def difficulty_time_factor(header, parent_header)
40
- [1 - (header.timestamp - parent_header.timestamp) / 10, -99].max
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