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
@@ -1,5 +1,5 @@
1
1
  module Ciri
2
2
  module RLP
3
- VERSION = "0.1.1"
3
+ VERSION = "0.2.1"
4
4
  end
5
5
  end
@@ -62,9 +62,9 @@ RSpec.describe Ciri::RLP do
62
62
  expect {
63
63
  rlp_decoded = Ciri::RLP.decode(Ciri::Utils.to_bytes out_value)
64
64
  if Ciri::Utils.to_hex(Ciri::RLP.encode(rlp_decoded)) != out_value
65
- raise Ciri::RLP::InvalidValueError, "not invalid encoding"
65
+ raise Ciri::RLP::InvalidError, "not invalid encoding"
66
66
  end
67
- }.to raise_error(Ciri::RLP::InvalidValueError)
67
+ }.to raise_error(Ciri::RLP::InvalidError)
68
68
  elsif in_value == 'VALID'
69
69
  expect {Ciri::RLP.decode(Ciri::Utils.to_bytes out_value)}.to_not raise_error
70
70
  else
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ciri-utils (0.2.0)
4
+ ciri-utils (0.2.1)
5
5
  digest-sha3 (~> 1.1.0)
6
6
 
7
7
  GEM
@@ -1,5 +1,5 @@
1
1
  module Ciri
2
2
  module Utils
3
- VERSION = "0.2.0"
3
+ VERSION = "0.2.1"
4
4
  end
5
5
  end
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ["Jiang Jinyang"]
9
9
  spec.email = ["jjyruby@gmail.com"]
10
10
 
11
- spec.summary = %q{Ciri project intent to implement a full feature set Ethereum client.}
12
- spec.description = %q{Ciri aims to be a feature complete, long maintained and stable Ethereum client.}
11
+ spec.summary = %q{Ciri is an ongoing Ethereum implementation.}
12
+ spec.description = %q{It aims to be a feature complete Ethereum implementation and expects to achieve both research-friendly and high-performance.}
13
13
  spec.homepage = "https://github.com/ciri-ethereum/ciri"
14
14
  spec.license = "Apache 2.0"
15
15
 
@@ -21,8 +21,8 @@ Gem::Specification.new do |spec|
21
21
  spec.require_paths = ["lib"]
22
22
 
23
23
  # components
24
- spec.add_dependency 'ciri-utils', '~> 0.2.0'
25
- spec.add_dependency 'ciri-rlp', '~> 0.1.1'
24
+ spec.add_dependency 'ciri-utils', '~> 0.2.1'
25
+ spec.add_dependency 'ciri-rlp', '~> 0.2.1'
26
26
  spec.add_dependency 'ciri-crypto', '~> 0.1.1'
27
27
 
28
28
  spec.add_dependency 'ffi', '~> 1.9.23'
@@ -15,29 +15,31 @@
15
15
  # limitations under the License.
16
16
 
17
17
 
18
+ require 'ciri/rlp'
19
+
18
20
  module Ciri
19
21
  class Chain
20
22
 
21
23
  # block header
22
24
  class Header
23
- include Ciri::RLP::Serializable
25
+ include RLP::Serializable
24
26
 
25
27
  schema [
26
- :parent_hash,
27
- :ommers_hash,
28
- :beneficiary,
29
- :state_root,
30
- :transactions_root,
31
- :receipts_root,
32
- :logs_bloom,
28
+ {parent_hash: RLP::RawString},
29
+ {ommers_hash: RLP::RawString},
30
+ {beneficiary: RLP::RawString},
31
+ {state_root: RLP::RawString},
32
+ {transactions_root: RLP::RawString},
33
+ {receipts_root: RLP::RawString},
34
+ {logs_bloom: RLP::RawString},
33
35
  {difficulty: Integer},
34
36
  {number: Integer},
35
37
  {gas_limit: Integer},
36
38
  {gas_used: Integer},
37
39
  {timestamp: Integer},
38
- :extra_data,
39
- :mix_hash,
40
- :nonce,
40
+ {extra_data: RLP::RawString},
41
+ {mix_hash: RLP::RawString},
42
+ {nonce: RLP::RawString},
41
43
  ]
