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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +8 -3
  3. data/README.md +5 -0
  4. data/Rakefile +24 -2
  5. data/ciri-rlp/.gitignore +11 -0
  6. data/ciri-rlp/.rspec +3 -0
  7. data/ciri-rlp/.travis.yml +5 -0
  8. data/ciri-rlp/CODE_OF_CONDUCT.md +74 -0
  9. data/ciri-rlp/Gemfile +6 -0
  10. data/ciri-rlp/Gemfile.lock +39 -0
  11. data/ciri-rlp/LICENSE.txt +21 -0
  12. data/ciri-rlp/README.md +98 -0
  13. data/ciri-rlp/Rakefile +6 -0
  14. data/ciri-rlp/bin/console +14 -0
  15. data/ciri-rlp/bin/setup +8 -0
  16. data/ciri-rlp/ciri-rlp.gemspec +28 -0
  17. data/{lib → ciri-rlp/lib}/ciri/rlp.rb +2 -2
  18. data/ciri-rlp/lib/ciri/rlp/decode.rb +144 -0
  19. data/ciri-rlp/lib/ciri/rlp/encode.rb +140 -0
  20. data/ciri-rlp/lib/ciri/rlp/serializable.rb +241 -0
  21. data/ciri-rlp/lib/ciri/rlp/version.rb +5 -0
  22. data/ciri-rlp/spec/ciri/fixture_spec.rb +95 -0
  23. data/ciri-rlp/spec/ciri/rlp/decode_spec.rb +68 -0
  24. data/ciri-rlp/spec/ciri/rlp/encode_spec.rb +72 -0
  25. data/ciri-rlp/spec/ciri/rlp/serializable_spec.rb +147 -0
  26. data/ciri-rlp/spec/ciri/rlp_spec.rb +5 -0
  27. data/ciri-rlp/spec/spec_helper.rb +14 -0
  28. data/ciri-utils/.gitignore +11 -0
  29. data/ciri-utils/.rspec +3 -0
  30. data/ciri-utils/.travis.yml +5 -0
  31. data/ciri-utils/CODE_OF_CONDUCT.md +74 -0
  32. data/ciri-utils/Gemfile +6 -0
  33. data/ciri-utils/Gemfile.lock +37 -0
  34. data/ciri-utils/LICENSE.txt +21 -0
  35. data/ciri-utils/README.md +61 -0
  36. data/ciri-utils/Rakefile +6 -0
  37. data/ciri-utils/bin/console +14 -0
  38. data/ciri-utils/bin/setup +8 -0
  39. data/ciri-utils/ciri-utils.gemspec +28 -0
  40. data/{lib → ciri-utils/lib}/ciri/utils.rb +9 -33
  41. data/{lib → ciri-utils/lib}/ciri/utils/logger.rb +0 -0
  42. data/{lib → ciri-utils/lib}/ciri/utils/number.rb +15 -12
  43. data/ciri-utils/lib/ciri/utils/version.rb +5 -0
  44. data/ciri-utils/spec/ciri/utils_spec.rb +5 -0
  45. data/ciri-utils/spec/spec_helper.rb +14 -0
  46. data/ciri.gemspec +6 -3
  47. data/lib/ciri/bloom_filter.rb +83 -0
  48. data/lib/ciri/chain.rb +67 -130
  49. data/lib/ciri/chain/header.rb +2 -2
  50. data/lib/ciri/chain/header_chain.rb +136 -0
  51. data/lib/ciri/chain/transaction.rb +1 -1
  52. data/lib/ciri/crypto.rb +2 -2
  53. data/lib/ciri/db/account_db.rb +145 -0
  54. data/lib/ciri/db/backend/memory.rb +24 -1
  55. data/lib/ciri/devp2p/peer.rb +1 -1
  56. data/lib/ciri/devp2p/rlpx/connection.rb +5 -5
  57. data/lib/ciri/eth/peer.rb +3 -3
  58. data/lib/ciri/eth/protocol_manage.rb +3 -3
  59. data/lib/ciri/eth/protocol_messages.rb +27 -26
  60. data/lib/ciri/ethash.rb +18 -3
  61. data/lib/ciri/evm.rb +101 -56
  62. data/lib/ciri/{utils/lib_c.rb → evm/errors.rb} +28 -18
  63. data/lib/ciri/evm/instruction.rb +3 -1
  64. data/lib/ciri/evm/{serialize.rb → log_entry.rb} +9 -27
  65. data/lib/ciri/evm/machine_state.rb +21 -2
  66. data/lib/ciri/evm/op.rb +19 -16
  67. data/lib/ciri/evm/state.rb +61 -0
  68. data/lib/ciri/evm/vm.rb +78 -102
  69. data/lib/ciri/forks.rb +1 -4
  70. data/lib/ciri/forks/base.rb +55 -0
  71. data/lib/ciri/forks/frontier.rb +37 -10
  72. data/lib/ciri/forks/frontier/cost.rb +186 -0
  73. data/lib/ciri/key.rb +1 -1
  74. data/lib/ciri/pow.rb +1 -1
  75. data/lib/ciri/rlp/decode.rb +6 -3
  76. data/lib/ciri/rlp/encode.rb +10 -10
  77. data/lib/ciri/rlp/serializable.rb +12 -9
  78. data/lib/ciri/serialize.rb +58 -0
  79. data/lib/ciri/trie.rb +362 -0
  80. data/lib/ciri/trie/nibbles.rb +97 -0
  81. data/lib/ciri/trie/nodes.rb +187 -0
  82. data/lib/ciri/{evm → types}/account.rb +20 -13
  83. data/lib/ciri/types/address.rb +16 -11
  84. data/lib/ciri/types/number.rb +73 -0
  85. data/lib/ciri/types/receipt.rb +57 -0
  86. data/lib/ciri/version.rb +1 -1
  87. metadata +82 -19
  88. 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.fork_config
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
@@ -21,23 +21,50 @@
21
21
  # THE SOFTWARE.
22
22
 
23
23
 
24
- require 'ciri/evm/forks/frontier'
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
- class << self
31
- def fork_config
32
- ForkConfig.new(
33
- cost_of_operation: proc {|vm| EVM::Forks::Frontier::Cost.cost_of_operation vm},
34
- cost_of_memory: proc {|i| EVM::Forks::Frontier::Cost.cost_of_memory i},
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.data_to_hex privkey}"
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.data_to_hex(out_mix_hash)} != #{Utils.data_to_hex(mix_hash)}")
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)
@@ -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 < Serializable
72
- type.rlp_decode!(s)
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
- list << decode_with_type(s2, type[0])
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
@@ -28,25 +28,25 @@ module Ciri
28
28
  class InputOverflow < StandardError
29
29
  end
30
30
 
31
- # Encode input to rlp encoding, only allow string or array
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 = Raw)
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
- encode(input, Integer)
46
- elsif input.is_a?(Serializable)
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
- encode(input)
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 < Serializable
74
- item.rlp_encode!
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.data_to_hex item.to_s} into #{type}"
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!(encoded)
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!(data, skip_keys: nil, white_list_keys: nil)
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!(input)
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 < Serializable
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!(input)
175
+ data = schema.rlp_decode(input)
176
176
  self.new(data)
177
177
  end
178
178
 
179
- alias rlp_decode! rlp_decode
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!(skip_keys: nil, white_list_keys: nil)
229
- self.class.schema.rlp_encode!(serializable_attributes, skip_keys: skip_keys, white_list_keys: white_list_keys)
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)