scale.rb 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,8 +8,8 @@ module Scale
8
8
  @value = value
9
9
  end
10
10
 
11
- def ==(another)
12
- self.value == another.value
11
+ def ==(other)
12
+ value == other.value
13
13
  end
14
14
  end
15
15
 
@@ -21,18 +21,18 @@ module Scale
21
21
  def decode(scale_bytes)
22
22
  byte = scale_bytes.get_next_bytes(1)
23
23
  if byte == [0]
24
- return self.new(nil)
24
+ new(nil)
25
25
  elsif byte == [1]
26
- if self::INNER_TYPE_STR == 'boolean'
27
- return self.new(false)
26
+ if self::INNER_TYPE_STR == "boolean"
27
+ new(false)
28
28
  else
29
29
  # big process
30
- value = type_of(self::INNER_TYPE_STR).decode(scale_bytes)
31
- return self.new(value)
30
+ value = Scale::Types.get(self::INNER_TYPE_STR).decode(scale_bytes)
31
+ new(value)
32
32
  end
33
33
  elsif byte == [2]
34
- if self::INNER_TYPE_STR == 'boolean'
35
- return self.new(true)
34
+ if self::INNER_TYPE_STR == "boolean"
35
+ new(true)
36
36
  else
37
37
  raise "bad data"
38
38
  end
@@ -42,7 +42,7 @@ module Scale
42
42
  end
43
43
 
44
44
  def inner_type(type_str)
45
- self.const_set(:INNER_TYPE_STR, type_str)
45
+ const_set(:INNER_TYPE_STR, type_str)
46
46
  end
47
47
  end
48
48
 
@@ -52,26 +52,54 @@ module Scale
52
52
 
53
53
  def encode
54
54
  # TODO: add Null type
55
- if self.value.nil?
55
+ if value.nil?
56
56
  "00"
57
57
  else
58
- return "02" if self.value.class == TrueClass && self.value === true
59
- return "01" if self.value.class == FalseClass && self.value === false
60
- "01" + self.value.encode
58
+ return "02" if value.class == TrueClass && value === true
59
+ return "01" if value.class == FalseClass && value === false
60
+ "01" + value.encode
61
61
  end
62
62
  end
63
63
  end
64
64
 
65
+ module FixedWidthInt
66
+ include SingleValue
67
+
68
+ module ClassMethods
69
+ def decode(scale_bytes)
70
+ bit_length = to_s[15..].to_i
71
+ byte_length = bit_length / 8
72
+ bytes = scale_bytes.get_next_bytes byte_length
73
+ value = bytes.reverse.bytes_to_hex.to_i(16).to_signed(bit_length)
74
+ new(value)
75
+ end
76
+ end
77
+
78
+ def self.included(base)
79
+ base.extend(ClassMethods)
80
+ end
81
+
82
+ def encode
83
+ if value.class != ::Integer
84
+ raise "#{self.class}'s value must be integer"
85
+ end
86
+ bit_length = self.class.name[15..].to_i
87
+ hex = value.to_unsigned(bit_length).to_s(16).hex_to_bytes.reverse.bytes_to_hex
88
+ hex[2..]
89
+ end
90
+ end
91
+
65
92
  module FixedWidthUInt
66
93
  include SingleValue
67
94
 
68
95
  module ClassMethods
96
+ attr_accessor :byte_length
97
+
69
98
  def decode(scale_bytes)
70
- class_name = self.to_s
71
- bytes = scale_bytes.get_next_bytes self::BYTES_LENGTH
99
+ bytes = scale_bytes.get_next_bytes self::BYTE_LENGTH
72
100
  bytes_reversed = bytes.reverse
73
- hex = bytes_reversed.reduce('0x') { |hex, byte| hex + byte.to_s(16).rjust(2, '0') }
74
- self.new(hex.to_i(16))
101
+ hex = bytes_reversed.reduce("0x") { |hex, byte| hex + byte.to_s(16).rjust(2, "0") }
102
+ new(hex.to_i(16))
75
103
  end
76
104
  end
77
105
 
@@ -80,7 +108,10 @@ module Scale
80
108
  end
81
109
 
82
110
  def encode