42
44
 
43
45
  # header hash
@@ -71,16 +71,7 @@ module Ciri
71
71
  return header.difficulty if header.number == 0
72
72
 
73
73
  fork_schema = @fork_config.choose_fork(header.number)
74
- difficulty_time_factor = fork_schema.difficulty_time_factor(header, parent_header)
75
-
76
- x = parent_header.difficulty / 2048
77
-
78
- # difficulty bomb
79
- height = fork_schema.difficulty_virtual_height(header.number)
80
- height_factor = 2 ** (height / 100000 - 2)
81
-
82
- difficulty = (parent_header.difficulty + x * difficulty_time_factor + height_factor).to_i
83
- [header.difficulty, difficulty].max
74
+ fork_schema.calculate_difficulty(header, parent_header)
84
75
  end
85
76
 
86
77
  # write header
@@ -99,7 +99,11 @@ module Ciri
99
99
  end
100
100
 
101
101
  # validate transaction
102
- def validate!(fork_schema: nil)
102
+ def validate!
103
+ raise NotImplementedError
104
+ end
105
+
106
+ def validate_sender!
103
107
  begin
104
108
  sender
105
109
  rescue Ciri::Crypto::ECDSASignatureError => e
@@ -107,30 +111,8 @@ module Ciri
107
111
  rescue Ciri::Types::Errors::InvalidError => e
108
112
  raise InvalidError.new(e.to_s)
109
113
  end
110
-
111
- raise InvalidError.new('signature rvs error') unless signature.valid?
112
- # raise InvalidError.new('signature s is low') unless signature.low_s?
113
- raise InvalidError.new('gas_price overflow') unless UInt256.valid?(gas_price)
114
- raise InvalidError.new('nonce overflow') unless UInt256.valid?(nonce)
115
- raise InvalidError.new('gas_limit overflow') unless UInt256.valid?(gas_limit)
116
- raise InvalidError.new('value overflow') unless UInt256.valid?(value)
117
-
118
- if fork_schema
119
- if (reason = fork_schema.validate_transaction(self))
120
- raise InvalidError.new(reason)
121
- end
122
-
123
- begin
124
- intrinsic_gas = fork_schema.intrinsic_gas_of_transaction(self)
125
- rescue StandardError
126
- raise InvalidError.new 'intrinsic gas calculation error'
127
- end
128
- raise InvalidError.new 'intrinsic gas not enough' unless intrinsic_gas <= gas_limit
129
- end
130
114
  end
131
115
 
132
- private
133
-
134
116
  # return chain_id by v
135
117
  def chain_id
136
118
  if eip_155_signed_transaction?
@@ -103,10 +103,6 @@ module Ciri
103
103
  db[find_account(address).code_hash] || ''.b
104
104
  end
105
105
 
106
- def touch_account(address)
107
- update_account(address, find_account(address))
108
- end
109
-
110
106
  def find_account(address)
111
107
  rlp_encoded_account = @trie[convert_key address]
112
108
  if rlp_encoded_account.nil? || rlp_encoded_account.size == 0
@@ -0,0 +1,27 @@
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
+ module Ciri
19
+ module DB
20
+ module Backend
21
+
22
+ class InvalidError < StandardError
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -15,8 +15,8 @@
15
15
  # limitations under the License.
16
16
 
17
17
 
18
- require_relative 'rocks_db'
19
18
  require 'forwardable'
19
+ require_relative 'errors'
20
20
 
21
21
  module Ciri
22
22
  module DB
@@ -37,9 +37,6 @@ module Ciri
37
37
  end
38
38
  end
39
39
 
