scale.rb 0.2.3 → 0.2.8

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.
@@ -92,14 +92,14 @@ module Scale
92
92
  storage_function_type = Scale::Types.type_of("Enum", %w[Plain Map DoubleMap]).decode(scale_bytes).value
93
93
  if storage_function_type == "Plain"
94
94
  result[:type] = {
95
- Plain: adjust(String.decode(scale_bytes).value)
95
+ Plain: String.decode(scale_bytes).value
96
96
  }
97
97
  elsif storage_function_type == "Map"
98
98
  result[:type] = {
99
99
  Map: {
100
100
  hasher: StorageHasher.decode(scale_bytes).value,
101
- key: adjust(String.decode(scale_bytes).value),
102
- value: adjust(String.decode(scale_bytes).value),
101
+ key: String.decode(scale_bytes).value,
102
+ value: String.decode(scale_bytes).value,
103
103
  linked: Bool.decode(scale_bytes).value
104
104
  }
105
105
  }
@@ -107,9 +107,9 @@ module Scale
107
107
  result[:type] = {
108
108
  DoubleMap: {
109
109
  hasher: StorageHasher.decode(scale_bytes).value,
110
- key1: adjust(String.decode(scale_bytes).value),
111
- key2: adjust(String.decode(scale_bytes).value),
112
- value: adjust(String.decode(scale_bytes).value),
110
+ key1: String.decode(scale_bytes).value,
111
+ key2: String.decode(scale_bytes).value,
112
+ value: String.decode(scale_bytes).value,
113
113
  key2Hasher: StorageHasher.decode(scale_bytes).value
114
114
  }
115
115
  }
@@ -92,7 +92,7 @@ module Scale
92
92
  name: String.decode(scale_bytes).value,
93
93
  type: String.decode(scale_bytes).value, # convert
94
94
  value: Hex.decode(scale_bytes).value,
95
- docs: Scale::Types.type_of("Vec<String>").decode(scale_bytes).value.map(&:value)
95
+ documentation: Scale::Types.type_of("Vec<String>").decode(scale_bytes).value.map(&:value)
96
96
  }
97
97
  MetadataV6ModuleConstants.new result
98
98
  end
@@ -106,14 +106,14 @@ module Scale
106
106
  storage_function_type = Scale::Types.type_of("Enum", %w[Plain Map DoubleMap]).decode(scale_bytes).value
107
107
  if storage_function_type == "Plain"
108
108
  result[:type] = {
109
- Plain: adjust(String.decode(scale_bytes).value)
109
+ Plain: String.decode(scale_bytes).value
110
110
  }
111
111
  elsif storage_function_type == "Map"
112
112
  result[:type] = {
113
113
  Map: {
114
114
  hasher: StorageHasher.decode(scale_bytes).value,
115
- key: adjust(String.decode(scale_bytes).value),
116
- value: adjust(String.decode(scale_bytes).value),
115
+ key: String.decode(scale_bytes).value,
116
+ value: String.decode(scale_bytes).value,
117
117
  linked: Bool.decode(scale_bytes).value
118
118
  }
119
119
  }
@@ -121,16 +121,16 @@ module Scale
121
121
  result[:type] = {
122
122
  DoubleMap: {
123
123
  hasher: StorageHasher.decode(scale_bytes).value,
124
- key1: adjust(String.decode(scale_bytes).value),
125
- key2: adjust(String.decode(scale_bytes).value),
126
- value: adjust(String.decode(scale_bytes).value),
124
+ key1: String.decode(scale_bytes).value,
125
+ key2: String.decode(scale_bytes).value,
126
+ value: String.decode(scale_bytes).value,
127
127
  key2Hasher: StorageHasher.decode(scale_bytes).value
128
128
  }
129
129
  }
130
130
  end
131
131
 
132
132
  result[:fallback] = Hex.decode(scale_bytes).value
133
- result[:docs] = Scale::Types.type_of("Vec<String>").decode(scale_bytes).value.map(&:value)
133
+ result[:documentation] = Scale::Types.type_of("Vec<String>").decode(scale_bytes).value.map(&:value)
134
134
 
135
135
  MetadataV7ModuleStorageEntry.new(result)
136
136
  end