83
- bytes = self.value.to_s(16).rjust(self.class::BYTES_LENGTH*2, '0').scan(/.{2}/).reverse.map {|hex| hex.to_i(16) }
111
+ if value.class != ::Integer
112
+ raise "#{self.class}'s value must be integer"
113
+ end
114
+ bytes = value.to_s(16).rjust(self.class::BYTE_LENGTH * 2, "0").scan(/.{2}/).reverse.map {|hex| hex.to_i(16) }
84
115
  bytes.bytes_to_hex[2..]
85
116
  end
86
117
  end
@@ -92,7 +123,7 @@ module Scale
92
123
  module ClassMethods
93
124
  def decode(scale_bytes)
94
125
  item_values = self::ITEM_TYPE_STRS.map do |item_type_str|
95
- type_of(item_type_str).decode(scale_bytes)
126
+ Scale::Types.get(item_type_str).decode(scale_bytes)
96
127
  end
97
128
 
98
129
  value = {}
@@ -100,25 +131,25 @@ module Scale
100
131
  value[attr] = val
101
132
  end
102
133
 
103
- result = self.new(value)
134
+ result = new(value)
104
135
  value.each_pair do |attr, val|
105
136
  result.send "#{attr}=", val
106
137
  end
107
- return result
138
+ result
108
139
  end
109
140
 
110
- def items(**items)
141
+ def items(items)
111
142
  attr_names = []
112
143
  attr_type_strs = []
113
144
 
114
145
  items.each_pair do |attr_name, attr_type_str|
115
- attr_names << attr_name
146
+ attr_names << attr_name.to_s.gsub("-", "")
116
147
  attr_type_strs << attr_type_str
117
148
  end
118
149
 
119
- self.const_set(:ITEM_NAMES, attr_names)
120
- self.const_set(:ITEM_TYPE_STRS, attr_type_strs)
121
- self.attr_accessor *attr_names
150
+ const_set(:ITEM_NAMES, attr_names)
151
+ const_set(:ITEM_TYPE_STRS, attr_type_strs)
152
+ attr_accessor *attr_names
122
153
  end
123
154
  end
124
155
 
@@ -127,8 +158,8 @@ module Scale
127
158
  end
128
159
 
129
160
  def encode
130
- [].tap do |result|
131
- self.value.each_pair do |attr_name, attr_value|
161
+ [].tap do |result|
162
+ value.each_pair do |attr_name, attr_value|
132
163
  result << attr_value.encode
133
164
  end
134
165
  end.join
@@ -137,17 +168,17 @@ module Scale
137
168
 
138
169
  module Tuple
139
170
  include SingleValue
140
-
171
+
141
172
  module ClassMethods
142
173
  def decode(scale_bytes)
143
174
  values = self::TYPE_STRS.map do |type_str|
144
- type_of(type_str).decode(scale_bytes)
175
+ Scale::Types.get(type_str).decode(scale_bytes)
145
176
  end
146
- return self.new(values)
177
+ new(values)
147
178
  end
148
179
 
149
180
  def inner_types(*type_strs)
150
- self.const_set(:TYPE_STRS, type_strs)
181
+ const_set(:TYPE_STRS, type_strs)
151
182
  end
152
183
  end
153
184
 
@@ -156,7 +187,7 @@ module Scale
156
187
  end
157
188
 
158
189
  def encode
159
- self.value.map(&:encode).join
190
+ value.map(&:encode).join
160
191
  end
161
192
  end
162
193
 
@@ -166,18 +197,17 @@ module Scale
166
197
  module ClassMethods
167
198
  def decode(scale_bytes)
168
199
  index = scale_bytes.get_next_bytes(1)[0]
169
- if self.const_defined? "ITEM_NAMES"
200
+ if const_defined? "ITEM_NAMES"
170
201
  item_type_str = self::ITEM_TYPE_STRS[index]
171
202
  raise "There is no such member with index #{index} for enum #{self}" if item_type_str.nil?
172
- value = type_of(item_type_str).decode(scale_bytes)
173
- return self.new(value)
203
+ value = Scale::Types.get(item_type_str).decode(scale_bytes)
174
204
  else
175
205
  value = self::VALUES[index]
176
- return self.new(value)
177
206
  end
207
+ new(value)
178
208
  end
179
209
 