40
- class InvalidError < StandardError
41
- end
42
-
43
40
  extend Forwardable
44
41
 
45
42
  def initialize
@@ -51,24 +48,20 @@ module Ciri
51
48
  @db = orig.instance_variable_get(:@db).dup
52
49
  end
53
50
 
54
- def_delegators :@db, :[], :[]=, :fetch, :delete, :include?
51
+ def_delegators :db, :[], :[]=, :fetch, :delete, :include?
55
52
 
56
53
  def get(key)
57
- @db[key]
54
+ db[key]
58
55
  end
59
56
 
60
57
  def put(key, value)
61
- @db[key] = value
62
- end
63
-
64
- def each(&blk)
65
- keys.each(&blk)
58
+ db[key] = value
66
59
  end
67
60
 
68
61
  def batch
69
62
  b = Batch.new
70
63
  yield(b)
71
- @db.merge! b.value
64
+ db.merge! b.value
72
65
  end
73
66
 
74
67
  def close
@@ -79,6 +72,11 @@ module Ciri
79
72
  @db.nil?
80
73
  end
81
74
 
75
+ private
76
+ def db
77
+ @db || raise(InvalidError.new 'db is closed')
78
+ end
79
+
82
80
  end
83
81
  end
84
82
  end
@@ -15,8 +15,9 @@
15
15
  # limitations under the License.
16
16
 
17
17
 
18
- require_relative 'rocks_db'
19
18
  require 'forwardable'
19
+ require_relative 'rocks_db'
20
+ require_relative 'errors'
20
21
 
21
22
  module Ciri
22
23
  module DB
@@ -24,17 +25,23 @@ module Ciri
24
25
 
25
26
  # implement kvstore
26
27
  class Rocks
27
-
28
- class InvalidError < StandardError
29
- end
30
-
31
28
  extend Forwardable
32
29
 
33
30
  def initialize(path)
34
31
  @db = RocksDB::DB.new(path)
35
32
  end
36
33
 
37
- def_delegators :db, :get, :put, :[], :[]=
34
+ def_delegators :db, :get, :put, :[], :[]=, :delete
35
+
36
+ def fetch(key)
37
+ value = self[key]
38
+ raise KeyError.new("key not found: #{key.inspect}") if value.nil?
39
+ value
40
+ end
41
+
42
+ def include?(key)
43
+ !self[key].nil?
44
+ end
38
45
 
39
46
  def each(&blk)
40
47
  inter_each(only_key: false, &blk)
@@ -237,6 +237,10 @@ module Ciri
237
237
 
238
238
  alias []= put
239
239
 
240
+ def delete(key)
241
+ RocksDBLib.delete(@db, @writeoptions, key)
242
+ end
243
+
240
244
  def new_iterator
241
245
  Iterator.new(@db, @readoptions)
242
246
  end
@@ -66,7 +66,8 @@ module Ciri
66
66
  raise InvalidTransition.new("overflow header gas_used, total_gas_used: #{total_gas_used}, block gas_used: #{block.header.gas_used}")
67
67
  end
68
68
 
69
- receipts << Types::Receipt.new(state_root: result.state_root, gas_used: total_gas_used, logs: result.logs)
69
+ receipt = fork_schema.make_receipt(execution_result: result, gas_used: total_gas_used)
70
+ receipts << receipt
70
71
  end
71
72
 
72
73
  if check_gas_used && total_gas_used != block.header.gas_used
@@ -162,6 +163,10 @@ module Ciri
162
163
  miner_account.balance += fee
163
164
  state.set_balance(block_info.coinbase, miner_account.balance)
164
165
 
166
+ # EIP158 fork, we need to delete miner account if account become empty
167
+ vm.sub_state.add_touched_account(block_info.coinbase)
168
+ vm.delete_empty_accounts
169
+
165
170
  # destroy accounts
166
171
  vm.execution_context.all_suicide_accounts.each do |address|
167
172
  state.set_balance(address, 0)
