scale.rb 0.2.4 → 0.2.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -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, :metadata
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