180
- def items(**items)
210
+ def items(items)
181
211
  attr_names = []
182
212
  attr_type_strs = []
183
213
 
@@ -186,12 +216,12 @@ module Scale
186
216
  attr_type_strs << attr_type_str
187
217
  end
188
218
 
189
- self.const_set(:ITEM_NAMES, attr_names)
190
- self.const_set(:ITEM_TYPE_STRS, attr_type_strs)
219
+ const_set(:ITEM_NAMES, attr_names)
220
+ const_set(:ITEM_TYPE_STRS, attr_type_strs)
191
221
  end
192
222
 
193
223
  def values(*values)
194
- self.const_set(:VALUES, values)
224
+ const_set(:VALUES, values)
195
225
  end
196
226
  end
197
227
 
@@ -201,11 +231,11 @@ module Scale
201
231
 
202
232
  def encode
203
233
  if self.class.const_defined? "ITEM_NAMES"
204
- value_type_str = self.value.class.to_s.split("::").last.to_s
205
- index = self::class::ITEM_TYPE_STRS.index(value_type_str).to_s(16).rjust(2, '0')
206
- index + self.value.encode
234
+ value_type_str = value.class.to_s.split("::").last.to_s
235
+ index = self.class::ITEM_TYPE_STRS.index(value_type_str).to_s(16).rjust(2, "0")
236
+ index + value.encode
207
237
  else
208
- self::class::VALUES.index(self.value).to_s(16).rjust(2, '0')
238
+ self.class::VALUES.index(value).to_s(16).rjust(2, "0")
209
239
  end
210
240
  end
211
241
  end
@@ -214,18 +244,18 @@ module Scale
214
244
  include SingleValue # value is an array
215
245
 
216
246
  module ClassMethods
217
- def decode(scale_bytes, raw=false)
247
+ def decode(scale_bytes, raw = false)
218
248
  number = Scale::Types::Compact.decode(scale_bytes).value
219
249
  items = []
220
250
  number.times do
221
- item = type_of(self::INNER_TYPE_STR).decode(scale_bytes)
251
+ item = Scale::Types.get(self::INNER_TYPE_STR).decode(scale_bytes)
222
252
  items << item
223
253
  end
224
- raw ? items : self.new(items)
254
+ raw ? items : new(items)
225
255
  end
226
256
 
227
257
  def inner_type(type_str)
228
- self.const_set(:INNER_TYPE_STR, type_str)
258
+ const_set(:INNER_TYPE_STR, type_str)
229
259
  end
230
260
  end
231
261
 
@@ -234,9 +264,9 @@ module Scale
234
264
  end
235
265
 
236
266
  def encode
237
- number = Scale::Types::Compact.new(self.value.length).encode
267
+ number = Scale::Types::Compact.new(value.length).encode
238
268
  [number].tap do |result|
239
- self.value.each do |element|
269
+ value.each do |element|
240
270
  result << element.encode
241
271
  end
242
272
  end.join
@@ -248,24 +278,24 @@ module Scale
248
278
 
249
279
  module ClassMethods
250
280
  def decode(scale_bytes)
251
- value = "Scale::Types::U#{self::BYTES_LENGTH*8}".constantize.decode(scale_bytes).value
252
- return self.new [] if not value || value <= 0
281
+ value = "Scale::Types::U#{self::BYTES_LENGTH * 8}".constantize.decode(scale_bytes).value
282
+ return new [] unless value || value <= 0
253
283
 
254
- result = self::VALUES.select{ |_, mask| value & mask > 0 }.keys
255
- return self.new result
284
+ result = self::ITEMS.select { |_, mask| value & mask > 0 }.keys
285
+ new result
256
286
  end
257
287
 
258
- # values is a hash:
288
+ # items is a hash:
259
289
  # {
260
290
  # "TransactionPayment" => 0b00000001,
261
291
  # "Transfer" => 0b00000010,
262
292
  # "Reserve" => 0b00000100,
263
293
  # ...
264
294
  # }
