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