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.
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