@@ -143,7 +143,7 @@ module Scale
143
143
  name: String.decode(scale_bytes).value,
144
144
  type: String.decode(scale_bytes).value, # convert
145
145
  value: Hex.decode(scale_bytes).value,
146
- docs: Scale::Types.type_of("Vec<String>").decode(scale_bytes).value.map(&:value)
146
+ documentation: Scale::Types.type_of("Vec<String>").decode(scale_bytes).value.map(&:value)
147
147
  }
148
148
  MetadataV7ModuleConstants.new result
149
149
  end
@@ -88,7 +88,7 @@ module Scale
88
88
  def self.decode(scale_bytes)
89
89
  result = {
90
90
  name: String.decode(scale_bytes).value,
91
- docs: Scale::Types.type_of("Vec<String>").decode(scale_bytes).value.map(&:value)
91
+ documentation: Scale::Types.type_of("Vec<String>").decode(scale_bytes).value.map(&:value)
92
92
  }
93
93
 
94
94
  MetadataModuleError.new(result)
@@ -23,95 +23,85 @@ require "metadata/metadata_v8"
23
23
  require "metadata/metadata_v9"
24
24
  require "metadata/metadata_v10"
25
25
  require "metadata/metadata_v11"
26
+ require "metadata/metadata_v12"
26
27
 
27
28
  module Scale
28
29
  class Error < StandardError; end
29
30
 
30
31
  class TypeRegistry
31
32
  include Singleton
32
- attr_accessor :types
33
+ attr_reader :spec_name, :types, :versioning, :custom_types
34
+ attr_accessor :spec_version
35
+ attr_accessor :metadata
33
36
 
34
- def load(spec_name = nil, spec_version = nil)
35
- @spec_name = spec_name
36
- @spec_version = spec_version
37
- @types = load_types(spec_name, spec_version.nil? ? nil : spec_version.to_i)
37
+ def load(spec_name: nil, custom_types: nil)
38
+ @spec_name = nil
39
+ @types = nil
40
+ @versioning = nil
41
+ @custom_types = nil
38
42
 
43
+ default_types, _, _ = load_chain_spec_types("default")
44
+
45
+ if spec_name.nil? || spec_name == "default"
46
+ @spec_name = "default"
47
+ @types = default_types
48
+ else
49
+ @spec_name = spec_name
50
+ spec_types, @versioning, @spec_version = load_chain_spec_types(spec_name)
51
+ @types = default_types.merge(spec_types)
52
+ end
53
+
54
+ self.custom_types = custom_types
39
55
  true
40
56
  end
41
57
 
42
58
  def get(type_name)
43
- type = @types[type_name]
44
- return Scale::Types.type_of(type_name) if type.nil?
45
- type
46
- end
59
+ raise "Types not loaded" if @types.nil?
47
60
 
48
- private
49
- def load_types(spec_name, spec_version)
50
- # hard coded types
51
- coded_types = Scale::Types
52
- .constants
53
- .select { |c| Scale::Types.const_get(c).is_a? Class }
54
- .map { |type_name| [type_name.to_s, type_name.to_s] }
55
- .to_h
56
- .transform_values {|type| Scale::Types.constantize(type) }
57
-
58
- return coded_types if spec_name.nil?
59
-
60
- # default spec types
61
- default_types = load_chain_spec_types("default", spec_version).transform_values do |type|
62
- Scale::Types.type_convert(type, coded_types)
63
- end
64
- default_types = coded_types.merge(default_types)
61
+ all_types = {}.merge(@types)
65
62
 
66
- # chain spec types
67
- if spec_name != "default"
68
- spec_types = load_chain_spec_types(spec_name, spec_version)
69
- spec_types.transform_values do |type|
70
- Scale::Types.type_convert(type, default_types)
63
+ if @spec_version && @versioning
64
+ @versioning.each do |item|
65
+ if @spec_version >= item["runtime_range"][0] && @spec_version <= (item["runtime_range"][1] || 1073741823)
66
+ all_types.merge!(item["types"])
67
+ end
71
68
  end
72
- default_types.merge(spec_types)
73
- else
74
- default_types
75
69
  end
