ciri 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +14 -0
  3. data/.rspec +2 -1
  4. data/.travis.yml +11 -4
  5. data/Gemfile.lock +3 -0
  6. data/README.md +44 -34
  7. data/Rakefile +47 -4
  8. data/ciri.gemspec +13 -12
  9. data/docker/Base +34 -0
  10. data/lib/ciri/actor.rb +223 -0
  11. data/lib/ciri/chain.rb +293 -0
  12. data/lib/ciri/chain/block.rb +47 -0
  13. data/lib/ciri/chain/header.rb +62 -0
  14. data/lib/ciri/chain/transaction.rb +145 -0
  15. data/lib/ciri/crypto.rb +58 -5
  16. data/lib/ciri/db/backend/memory.rb +68 -0
  17. data/lib/ciri/db/backend/rocks.rb +104 -0
  18. data/lib/ciri/db/backend/rocks_db.rb +278 -0
  19. data/lib/ciri/devp2p/peer.rb +10 -2
  20. data/lib/ciri/devp2p/protocol.rb +11 -3
  21. data/lib/ciri/devp2p/protocol_io.rb +6 -3
  22. data/lib/ciri/devp2p/rlpx.rb +1 -0
  23. data/lib/ciri/devp2p/rlpx/encryption_handshake.rb +1 -1
  24. data/lib/ciri/devp2p/rlpx/frame_io.rb +1 -1
  25. data/lib/ciri/devp2p/rlpx/message.rb +4 -4
  26. data/lib/ciri/devp2p/server.rb +14 -13
  27. data/lib/ciri/eth.rb +33 -0
  28. data/lib/ciri/eth/peer.rb +64 -0
  29. data/lib/ciri/eth/protocol_manage.rb +122 -0
  30. data/lib/ciri/eth/protocol_messages.rb +158 -0
  31. data/lib/ciri/eth/synchronizer.rb +188 -0
  32. data/lib/ciri/ethash.rb +123 -0
  33. data/lib/ciri/evm.rb +140 -0
  34. data/lib/ciri/evm/account.rb +50 -0
  35. data/lib/ciri/evm/block_info.rb +31 -0
  36. data/lib/ciri/evm/forks/frontier.rb +183 -0
  37. data/lib/ciri/evm/instruction.rb +92 -0
  38. data/lib/ciri/evm/machine_state.rb +81 -0
  39. data/lib/ciri/evm/op.rb +536 -0
  40. data/lib/ciri/evm/serialize.rb +60 -0
  41. data/lib/ciri/evm/sub_state.rb +64 -0
  42. data/lib/ciri/evm/vm.rb +379 -0
  43. data/lib/ciri/forks.rb +38 -0
  44. data/lib/ciri/forks/frontier.rb +43 -0
  45. data/lib/ciri/key.rb +7 -1
  46. data/lib/ciri/pow.rb +95 -0
  47. data/lib/ciri/rlp.rb +3 -53
  48. data/lib/ciri/rlp/decode.rb +100 -40
  49. data/lib/ciri/rlp/encode.rb +95 -34
  50. data/lib/ciri/rlp/serializable.rb +61 -91
  51. data/lib/ciri/types/address.rb +70 -0
  52. data/lib/ciri/types/errors.rb +36 -0
  53. data/lib/ciri/utils.rb +45 -13
  54. data/lib/ciri/utils/lib_c.rb +46 -0
  55. data/lib/ciri/utils/logger.rb +99 -0
  56. data/lib/ciri/utils/number.rb +67 -0
  57. data/lib/ciri/version.rb +1 -1
  58. metadata +67 -7
  59. data/lib/ciri/devp2p/actor.rb +0 -224
@@ -29,7 +29,11 @@ module Ciri
29
29
  # represent bool types: true | false
30
30
  class Bool
31
31
  ENCODED_TRUE = Ciri::Utils.big_endian_encode(0x01)
32
- ENCODED_FALSE = Ciri::Utils.big_endian_encode(0x00)
32
+ ENCODED_FALSE = Ciri::Utils.big_endian_encode(0x80)
33
+ end
34
+
35
+ # represent RLP raw types, binary or array
36
+ class Raw
33
37
  end
34
38
 
35
39
  # Serializable module allow ruby objects serialize/deserialize to or from RLP encoding.
@@ -71,26 +75,38 @@ module Ciri
71
75
  #
72
76
  module Serializable
