ciri 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -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::
|
65
|
+
raise Ciri::RLP::InvalidError, "not invalid encoding"
|
66
66
|
end
|
67
|
-
}.to raise_error(Ciri::RLP::
|
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
|
data/ciri-utils/Gemfile.lock
CHANGED
data/ciri.gemspec
CHANGED
@@ -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
|
12
|
-
spec.description = %q{
|
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.
|
25
|
-
spec.add_dependency 'ciri-rlp', '~> 0.
|
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'
|
data/lib/ciri/chain/header.rb
CHANGED
@@ -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
|
25
|
+
include RLP::Serializable
|
24
26
|
|
25
27
|
schema [
|
26
|
-
:
|
27
|
-
:
|
28
|
-
:
|
29
|
-
:
|
30
|
-
:
|
31
|
-
:
|
32
|
-
:
|
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
|
-
:
|
39
|
-
:
|
40
|
-
:
|
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
|
-
|
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!
|
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?
|
data/lib/ciri/db/account_db.rb
CHANGED
@@ -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
|
51
|
+
def_delegators :db, :[], :[]=, :fetch, :delete, :include?
|
55
52
|
|
56
53
|
def get(key)
|
57
|
-
|
54
|
+
db[key]
|
58
55
|
end
|
59
56
|
|
60
57
|
def put(key, value)
|
61
|
-
|
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
|
-
|
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)
|
data/lib/ciri/evm.rb
CHANGED
@@ -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
|
-
|
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, :
|
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
|
78
|
+
def revert_sub_state
|
75
79
|
@sub_state = SubState::EMPTY
|
76
80
|
end
|
77
81
|
|
data/lib/ciri/evm/instruction.rb
CHANGED
data/lib/ciri/evm/op.rb
CHANGED
@@ -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
|
-
|
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,
|
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
|
-
|
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
|