70
+
71
+ all_types.merge!(@custom_types) if @custom_types
72
+
73
+ type = type_traverse(type_name, all_types)
74
+
75
+ Scale::Types.constantize(type)
76
76
  end
77
77
 
78
- def load_chain_spec_types(spec_name, spec_version)
79
- file = File.join File.expand_path("../..", __FILE__), "lib", "type_registry", "#{spec_name}.json"
80
- json_string = File.open(file).read
81
- json = JSON.parse(json_string)
78
+ def custom_types=(custom_types)
79
+ @custom_types = custom_types.stringify_keys if (not custom_types.nil?) && custom_types.class.name == "Hash"
80
+ end
82
81
 
83
- types = {}
84
- runtime_id = json["runtime_id"]
85
- versioning = json["versioning"] || []
82
+ private
86
83
 
87
- if runtime_id.nil? || (spec_version && spec_version >= runtime_id)
88
- types = json["types"]
89
- end
84
+ def load_chain_spec_types(spec_name)
85
+ file = File.join File.expand_path("../..", __FILE__), "lib", "type_registry", "#{spec_name}.json"
86
+ json_string = File.open(file).read
87
+ json = JSON.parse(json_string)
90
88
 
91
- if spec_version
92
- versioning.each do |item|
93
- if spec_version >= item["runtime_range"][0] && spec_version <= (item["runtime_range"][1] || 1073741823)
94
- types.merge!(item["types"])
95
- end
96
- end
89
+ runtime_id = json["runtime_id"]
90
+
91
+ [json["types"], json["versioning"], runtime_id]
97
92
  end
98
93
 
99
- types.transform_values! do |type|
100
- if type.class != ::String
101
- Scale::Types.constantize(type)
94
+ def type_traverse(type, types)
95
+ if types.has_key?(type) && types[type] != type
96
+ type_traverse(types[type], types)
102
97
  else
103
- t = Scale::Types.type_convert(type, types)
104
- if t.class == ::String
105
- Scale::Types.constantize(t)
98
+ if type.class == ::String
99
+ rename(type)
106
100
  else
107
- t
101
+ type
108
102
  end
109
103
  end
110
104
  end
111
-
112
- types
113
- end
114
-
115
105
  end
116
106
 
117
107
  # TODO: == implement
@@ -227,7 +217,6 @@ module Scale
227
217
  end
228
218
 
229
219
  def self.get(type_name)
230
- type_name = adjust(type_name)
231
220
  TypeRegistry.instance.get(type_name)
232
221
  end
233
222
 
@@ -247,19 +236,6 @@ module Scale
247
236
  end
248
237
  end
249
238
 
250
- def self.type_convert(type, types)
251
- return type if type.class != ::String
252
-
253
- if type =~ /\[u\d+; \d+\]/
254
- byte_length = type.scan(/\[u\d+; (\d+)\]/).first.first
255
- "VecU8Length#{byte_length}"
256
- elsif types.has_key?(type) && types[type] != type
257
- type_convert(types[type], types)
258
- else
259
- adjust(type)
260
- end
261
- end
262
-
263
239
  def self.type_of(type_string, values = nil)
264
240
  if type_string.end_with?(">")
265
241
  type_strs = type_string.scan(/^([^<]*)<(.+)>$/).first
@@ -274,7 +250,7 @@ module Scale
274
250
  name = "#{type_str}_Of_#{inner_type_str.camelize}_#{klass.object_id}"
275
251
  Scale::Types.const_set fix(name), klass
276
252
  else
277
- raise "#{type_str} not support inner type"
253
+ raise "#{type_str} not support inner type: #{type_string}"
278
254
  end
279
255
  elsif type_string.start_with?("(") && type_string.end_with?(")") # tuple
280
256
  # TODO: add nested tuple support
@@ -345,13 +321,14 @@ def fix(name)
345
321
  .gsub(":", "։")
346
322
  end
347
323
 
348
- def adjust(type)
324
+ def rename(type)
349
325
  type = type.gsub("T::", "")
350
326
  .gsub("<T>", "")
351
327
  .gsub("<T as Trait>::", "")
352
328
  .delete("\n")
353
329
  .gsub("EventRecord<Event, Hash>", "EventRecord")
354
330
  .gsub(/(u)(\d+)/, 'U\2')