73
77
  # nil represent RLP raw value(string or array of string)
74
- TYPES = [nil, Integer, Bool].map {|key| [key, true]}.to_h.freeze
78
+ TYPES = [Raw, Integer, Bool].map {|key| [key, true]}.to_h.freeze
75
79
 
76
80
  # Schema specific columns types of classes, normally you should not use Serializable::Schema directly
77
81
  #
78
82
  class Schema
83
+ include Encode
84
+ include Decode
85
+
79
86
  class InvalidSchemaError < StandardError
80
87
  end
81
88
 
82
89
  # keys return data columns array
83
90
  attr_reader :keys
84
91
 
92
+ KeySchema = Struct.new(:type, :options, keyword_init: true)
93
+
85
94
  def initialize(schema)
86
95
  keys = []
87
96
  @_schema = {}
88
97
 
89
98
  schema.each do |key|
90
- key, type = key.is_a?(Hash) ? key.to_a[0] : [key, nil]
99
+ if key.is_a?(Hash)
100
+ options = [:optional].map {|o| [o, key.delete(o)]}.to_h
101
+ raise InvalidSchemaError.new("include unknown options #{key}") unless key.size == 1
102
+ key, type = key.to_a[0]
103
+ else
104
+ options = {}
105
+ type = Raw
106
+ end
91
107
  raise InvalidSchemaError.new("missing type #{type} for key #{key}") unless check_key_type(type)
92
108
  keys << key
93
- @_schema[key] = type
109
+ @_schema[key] = KeySchema.new(type: type, options: options)
94
110
  end
95
111
 
96
112
  @_schema.freeze
@@ -109,25 +125,38 @@ module Ciri
109
125
  end
110
126
  end
111
127
 
112
- def rlp_encode!(data, raw: true)
128
+ def rlp_encode!(data, skip_keys: nil, white_list_keys: nil)
113
129
  # pre-encode, encode data to rlp compatible format(only string or array)
114
- data_list = keys.map do |key|
115
- Serializable.encode_with_type(data[key], self[key])
130
+ used_keys = if white_list_keys
131
+ white_list_keys
132
+ elsif skip_keys
133
+ keys - skip_keys
134
+ else
135
+ keys
136
+ end
137
+ data_list = []
138
+ used_keys.each do |key|
139
+ value = data[key]
140
+ next if value.nil? && self[key].options[:optional]
141
+ data_list << encode_with_type(value, self[key].type)
116
142
  end
117
- raw ? RLP.encode(data_list) : data_list
143
+ encode_list(data_list)
118
144
  end
119
145
 
120
- def rlp_decode!(input, raw: true)
121
- data = raw ? RLP.decode(input) : input
122
- keys.each_with_index.map do |key, i|
123
- # decode data by type
124
- decoded_item = Serializable.decode_with_type(data[i], self[key])
125
- [key, decoded_item]
126
- end.to_h
146
+ def rlp_decode!(input)
147
+ values = decode_list(input) do |list, stream|
148
+ keys.each do |key|
149
+ # decode data by type
150
+ next if stream.eof? && self[key].options[:optional]
151
+ list << decode_with_type(stream, self[key].type)
152
+ end
153
+ end
154
+ # convert to key value hash
155
+ keys.zip(values).to_h
127
156
  end
128
157
 
129
-
130
158
  private
159
+
131
160
  def check_key_type(type)
132
161
  return true if TYPES.key?(type)
133
162
  return true if type.is_a?(Class) && type < Serializable
@@ -142,8 +171,8 @@ module Ciri
142
171
 
143
172
  module ClassMethods
144
173
  # Decode object from input
145
- def rlp_decode(input, raw: true)
146
- data = schema.rlp_decode!(input, raw: raw)
174
+ def rlp_decode(input)
175
+ data = schema.rlp_decode!(input)
147
176
  self.new(data)
148
177
  end
149
178
 
@@ -161,15 +190,16 @@ module Ciri
161
190
  end
162
191
 
163
192
  private
193
+
164
194
  def define_attributes(schema)
165
195
  schema.keys.each do |attribute|
166
196
  module_eval <<-ATTR_METHODS
167
197
  def #{attribute}
168
- data[:"#{attribute}"]
198
+ serializable_attributes[:"#{attribute}"]
169
199
  end
170
200
 
171
201
  def #{attribute}=(value)