265
- def values(values, bytes_length=1)
266
- raise "byte length is wrong: #{bytes_length}" if not [1, 2, 4, 8, 16].include?(bytes_length)
267
- self.const_set(:VALUES, values)
268
- self.const_set(:BYTES_LENGTH, bytes_length)
295
+ def items(items, bytes_length = 1)
296
+ raise "byte length is wrong: #{bytes_length}" unless [1, 2, 4, 8, 16].include?(bytes_length)
297
+ const_set(:ITEMS, items)
298
+ const_set(:BYTES_LENGTH, bytes_length)
269
299
  end
270
300
  end
271
301
 
@@ -274,8 +304,8 @@ module Scale
274
304
  end
275
305
 
276
306
  def encode
277
- value = self.class::VALUES.select{ |str, _| self.value.include?(str) }.values.sum
278
- "Scale::Types::U#{self.class::BYTES_LENGTH*8}".constantize.new(value).encode
307
+ value = self.class::ITEMS.select { |key, _| self.value.include?(key) }.values.sum
308
+ "Scale::Types::U#{self.class::BYTES_LENGTH * 8}".constantize.new(value).encode
279
309
  end
280
310
  end
281
311
 
@@ -284,17 +314,16 @@ module Scale
284
314
 
285
315
  module ClassMethods
286
316
  def decode(scale_bytes)
287
- class_name = self.to_s
288
- length = class_name[class_name.length-1]
289
- raise "length is wrong: #{length}" if not ["2", "3", "4", "8", "16", "20", "32", "64"].include?(length)
290
- length = length.to_i
317
+ byte_length = name[25..]
318
+ raise "length is wrong: #{byte_length}" unless %w[2 3 4 8 16 20 32 64].include?(byte_length)
319
+ byte_length = byte_length.to_i
291
320
 
292
- bytes = scale_bytes.get_next_bytes(length)
321
+ bytes = scale_bytes.get_next_bytes(byte_length)
293
322
  str = bytes.pack("C*").force_encoding("utf-8")
294
323
  if str.valid_encoding?
295
- self.new str
324
+ new str
296
325
  else
297
- self.new bytes.bytes_to_hex
326
+ new bytes.bytes_to_hex
298
327
  end
299
328
  end
300
329
  end
@@ -305,14 +334,14 @@ module Scale
305
334
 
306
335
  def encode
307
336
  class_name = self.class.to_s
308
- length = class_name[class_name.length-1]
309
- raise "length is wrong: #{length}" if not ["2", "3", "4", "8", "16", "20", "32", "64"].include?(length)
337
+ length = class_name[25..]
338
+ raise "length is wrong: #{length}" unless %w[2 3 4 8 16 20 32 64].include?(length)
310
339
  length = length.to_i
311
340
 
312
- if self.value.start_with?("0x") && self.value.length == (length*2+2)
313
- self.value[2..]
341
+ if value.start_with?("0x") && value.length == (length * 2 + 2)
342
+ value[2..]
314
343
  else
315
- bytes = self.value.unpack("C*")
344
+ bytes = value.unpack("C*")
316
345
  bytes.bytes_to_hex[2..]
317
346
  end
318
347
  end