331
+ return "Bool" if type == "bool"
355
332
  return "Null" if type == "()"
356
333
  return "String" if type == "Vec<u8>"
357
334
  return "Compact" if type == "Compact<u32>" || type == "Compact<U32>"
@@ -360,9 +337,17 @@ def adjust(type)
360
337
  return "Compact" if type == "<Balance as HasCompact>::Type"
361
338
  return "Compact" if type == "<BlockNumber as HasCompact>::Type"
362
339
  return "Compact" if type == "Compact<Balance>"
340
+ return "Compact" if type == "Compact<BlockNumber>"
363
341
  return "CompactMoment" if type == "<Moment as HasCompact>::Type"
342
+ return "CompactMoment" if type == "Compact<Moment>"
364
343
  return "InherentOfflineReport" if type == "<InherentOfflineReport as InherentOfflineReport>::Inherent"
365
344
  return "AccountData" if type == "AccountData<Balance>"
345
+
346
+ if type =~ /\[U\d+; \d+\]/
347
+ byte_length = type.scan(/\[U\d+; (\d+)\]/).first.first
348
+ return "VecU8Length#{byte_length}"
349
+ end
350
+
366
351
  type
367
352
  end
368
353
 
@@ -395,3 +380,19 @@ class Integer
395
380
  self
396
381
  end
397
382
  end
383
+
384
+ class ::Hash
385
+ # via https://stackoverflow.com/a/25835016/2257038
386
+ def stringify_keys
387
+ h = self.map do |k,v|
388
+ v_str = if v.instance_of? Hash
389
+ v.stringify_keys
390
+ else
391
+ v
392
+ end
393
+
394
+ [k.to_s, v_str]
395
+ end
396
+ Hash[h]
397
+ end
398
+ end
@@ -11,6 +11,28 @@ module Scale
11
11
  def ==(other)
12
12
  value == other.value
13
13
  end
14
+
15
+ def to_human
16
+ if @value.class == ::Hash
17
+ @value.transform_values do |v|
18
+ if v.class.included_modules.include?(SingleValue)
19
+ v.to_human
20
+ else
21
+ v
22
+ end
23
+ end
24
+ elsif @value.class == ::Array
25
+ @value.map do |v|
26
+ if v.class.included_modules.include?(SingleValue)
27
+ v.to_human
28
+ else
29
+ v
30
+ end
31
+ end
32
+ else
33
+ @value
34
+ end
35
+ end
14
36
  end
15
37
 
16
38
  # value: one of nil, false, true, scale object
@@ -67,9 +89,8 @@ module Scale
67
89
 
68
90
  module ClassMethods
69
91
  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
92
+ bytes = scale_bytes.get_next_bytes self::BYTE_LENGTH
93
+ bit_length = bytes.length.to_i * 8
73
94
  value = bytes.reverse.bytes_to_hex.to_i(16).to_signed(bit_length)
74
95
  new(value)
75
96
  end
@@ -83,7 +104,7 @@ module Scale
83
104
  if value.class != ::Integer
84
105
  raise "#{self.class}'s value must be integer"
85
106
  end
86
- bit_length = self.class.name[15..].to_i
107
+ bit_length = self.class::BYTE_LENGTH * 8
87
108
  hex = value.to_unsigned(bit_length).to_s(16).hex_to_bytes.reverse.bytes_to_hex
88
109
  hex[2..]
89
110
  end
@@ -111,19 +132,20 @@ module Scale
111
132
  if value.class != ::Integer
112
133
  raise "#{self.class}'s value must be integer"
113
134
  end
114
- bytes = value.to_s(16).rjust(self.class::BYTE_LENGTH * 2, "0").scan(/.{2}/).reverse.map {|hex| hex.to_i(16) }
135
+ byte_length = self.class::BYTE_LENGTH
136
+ bytes = value.to_s(16).rjust(byte_length * 2, "0").scan(/.{2}/).reverse.map {|hex| hex.to_i(16) }
115
137
  bytes.bytes_to_hex[2..]
116
138
  end
117
139
  end
118
140
 
119
-
120
141
  module Struct
121
142
  include SingleValue
122
143
  # new(1.to_u32, U32(69))
123
144
  module ClassMethods