172
- data[:"#{attribute}"] = value
202
+ serializable_attributes[:"#{attribute}"] = value
173
203
  end
174
204
  ATTR_METHODS
175
205
  end
@@ -180,87 +210,27 @@ module Ciri
180
210
  def included(base)
181
211
  base.send :extend, ClassMethods
182
212
  end
183
-
184
- # use this method before RLP.encode
185
- # encode item to string or array
186
- def encode_with_type(item, type, zero: '')
187
- if type == Integer
188
- if item == 0
189
- "\x80".b
190
- elsif item < 128
191
- Ciri::Utils.big_endian_encode(item, zero)
192
- else
193
- buf = Ciri::Utils.big_endian_encode(item, zero)
194
- [0x80 + buf.size].pack("c*") + buf
195
- end
196
- elsif type == Bool
197
- item ? Bool::ENCODED_TRUE : Bool::ENCODED_FALSE
198
- elsif type.is_a?(Class) && type < Serializable
199
- item.rlp_encode!(raw: false)
200
- elsif type.is_a?(Array)
201
- if type.size == 1 # array type
202
- item.map {|i| encode_with_type(i, type[0])}
203
- else # unknown
204
- raise InvalidValueError.new "type size should be 1, got #{type}"
205
- end
206
- else
207
- raise InvalidValueError.new "unknown type #{type}" unless TYPES.key?(type)
208
- item
209
- end
210
- end
211
-
212
- # Use this method after RLP.decode, decode values from string or array to specific types
213
- # see Ciri::RLP::Serializable::TYPES for supported types
214
- #
215
- # Examples:
216
- #
217
- # item = Ciri::RLP.decode(encoded_text)
218
- # decode_with_type(item, Integer)
219
- #
220
- def decode_with_type(item, type)
221
- if type == Integer
222
- if item == "\x80".b || item.empty?
223
- 0
224
- elsif item[0].ord < 0x80
225
- Ciri::Utils.big_endian_decode(item)
226
- else
227
- size = item[0].ord - 0x80
228
- Ciri::Utils.big_endian_decode(item[1..size])
229
- end
230
- elsif type == Bool
231
- if item == Bool::ENCODED_TRUE
232
- true
233
- elsif item == Bool::ENCODED_FALSE
234
- false
235
- else
236
- raise InvalidValueError.new "invalid bool value #{item}"
237
- end
238
- elsif type.is_a?(Class) && type < Serializable
239
- # already decoded from RLP encoding
240
- type.rlp_decode!(item, raw: false)
241
- elsif type.is_a?(Array)
242
- item.map {|i| decode_with_type(i, type[0])}
243
- else
244
- raise InvalidValueError.new "unknown type #{type}" unless TYPES.key?(type)
245
- item
246
- end
247
- end
248
213
  end
249
214
 
250
- attr_reader :data
215
+ attr_reader :serializable_attributes
251
216
 
252
217
  def initialize(**data)
253
- @data = (self.class.default_data || {}).merge(data)
254
- self.class.schema.validate!(@data)
218
+ @serializable_attributes = (self.class.default_data || {}).merge(data)
219
+ self.class.schema.validate!(@serializable_attributes)
220
+ end
221
+
222
+ def initialize_copy(orig)
223
+ super
224
+ @serializable_attributes = orig.serializable_attributes.dup
255
225
  end
256
226
 
257
227
  # Encode object to rlp encoding string
258
- def rlp_encode!(raw: true)
259
- self.class.schema.rlp_encode!(data, raw: raw)
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)
260
230
  end
261
231
 
262
232
  def ==(other)
263
- self.class == other.class && data == other.data
233
+ self.class == other.class && serializable_attributes == other.serializable_attributes
264
234
  end
265
235
 
266
236
  end
@@ -0,0 +1,70 @@
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_relative 'errors'
25
+ require 'ciri/rlp'
26
+
27
+ module Ciri
28
+ module Types
29
+ class Address
30
+
31
+ include RLP::Serializable
32
+ include Errors
33
+
34
+ def initialize(address)
35
+ @address = address.to_s
36
+ end
37
+
38
+ def rlp_encode!
39
+ RLP.encode(@address)
40
+ end
41
+
42
+ def self.rlp_decode!(data)
43
+ address = self.new(RLP.decode(data))
44
+ address.validate
45
+ address
46
+ end
47
+
48
+ def to_s
49
+ @address
50
+ end
51
+
52
+ alias to_str to_s
53
+
54
+ def to_hex
55
+ Utils.data_to_hex to_s
56
+ end
57
+
58
+ def empty?
59
+ @address.empty?
60
+ end
61
+
62
+ def validate
63
+ # empty address is valid
64
+ return if empty?
65
+ raise InvalidError.new("address must be 20 size, got #{@address.size}") unless @address.size == 20
66
+ end
67
+
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,36 @@
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 Types
26
+ module Errors
27
+
28
+ class Error < StandardError
29
+ end
30
+
31
+ class InvalidError < Error
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -22,11 +22,15 @@
22
22
 
