ciri 0.0.1 → 0.0.2
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +8 -3
- data/README.md +5 -0
- data/Rakefile +24 -2
- data/ciri-rlp/.gitignore +11 -0
- data/ciri-rlp/.rspec +3 -0
- data/ciri-rlp/.travis.yml +5 -0
- data/ciri-rlp/CODE_OF_CONDUCT.md +74 -0
- data/ciri-rlp/Gemfile +6 -0
- data/ciri-rlp/Gemfile.lock +39 -0
- data/ciri-rlp/LICENSE.txt +21 -0
- data/ciri-rlp/README.md +98 -0
- data/ciri-rlp/Rakefile +6 -0
- data/ciri-rlp/bin/console +14 -0
- data/ciri-rlp/bin/setup +8 -0
- data/ciri-rlp/ciri-rlp.gemspec +28 -0
- data/{lib → ciri-rlp/lib}/ciri/rlp.rb +2 -2
- data/ciri-rlp/lib/ciri/rlp/decode.rb +144 -0
- data/ciri-rlp/lib/ciri/rlp/encode.rb +140 -0
- data/ciri-rlp/lib/ciri/rlp/serializable.rb +241 -0
- data/ciri-rlp/lib/ciri/rlp/version.rb +5 -0
- data/ciri-rlp/spec/ciri/fixture_spec.rb +95 -0
- data/ciri-rlp/spec/ciri/rlp/decode_spec.rb +68 -0
- data/ciri-rlp/spec/ciri/rlp/encode_spec.rb +72 -0
- data/ciri-rlp/spec/ciri/rlp/serializable_spec.rb +147 -0
- data/ciri-rlp/spec/ciri/rlp_spec.rb +5 -0
- data/ciri-rlp/spec/spec_helper.rb +14 -0
- data/ciri-utils/.gitignore +11 -0
- data/ciri-utils/.rspec +3 -0
- data/ciri-utils/.travis.yml +5 -0
- data/ciri-utils/CODE_OF_CONDUCT.md +74 -0
- data/ciri-utils/Gemfile +6 -0
- data/ciri-utils/Gemfile.lock +37 -0
- data/ciri-utils/LICENSE.txt +21 -0
- data/ciri-utils/README.md +61 -0
- data/ciri-utils/Rakefile +6 -0
- data/ciri-utils/bin/console +14 -0
- data/ciri-utils/bin/setup +8 -0
- data/ciri-utils/ciri-utils.gemspec +28 -0
- data/{lib → ciri-utils/lib}/ciri/utils.rb +9 -33
- data/{lib → ciri-utils/lib}/ciri/utils/logger.rb +0 -0
- data/{lib → ciri-utils/lib}/ciri/utils/number.rb +15 -12
- data/ciri-utils/lib/ciri/utils/version.rb +5 -0
- data/ciri-utils/spec/ciri/utils_spec.rb +5 -0
- data/ciri-utils/spec/spec_helper.rb +14 -0
- data/ciri.gemspec +6 -3
- data/lib/ciri/bloom_filter.rb +83 -0
- data/lib/ciri/chain.rb +67 -130
- data/lib/ciri/chain/header.rb +2 -2
- data/lib/ciri/chain/header_chain.rb +136 -0
- data/lib/ciri/chain/transaction.rb +1 -1
- data/lib/ciri/crypto.rb +2 -2
- data/lib/ciri/db/account_db.rb +145 -0
- data/lib/ciri/db/backend/memory.rb +24 -1
- data/lib/ciri/devp2p/peer.rb +1 -1
- data/lib/ciri/devp2p/rlpx/connection.rb +5 -5
- data/lib/ciri/eth/peer.rb +3 -3
- data/lib/ciri/eth/protocol_manage.rb +3 -3
- data/lib/ciri/eth/protocol_messages.rb +27 -26
- data/lib/ciri/ethash.rb +18 -3
- data/lib/ciri/evm.rb +101 -56
- data/lib/ciri/{utils/lib_c.rb → evm/errors.rb} +28 -18
- data/lib/ciri/evm/instruction.rb +3 -1
- data/lib/ciri/evm/{serialize.rb → log_entry.rb} +9 -27
- data/lib/ciri/evm/machine_state.rb +21 -2
- data/lib/ciri/evm/op.rb +19 -16
- data/lib/ciri/evm/state.rb +61 -0
- data/lib/ciri/evm/vm.rb +78 -102
- data/lib/ciri/forks.rb +1 -4
- data/lib/ciri/forks/base.rb +55 -0
- data/lib/ciri/forks/frontier.rb +37 -10
- data/lib/ciri/forks/frontier/cost.rb +186 -0
- data/lib/ciri/key.rb +1 -1
- data/lib/ciri/pow.rb +1 -1
- data/lib/ciri/rlp/decode.rb +6 -3
- data/lib/ciri/rlp/encode.rb +10 -10
- data/lib/ciri/rlp/serializable.rb +12 -9
- data/lib/ciri/serialize.rb +58 -0
- data/lib/ciri/trie.rb +362 -0
- data/lib/ciri/trie/nibbles.rb +97 -0
- data/lib/ciri/trie/nodes.rb +187 -0
- data/lib/ciri/{evm → types}/account.rb +20 -13
- data/lib/ciri/types/address.rb +16 -11
- data/lib/ciri/types/number.rb +73 -0
- data/lib/ciri/types/receipt.rb +57 -0
- data/lib/ciri/version.rb +1 -1
- metadata +82 -19
- data/lib/ciri/evm/forks/frontier.rb +0 -183
data/lib/ciri/forks.rb
CHANGED
@@ -26,12 +26,9 @@ require_relative 'forks/frontier'
|
|
26
26
|
module Ciri
|
27
27
|
module Forks
|
28
28
|
|
29
|
-
# Fork configure
|
30
|
-
ForkConfig = Struct.new(:cost_of_operation, :cost_of_memory, :intrinsic_gas_of_transaction, keyword_init: true)
|
31
|
-
|
32
29
|
def self.detect_fork(header: nil, number: nil)
|
33
30
|
number ||= header.number
|
34
|
-
Frontier.
|
31
|
+
Frontier::Config.new
|
35
32
|
end
|
36
33
|
|
37
34
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2018, by Jiang Jinyang. <https://justjjy.com>
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
13
|
+
# all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
# THE SOFTWARE.
|
22
|
+
|
23
|
+
|
24
|
+
module Ciri
|
25
|
+
module Forks
|
26
|
+
|
27
|
+
class Base
|
28
|
+
# gas methods
|
29
|
+
def gas_of_operation(vm)
|
30
|
+
raise NotImplementedError
|
31
|
+
end
|
32
|
+
|
33
|
+
def gas_of_memory(word_count)
|
34
|
+
raise NotImplementedError
|
35
|
+
end
|
36
|
+
|
37
|
+
def intrinsic_gas_of_transaction(transaction)
|
38
|
+
raise NotImplementedError
|
39
|
+
end
|
40
|
+
|
41
|
+
def calculate_deposit_code_gas(code_bytes)
|
42
|
+
raise NotImplementedError
|
43
|
+
end
|
44
|
+
|
45
|
+
def mining_rewards_of_block(block)
|
46
|
+
raise NotImplementedError
|
47
|
+
end
|
48
|
+
|
49
|
+
def calculate_refund_gas(vm)
|
50
|
+
raise NotImplementedError
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
data/lib/ciri/forks/frontier.rb
CHANGED
@@ -21,23 +21,50 @@
|
|
21
21
|
# THE SOFTWARE.
|
22
22
|
|
23
23
|
|
24
|
-
|
24
|
+
require_relative 'base'
|
25
|
+
require_relative 'frontier/cost'
|
25
26
|
|
26
27
|
module Ciri
|
27
28
|
module Forks
|
28
29
|
module Frontier
|
30
|
+
class Config < Base
|
29
31
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
intrinsic_gas_of_transaction: proc {|t| EVM::Forks::Frontier::Cost.intrinsic_gas_of_transaction t}
|
36
|
-
# transaction_klass: nil
|
37
|
-
)
|
32
|
+
BLOCK_REWARD = 5 * 10.pow(18) # 5 ether
|
33
|
+
|
34
|
+
# gas methods
|
35
|
+
def gas_of_operation(vm)
|
36
|
+
Cost.cost_of_operation vm
|
38
37
|
end
|
39
|
-
end
|
40
38
|
|
39
|
+
def gas_of_memory(word_count)
|
40
|
+
Cost.cost_of_memory word_count
|
41
|
+
end
|
42
|
+
|
43
|
+
def intrinsic_gas_of_transaction(transaction)
|
44
|
+
Cost.intrinsic_gas_of_transaction transaction
|
45
|
+
end
|
46
|
+
|
47
|
+
def calculate_deposit_code_gas(code_bytes)
|
48
|
+
Cost::G_CODEDEPOSIT * (code_bytes || ''.b).size
|
49
|
+
end
|
50
|
+
|
51
|
+
def calculate_refund_gas(vm)
|
52
|
+
vm.sub_state.suicide_accounts.size * Cost::R_SELFDESTRUCT
|
53
|
+
end
|
54
|
+
|
55
|
+
def mining_rewards_of_block(block)
|
56
|
+
rewards = Hash.new(0)
|
57
|
+
# reward miner
|
58
|
+
rewards[block.header.beneficiary] += ((1 + block.ommers.count.to_f / 32) * BLOCK_REWARD).to_i
|
59
|
+
|
60
|
+
# reward ommer(uncle) block miners
|
61
|
+
block.ommers.each do |ommer|
|
62
|
+
rewards[ommer.beneficiary] += ((1 + (ommer.number - block.header.number).to_f / 8) * BLOCK_REWARD).to_i
|
63
|
+
end
|
64
|
+
rewards
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
41
68
|
end
|
42
69
|
end
|
43
70
|
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2018, by Jiang Jinyang. <https://justjjy.com>
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
13
|
+
# all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
# THE SOFTWARE.
|
22
|
+
|
23
|
+
|
24
|
+
require 'ciri/evm/op'
|
25
|
+
|
26
|
+
module Ciri
|
27
|
+
module Forks
|
28
|
+
module Frontier
|
29
|
+
|
30
|
+
module Cost
|
31
|
+
|
32
|
+
include Ciri::EVM::OP
|
33
|
+
|
34
|
+
# fee schedule, start with G
|
35
|
+
G_ZERO = 0
|
36
|
+
G_BASE = 2
|
37
|
+
G_VERYLOW = 3
|
38
|
+
G_LOW = 5
|
39
|
+
G_MID = 8
|
40
|
+
G_HIGH = 10
|
41
|
+
G_EXTCODE = 700
|
42
|
+
G_BALANCE = 400
|
43
|
+
G_SLOAD = 50
|
44
|
+
G_JUMPDEST = 1
|
45
|
+
G_SSET = 20000
|
46
|
+
G_RESET = 5000
|
47
|
+
R_SCLEAR = 15000
|
48
|
+
R_SELFDESTRUCT = 24000
|
49
|
+
G_SELFDESTRUCT = 0
|
50
|
+
G_CREATE = 32000
|
51
|
+
G_CODEDEPOSIT = 200
|
52
|
+
G_CALL = 700
|
53
|
+
G_CALLVALUE = 9000
|
54
|
+
G_CALLSTIPEND = 2300
|
55
|
+
G_NEWACCOUNT = 25000
|
56
|
+
G_EXP = 10
|
57
|
+
G_EXPBYTE = 10
|
58
|
+
G_MEMORY = 3
|
59
|
+
G_TXCREATE = 32000
|
60
|
+
G_TXDATAZERO = 4
|
61
|
+
G_TXDATANONZERO = 68
|
62
|
+
G_TRANSACTION = 21000
|
63
|
+
G_LOG = 375
|
64
|
+
G_LOGDATA = 8
|
65
|
+
G_TOPIC = 375
|
66
|
+
G_SHA3 = 30
|
67
|
+
G_SHA3WORD = 6
|
68
|
+
G_COPY = 3
|
69
|
+
G_BLOCKHASH = 20
|
70
|
+
G_QUADDIVISOR = 100
|
71
|
+
|
72
|
+
# operation code by group, for later calculation
|
73
|
+
W_ZERO = [STOP, RETURN, REVERT]
|
74
|
+
W_BASE = [ADDRESS, ORIGIN, CALLER, CALLVALUE, CALLDATASIZE, CODESIZE, GASPRICE,
|
75
|
+
COINBASE, TIMESTAMP, NUMBER, DIFFICULTY, GASLIMIT, RETURNDATASIZE,
|
76
|
+
POP, PC, MSIZE, GAS]
|
77
|
+
W_VERYLOW = [ADD, SUB, NOT, LT, GT, SLT, SGT, EQ, ISZERO, AND, OR,
|
78
|
+
XOR, BYTE, CALLDATALOAD, MLOAD, MSTORE, MSTORE8,
|
79
|
+
*(1..32).map {|i| EVM::OP.get(PUSH1 + i - 1).code}, # push1 - push32
|
80
|
+
*(1..16).map {|i| EVM::OP.get(DUP1 + i - 1).code}, # dup1 - dup16
|
81
|
+
*(1..16).map {|i| EVM::OP.get(SWAP1 + i - 1).code}] # swap1 - swap16
|
82
|
+
W_LOW = [MUL, DIV, SDIV, MOD, SMOD, SIGNEXTEND]
|
83
|
+
W_MID = [ADDMOD, MULMOD, JUMP]
|
84
|
+
W_HIGH = [JUMPI]
|
85
|
+
W_EXTCODE = [EXTCODESIZE]
|
86
|
+
|
87
|
+
|
88
|
+
class << self
|
89
|
+
include Ciri::EVM::OP
|
90
|
+
|
91
|
+
# C(σ,μ,I)
|
92
|
+
# calculate cost of current operation
|
93
|
+
def cost_of_operation(vm)
|
94
|
+
ms = vm.machine_state
|
95
|
+
instruction = vm.instruction
|
96
|
+
w = instruction.get_op(ms.pc)
|
97
|
+
if w == SSTORE
|
98
|
+
cost_of_sstore(vm)
|
99
|
+
elsif w == EXP && ms.get_stack(1, Integer) == 0
|
100
|
+
G_EXP
|
101
|
+
elsif w == EXP && (x = ms.get_stack(1, Integer)) > 0
|
102
|
+
G_EXP + G_EXPBYTE * Utils.ceil_div(x.bit_length, 8)
|
103
|
+
elsif w == CALLDATACOPY || w == CODECOPY || w == RETURNDATACOPY
|
104
|
+
G_VERYLOW + G_COPY * Utils.ceil_div(ms.get_stack(2, Integer), 32)
|
105
|
+
elsif w == EXTCODECOPY
|
106
|
+
G_EXTCODE + G_COPY * Utils.ceil_div(ms.get_stack(3, Integer), 32)
|
107
|
+
elsif (LOG0..LOG4).include? w
|
108
|
+
G_LOG + G_LOGDATA * ms.get_stack(1, Integer) + (w - LOG0) * G_TOPIC
|
109
|
+
elsif w == CALL || w == CALLCODE || w == DELEGATECALL
|
110
|
+
1 # cost_of_call(state, ms)
|
111
|
+
elsif w == SELFDESTRUCT
|
112
|
+
cost_of_self_destruct(vm)
|
113
|
+
elsif w == CREATE
|
114
|
+
G_CREATE
|
115
|
+
elsif w == SHA3
|
116
|
+
G_SHA3 + G_SHA3WORD * Utils.ceil_div(ms.get_stack(1, Integer), 32)
|
117
|
+
elsif w == JUMPDEST
|
118
|
+
G_JUMPDEST
|
119
|
+
elsif w == SLOAD
|
120
|
+
G_SLOAD
|
121
|
+
elsif W_ZERO.include? w
|
122
|
+
G_ZERO
|
123
|
+
elsif W_BASE.include? w
|
124
|
+
G_BASE
|
125
|
+
elsif W_VERYLOW.include? w
|
126
|
+
G_VERYLOW
|
127
|
+
elsif W_LOW.include? w
|
128
|
+
G_LOW
|
129
|
+
elsif W_MID.include? w
|
130
|
+
G_MID
|
131
|
+
elsif W_HIGH.include? w
|
132
|
+
G_HIGH
|
133
|
+
elsif W_EXTCODE.include? w
|
134
|
+
G_EXTCODE
|
135
|
+
elsif w == BALANCE
|
136
|
+
G_BALANCE
|
137
|
+
elsif w == BLOCKHASH
|
138
|
+
G_BLOCKHASH
|
139
|
+
else
|
140
|
+
raise "can't compute cost for unknown op #{w}"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def cost_of_memory(i)
|
145
|
+
G_MEMORY * i + (i ** 2) / 512
|
146
|
+
end
|
147
|
+
|
148
|
+
def intrinsic_gas_of_transaction(t)
|
149
|
+
gas = (t.data.each_byte || '').reduce(0) {|sum, i| sum + (i.zero? ? G_TXDATAZERO : G_TXDATANONZERO)}
|
150
|
+
# gas + (t.to.empty? ? G_TXCREATE : 0) + G_TRANSACTION
|
151
|
+
gas + G_TRANSACTION
|
152
|
+
end
|
153
|
+
|
154
|
+
private
|
155
|
+
|
156
|
+
def cost_of_self_destruct(vm)
|
157
|
+
G_SELFDESTRUCT
|
158
|
+
end
|
159
|
+
|
160
|
+
def cost_of_call
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
def cost_of_sstore(vm)
|
165
|
+
ms = vm.machine_state
|
166
|
+
instruction = vm.instruction
|
167
|
+
|
168
|
+
key = ms.get_stack(0, Integer)
|
169
|
+
value = ms.get_stack(1, Integer)
|
170
|
+
|
171
|
+
stored_is_empty = vm.fetch(instruction.address, key).zero?
|
172
|
+
value_is_non_zero = value && !value.zero?
|
173
|
+
|
174
|
+
if value_is_non_zero && stored_is_empty
|
175
|
+
G_SSET
|
176
|
+
else
|
177
|
+
G_RESET
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
data/lib/ciri/key.rb
CHANGED
@@ -79,7 +79,7 @@ module Ciri
|
|
79
79
|
privkey = ec_key.private_key.to_s(2)
|
80
80
|
# some times below error will occurs, raise error with more detail
|
81
81
|
unless privkey.instance_of?(String) && privkey.size == 32
|
82
|
-
raise ArgumentError, "privkey must be composed of 32 bytes, #{bytes}: #{privkey.size} privkey: #{Utils.
|
82
|
+
raise ArgumentError, "privkey must be composed of 32 bytes, #{bytes}: #{privkey.size} privkey: #{Utils.to_hex privkey}"
|
83
83
|
end
|
84
84
|
@secp256k1_key ||= Crypto.ensure_secp256k1_key(privkey: privkey)
|
85
85
|
end
|
data/lib/ciri/pow.rb
CHANGED
@@ -68,7 +68,7 @@ module Ciri
|
|
68
68
|
out_mix_hash, out_result = Ethash.hashimoto_light(block_number, cache, mining_hash, Utils.big_endian_decode(nonce_bytes))
|
69
69
|
|
70
70
|
if out_mix_hash != mix_hash
|
71
|
-
raise InvalidError.new("mix hash mismatch; #{Utils.
|
71
|
+
raise InvalidError.new("mix hash mismatch; #{Utils.to_hex(out_mix_hash)} != #{Utils.to_hex(mix_hash)}")
|
72
72
|
end
|
73
73
|
|
74
74
|
result = Utils.big_endian_decode(out_result)
|
data/lib/ciri/rlp/decode.rb
CHANGED
@@ -68,12 +68,15 @@ module Ciri
|
|
68
68
|
else
|
69
69
|
raise InvalidValueError.new "invalid bool value #{item}"
|
70
70
|
end
|
71
|
-
elsif type.is_a?(Class) && type
|
72
|
-
type.rlp_decode
|
71
|
+
elsif type.is_a?(Class) && type.respond_to?(:rlp_decode)
|
72
|
+
type.rlp_decode(s)
|
73
73
|
elsif type.is_a?(Array)
|
74
74
|
decode_list(s) do |list, s2|
|
75
|
+
i = 0
|
75
76
|
until s2.eof?
|
76
|
-
|
77
|
+
t = type.size > i ? type[i] : type[-1]
|
78
|
+
list << decode_with_type(s2, t)
|
79
|
+
i += 1
|
77
80
|
end
|
78
81
|
end
|
79
82
|
elsif type == Raw
|
data/lib/ciri/rlp/encode.rb
CHANGED
@@ -28,25 +28,25 @@ module Ciri
|
|
28
28
|
class InputOverflow < StandardError
|
29
29
|
end
|
30
30
|
|
31
|
-
# Encode input to rlp encoding
|
31
|
+
# Encode input to rlp encoding
|
32
32
|
#
|
33
33
|
# Examples:
|
34
34
|
#
|
35
35
|
# Ciri::RLP.encode("hello world")
|
36
36
|
#
|
37
|
-
def encode(input, type =
|
38
|
-
encode_with_type(input, type)
|
37
|
+
def encode(input, type = nil)
|
38
|
+
type ? encode_with_type(input, type) : encode_simple(input)
|
39
39
|
end
|
40
40
|
|
41
41
|
def encode_simple(input)
|
42
42
|
if input.is_a?(Array)
|
43
43
|
encode_list(input) {|i| encode_simple(i)}
|
44
44
|
elsif input.is_a?(Integer)
|
45
|
-
|
46
|
-
elsif input.
|
47
|
-
input.rlp_encode
|
45
|
+
encode_with_type(input, Integer)
|
46
|
+
elsif input.class.respond_to?(:rlp_encode)
|
47
|
+
input.class.rlp_encode(input)
|
48
48
|
else
|
49
|
-
|
49
|
+
encode_with_type(input, Raw)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
@@ -70,8 +70,8 @@ module Ciri
|
|
70
70
|
end
|
71
71
|
elsif type == Bool
|
72
72
|
item ? Bool::ENCODED_TRUE : Bool::ENCODED_FALSE
|
73
|
-
elsif type.is_a?(Class) && type
|
74
|
-
|
73
|
+
elsif type.is_a?(Class) && type.respond_to?(:rlp_encode)
|
74
|
+
type.rlp_encode(item)
|
75
75
|
elsif type.is_a?(Array)
|
76
76
|
if type.size == 1 # array type
|
77
77
|
encode_list(item) {|i| encode_with_type(i, type[0])}
|
@@ -84,7 +84,7 @@ module Ciri
|
|
84
84
|
raise RLP::InvalidValueError.new "unknown type #{type}"
|
85
85
|
end
|
86
86
|
rescue
|
87
|
-
STDERR.puts "when encoding #{Utils.
|
87
|
+
STDERR.puts "when encoding #{Utils.to_hex item.to_s} into #{type}"
|
88
88
|
raise
|
89
89
|
end
|
90
90
|
|
@@ -69,8 +69,8 @@ module Ciri
|
|
69
69
|
# end
|
70
70
|
#
|
71
71
|
# msg = AuthMsgV4.new(signature: "\x00", initiator_pubkey: my_pubkey, nonce: [1, 2, 3], version: 4)
|
72
|
-
# encoded = msg.rlp_encode
|
73
|
-
# msg2 = AuthMsgV4.rlp_decode
|
72
|
+
# encoded = msg.rlp_encode
|
73
|
+
# msg2 = AuthMsgV4.rlp_decode(encoded)
|
74
74
|
# msg == msg2 # true
|
75
75
|
#
|
76
76
|
module Serializable
|
@@ -125,7 +125,7 @@ module Ciri
|
|
125
125
|
end
|
126
126
|
end
|
127
127
|
|
128
|
-
def rlp_encode
|
128
|
+
def rlp_encode(data, skip_keys: nil, white_list_keys: nil)
|
129
129
|
# pre-encode, encode data to rlp compatible format(only string or array)
|
130
130
|
used_keys = if white_list_keys
|
131
131
|
white_list_keys
|
@@ -143,7 +143,7 @@ module Ciri
|
|
143
143
|
encode_list(data_list)
|
144
144
|
end
|
145
145
|
|
146
|
-
def rlp_decode
|
146
|
+
def rlp_decode(input)
|
147
147
|
values = decode_list(input) do |list, stream|
|
148
148
|
keys.each do |key|
|
149
149
|
# decode data by type
|
@@ -159,7 +159,7 @@ module Ciri
|
|
159
159
|
|
160
160
|
def check_key_type(type)
|
161
161
|
return true if TYPES.key?(type)
|
162
|
-
return true if type.is_a?(Class) && type
|
162
|
+
return true if type.is_a?(Class) && type.respond_to?(:rlp_decode) && type.respond_to?(:rlp_encode)
|
163
163
|
|
164
164
|
if type.is_a?(Array) && type.size == 1
|
165
165
|
check_key_type(type[0])
|
@@ -172,11 +172,14 @@ module Ciri
|
|
172
172
|
module ClassMethods
|
173
173
|
# Decode object from input
|
174
174
|
def rlp_decode(input)
|
175
|
-
data = schema.rlp_decode
|
175
|
+
data = schema.rlp_decode(input)
|
176
176
|
self.new(data)
|
177
177
|
end
|
178
178
|
|
179
|
-
|
179
|
+
# Encode object to rlp encoding string
|
180
|
+
def rlp_encode(item, skip_keys: nil, white_list_keys: nil)
|
181
|
+
schema.rlp_encode(item.serializable_attributes, skip_keys: skip_keys, white_list_keys: white_list_keys)
|
182
|
+
end
|
180
183
|
|
181
184
|
def schema(data_schema = nil)
|
182
185
|
@data_schema ||= Schema.new(data_schema).tap do |schema|
|
@@ -225,8 +228,8 @@ module Ciri
|
|
225
228
|
end
|
226
229
|
|
227
230
|
# Encode object to rlp encoding string
|
228
|
-
def rlp_encode
|
229
|
-
self.class.
|
231
|
+
def rlp_encode(skip_keys: nil, white_list_keys: nil)
|
232
|
+
self.class.rlp_encode(self, skip_keys: skip_keys, white_list_keys: white_list_keys)
|
230
233
|
end
|
231
234
|
|
232
235
|
def ==(other)
|