@@ -0,0 +1,115 @@
1
+ module Scale
2
+ module Types
3
+
4
+ class Extrinsic
5
+ include SingleValue
6
+ # attr_accessor :address, :signature, :nonce, :era, :extrinsic_hash, :call_index, :params_raw, :params
7
+
8
+ def self.generate_hash(data)
9
+ Blake2b.hex data, Blake2b::Key.none, 32
10
+ end
11
+
12
+ def self.decode(scale_bytes, metadata)
13
+ result = {}
14
+
15
+ extrinsic_length = Compact.decode(scale_bytes).value
16
+ # TODO: legacy version
17
+
18
+ version_info = scale_bytes.get_next_bytes(1).bytes_to_hex
19
+ contains_transaction = version_info.to_i(16) >= 80
20
+
21
+ if version_info == "0x01" || version_info == "0x81"
22
+
23
+ if contains_transaction
24
+ address = Scale::Types.get("Address").decode(scale_bytes)
25
+ result[:address] = address.value
26
+ result[:account_length] = address.account_length
27
+ result[:account_id] = address.account_id
28
+ result[:account_index] = address.account_index
29
+ result[:signature] = Scale::Types.get("Signature").decode(scale_bytes).value
30
+ result[:nonce] = Scale::Types.get("Compact").decode(scale_bytes).value
31
+ result[:era] = Scale::Types.get("Era").decode(scale_bytes).value
32
+ result[:extrinsic_hash] = generate_hash(scale_bytes.bytes)
33
+ end
34
+ result[:call_index] = scale_bytes.get_next_bytes(2).bytes_to_hex[2..]
35
+
36
+ elsif version_info == "0x02" || version_info == "0x82"
37
+
38
+ if contains_transaction
39
+ address = Scale::Types.get("Address").decode(scale_bytes)
40
+ result[:address] = address.value
41
+ result[:account_length] = address.account_length
42
+ result[:account_id] = address.account_id
43
+ result[:account_index] = address.account_index
44
+ result[:signature] = Scale::Types.get("Signature").decode(scale_bytes).value
45
+ result[:era] = Scale::Types.get("Era").decode(scale_bytes).value
46
+ result[:nonce] = Scale::Types.get("Compact").decode(scale_bytes).value
47
+ result[:tip] = Scale::Types.get("Compact").decode(scale_bytes).value
48
+ result[:extrinsic_hash] = generate_hash(scale_bytes.bytes)
49
+ end
50
+ result[:call_index] = scale_bytes.get_next_bytes(2).bytes_to_hex[2..]
51
+
52
+ elsif version_info == "0x03" || version_info == "0x83"
53
+
54
+ if contains_transaction
55
+ address = Scale::Types.get("Address").decode(scale_bytes)
56
+ result[:address] = address.value
57
+ result[:account_length] = address.account_length
58
+ result[:account_id] = address.account_id
59
+ result[:account_index] = address.account_index
60
+ result[:signature] = Scale::Types.get("Signature").decode(scale_bytes).value
61
+ result[:era] = Scale::Types.get("Era").decode(scale_bytes).value
62
+ result[:nonce] = Scale::Types.get("Compact").decode(scale_bytes).value
63
+ result[:tip] = Scale::Types.get("Compact").decode(scale_bytes).value
64
+ result[:extrinsic_hash] = generate_hash(scale_bytes.bytes)
65
+ end
66
+ result[:call_index] = scale_bytes.get_next_bytes(2).bytes_to_hex[2..]
67
+
68
+ elsif version_info == "0x04" || version_info == "0x84"
69
+
70
+ if contains_transaction
71
+ address = Scale::Types.get("Address").decode(scale_bytes)
72
+ result[:address] = address.value
73
+ result[:account_length] = address.account_length
74
+ result[:account_id] = address.account_id
75
+ result[:account_index] = address.account_index
76
+ result[:signature_version] = Scale::Types.get("U8").decode(scale_bytes).value
77
+ result[:signature] = Scale::Types.get("Signature").decode(scale_bytes).value
78
+ result[:era] = Scale::Types.get("Era").decode(scale_bytes).value
79
+ result[:nonce] = Scale::Types.get("Compact").decode(scale_bytes).value
80
+ result[:tip] = Scale::Types.get("Compact").decode(scale_bytes).value
81
+ result[:extrinsic_hash] = generate_hash(scale_bytes.bytes)
82
+ end
83
+ result[:call_index] = scale_bytes.get_next_bytes(2).bytes_to_hex[2..]
84
+
85
+ else
86
+ raise "Extrinsics version #{version_info} is not implemented"
87
+ end
88
+
89
+ if result[:call_index]
90
+ call_module, call = metadata.value.call_index[result[:call_index]]
91
+
92
+ result[:call_function] = call[:name].downcase
93
+ result[:call_module] = call_module[:name].downcase
94
+
95
+ # decode params
96
+ result[:params_raw] = scale_bytes.get_remaining_bytes.bytes_to_hex
97
+ result[:params] = call[:args].map do |arg|
98
+ type = Scale::Types.get(arg[:type])
99
+ arg_obj = type.decode(scale_bytes)
100
+ {name: arg[:name], type: type.name, value: arg_obj.value, value_raw: "0x#{arg_obj.encode}" }
101
+ end
102
+ end
103
+
104
+ result[:extrinsic_length] = extrinsic_length
105
+ result[:version_info] = version_info
106
+
107
+ result
108
+ end
109
+
110
+ def encode
111
+ end
112
+ end
113
+
114
+ end
115
+ end