@@ -24,7 +24,7 @@ module Ciri
24
24
 
25
25
  include Utils::Logger
26
26
 
27
- attr_accessor :instruction, :depth, :pc, :output, :exception, :gas_limit, :block_info, :sub_state, :fork_schema
27
+ attr_accessor :instruction, :depth, :pc, :exception, :gas_limit, :block_info, :sub_state, :fork_schema
28
28
  attr_reader :children, :remain_gas, :machine_state
29
29
 
30
30
  def initialize(instruction:, depth: 0, gas_limit:, remain_gas: gas_limit, fork_schema:, pc: 0,
@@ -67,11 +67,15 @@ module Ciri
67
67
  @output ||= output
68
68
  end
69
69
 
70
+ def output
71
+ @output || ''.b
72
+ end
73
+
70
74
  def set_pc(pc)
71
75
  @pc = pc
72
76
  end
73
77
 
74
- def revert
78
+ def revert_sub_state
75
79
  @sub_state = SubState::EMPTY
76
80
  end
77
81
 
@@ -32,7 +32,6 @@ module Ciri
32
32
  def get_op(pos)
33
33
  code_size = (bytes_code || ''.b).size
34
34
  return OP::STOP if pos >= code_size
35
- # return OP::INVALID if pos >= code_size
36
35
  bytes_code[pos].ord
37
36
  end
38
37
 
@@ -19,6 +19,7 @@ require 'ciri/utils'
19
19
  require 'ciri/utils/number'
20
20
  require 'ciri/types/address'
21
21
  require_relative 'op_call'
22
+ require_relative 'op/errors'
22
23
 
23
24
  module Ciri
24
25
  class EVM
@@ -446,8 +447,12 @@ module Ciri
446
447
  init = vm.memory_fetch(mem_pos, size)
447
448
  create_gas = vm.remain_gas
448
449
  vm.consume_gas(create_gas)
450
+
449
451
  child_context = vm.execution_context.child_context(gas_limit: create_gas)
450
- contract_address, _ = vm.create_contract(value: value, init: init, touch_nonce: true, context: child_context)
452
+ child_context.instruction.value = value
453
+ child_context.instruction.bytes_code = init
454
+
455
+ contract_address, _ = vm.create_contract(context: child_context)
451
456
  vm.execution_context.return_gas(child_context.remain_gas)
452
457
 
453
458
  vm.push contract_address
@@ -468,17 +473,18 @@ module Ciri
468
473
  vm.set_output vm.memory_fetch(index, size)
469
474
  end
470
475
 
471
- def_op :DELEGATECALL, -0xf4, 6, 1 do |vm|
476
+ def_op :DELEGATECALL, 0xf4, 6, 1 do |vm|
472
477
  OPCall::DelegateCall.new.call(vm)
473
478
  end
474
479
 
475
480
  STATICCALL = 0xfa
476
481
 
477
- # TODO REVERT need to be implement in forks
478
- def_op :REVERT, -0xfd, 2, 0 do |vm|
482
+ def_op :REVERT, 0xfd, 2, 0 do |vm|
479
483
  index, size = vm.pop_list(2, Integer)
480
- vm.output = vm.memory_fetch(index, size)
481
484
  vm.extend_memory(index, size)
485
+ output = vm.memory_fetch(index, size)
486
+ vm.set_exception RevertError.new
487
+ vm.set_output output
482
488
  end
483
489
 
484
490
  def_op :INVALID, 0xfe, 0, 0 do |vm|
@@ -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
+ module Ciri
19
+ class EVM
20
+ module OP
21
+
22
+ class OPError < StandardError
23
+ end
24
+
25
+ class RevertError < OPError
26
+ def set_output(output)
27
+ @output = output
28
+ end
29
+
30
+ def output
31
+ @output || ''.b
32
+ end
33
+ end
34
+
35
+ end
36
+ end
37
+ end