124
145
  def decode(scale_bytes)
125
146
  item_values = self::ITEM_TYPE_STRS.map do |item_type_str|
126
- Scale::Types.get(item_type_str).decode(scale_bytes)
147
+ type = Scale::TypeRegistry.instance.get(item_type_str)
148
+ type.decode(scale_bytes)
127
149
  end
128
150
 
129
151
  value = {}
@@ -197,7 +219,7 @@ module Scale
197
219
  module ClassMethods
198
220
  def decode(scale_bytes)
199
221
  index = scale_bytes.get_next_bytes(1)[0]
200
- if const_defined? "ITEM_NAMES"
222
+ if const_defined? "ITEM_TYPE_STRS"
201
223
  item_type_str = self::ITEM_TYPE_STRS[index]
202
224
  raise "There is no such member with index #{index} for enum #{self}" if item_type_str.nil?
203
225
  value = Scale::Types.get(item_type_str).decode(scale_bytes)
@@ -208,16 +230,20 @@ module Scale
208
230
  end
209
231
 
210
232
  def items(items)
211
- attr_names = []
212
- attr_type_strs = []
233
+ if items.class == ::Hash
234
+ attr_names = []
235
+ attr_type_strs = []
213
236
 
214
- items.each_pair do |attr_name, attr_type_str|
215
- attr_names << attr_name
216
- attr_type_strs << attr_type_str
217
- end
237
+ items.each_pair do |attr_name, attr_type_str|
238
+ attr_names << attr_name
239
+ attr_type_strs << attr_type_str
240
+ end
218
241
 
219
- const_set(:ITEM_NAMES, attr_names)
220
- const_set(:ITEM_TYPE_STRS, attr_type_strs)
242
+ const_set(:ITEM_NAMES, attr_names)
243
+ const_set(:ITEM_TYPE_STRS, attr_type_strs)
244
+ elsif items.class == ::Array
245
+ const_set(:ITEM_TYPE_STRS, items)
246
+ end
221
247
  end
222
248
 
223
249
  def values(*values)
@@ -238,6 +264,14 @@ module Scale
238
264
  self.class::VALUES.index(value).to_s(16).rjust(2, "0")
239
265
  end
240
266
  end
267
+
268
+ def to_human
269
+ if self.class.const_defined? "ITEM_TYPE_STRS"
270
+ @value.to_human
271
+ else
272
+ @value
273
+ end
274
+ end
241
275
  end
242
276
 
243
277
  module Vec
@@ -248,7 +282,8 @@ module Scale
248
282
  number = Scale::Types::Compact.decode(scale_bytes).value
249
283
  items = []
250
284
  number.times do
251
- item = Scale::Types.get(self::INNER_TYPE_STR).decode(scale_bytes)
285
+ type = Scale::Types.get(self::INNER_TYPE_STR)
286
+ item = type.decode(scale_bytes)
252
287
  items << item
253
288
  end
254
289
  raw ? items : new(items)
@@ -278,7 +313,7 @@ module Scale
278
313
 
279
314
  module ClassMethods
280
315
  def decode(scale_bytes)
281
- value = "Scale::Types::U#{self::BYTES_LENGTH * 8}".constantize.decode(scale_bytes).value
316
+ value = "Scale::Types::U#{self::BYTE_LENGTH * 8}".constantize.decode(scale_bytes).value
282
317
  return new [] unless value || value <= 0
283
318
 
284
319
  result = self::ITEMS.select { |_, mask| value & mask > 0 }.keys
@@ -295,7 +330,7 @@ module Scale
295
330
  def items(items, bytes_length = 1)
296
331
  raise "byte length is wrong: #{bytes_length}" unless [1, 2, 4, 8, 16].include?(bytes_length)
297
332
  const_set(:ITEMS, items)
298
- const_set(:BYTES_LENGTH, bytes_length)
333
+ const_set(:BYTE_LENGTH, bytes_length)
299
334
  end
300
335
  end
301
336
 
@@ -305,7 +340,7 @@ module Scale
305
340
 
306
341
  def encode
307
342
  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
343
+ "Scale::Types::U#{self.class::BYTE_LENGTH * 8}".constantize.new(value).encode
309
344
  end
310
345
  end
311
346