23
23
 
24
24
  require 'digest/sha3'
25
+ require_relative 'utils/number'
25
26
 
26
27
  module Ciri
27
28
  module Utils
28
29
 
29
30
  class << self
31
+ include Utils::Number
32
+
33
+
30
34
  def sha3(*data)
31
35
  s = Digest::SHA3.new(256)
32
36
  data.each {|i| s.update(i)}
@@ -37,24 +41,24 @@ module Ciri
37
41
  s1.size == s2.size && s1.each_byte.each_with_index.map {|b, i| b ^ s2[i].ord}.reduce(0, :+) == 0
38
42
  end
39
43
 
40
- def big_endian_encode(n, zero = '')
41
- if n == 0
42
- zero
43
- else
44
- big_endian_encode(n / 256) + (n % 256).chr
45
- end
44
+ def hex_to_data(hex)
45
+ data = [hex].pack("H*")
46
+ data = data[1..-1] if data.size > 0 && data[0].ord == 1
47
+ data
46
48
  end
47
49
 
48
- def big_endian_decode(input)
49
- input.each_byte.reduce(0) {|s, i| s * 256 + i}
50
+ def hex_to_number(hex)
51
+ big_endian_decode hex_to_data(hex)
50
52
  end
51
53
 
52
- def hex_to_data(hex)
53
- [hex].pack("H*")
54
+ def data_to_hex(data)
55
+ hex = data.to_s.unpack("H*").first
56
+ hex[0..1] = '0x' if hex.start_with?('01')
57
+ hex
54
58
  end
55
59
 
56
- def data_to_hex(data)
57
- data.unpack("H*").first
60
+ def number_to_hex(number)
61
+ data_to_hex big_endian_encode(number)
58
62
  end
59
63
 
60
64
  def create_ec_pk(raw_pubkey: nil, raw_privkey: nil)
@@ -69,7 +73,35 @@ module Ciri
69
73
  key.private_key = OpenSSL::BN.new(raw_privkey, 2) if raw_privkey
70
74
  end
71
75
  end
76
+
77
+ def to_underscore(str)
78
+ str.gsub(/[A-Z]/) {|a| "_" + a.downcase}
79
+ end
80
+
81
+ def blank_binary?(item)
82
+ return true if item.is_a?(String) && item.each_byte.all?(&:zero?)
83
+ blank?(item)
84
+ end
85
+
86
+ def blank?(item)
87
+ if item.nil?
88
+ true
89
+ elsif item.is_a? Integer
90
+ item.zero?
91
+ elsif item.is_a? String
92
+ item.empty?
93
+ else
94
+ false
95
+ end
96
+ end
97
+
98
+ def present?(item)
99
+ !blank?(item)
100
+ end
101
+
72
102
  end
73
103
 
104
+ BLANK_SHA3 = Utils.sha3(''.b).freeze
105
+
74
106
  end
75
- end
107
+ end
@@ -0,0 +1,46 @@
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 'ffi'
25
+
26
+ module Ciri
27
+ module Utils
28
+
29
+ module LibC
30
+ extend FFI::Library
31
+ ffi_lib FFI::Library::LIBC
32
+
33
+ # memory allocators
34
+ attach_function :malloc, [:size_t], :pointer
35
+ attach_function :calloc, [:size_t], :pointer
36
+ attach_function :valloc, [:size_t], :pointer
37
+ attach_function :realloc, [:pointer, :size_t], :pointer
38
+ attach_function :free, [:pointer], :void
39
+
40
+ # memory movers
41
+ attach_function :memcpy, [:pointer, :pointer, :size_t], :pointer
42
+ attach_function :bcopy, [:pointer, :pointer, :size_t], :void
43
+ end
44
+
45
+ end
46
+ end