scale_rb 0.5.0 → 0.5.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.
@@ -0,0 +1,552 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './types'
4
+
5
+ # rubocop:disable all
6
+ module ScaleRb
7
+ class OldRegistry
8
+ include Types
9
+
10
+ # Map name to index of type in `types` array
11
+ # % lookup :: String -> Integer
12
+ attr_reader :lookup
13
+
14
+ # % keys :: Integer -> String
15
+ attr_reader :keys
16
+
17
+ # % types :: Array<PortableType>
18
+ attr_reader :types
19
+
20
+ attr_reader :old_types
21
+
22
+ # % initialize :: Hash<String, Any> -> void
23
+ def initialize(old_types)
24
+ @old_types = old_types
25
+ @lookup = {}
26
+ @keys = {}
27
+ @types = []
28
+
29
+ build()
30
+ end
31
+
32
+ def build()
33
+ @old_types.keys.each do |name|
34
+ use(name)
35
+ end
36
+ end
37
+
38
+ def [](identifier)
39
+ if identifier.is_a?(::Integer)
40
+ @types[identifier]
41
+ elsif identifier.is_a?(::String)
42
+ @types[use(identifier)]
43
+ else
44
+ raise "Unknown identifier type: #{identifier.class}"
45
+ end
46
+ end
47
+
48
+ def inspect
49
+ "registry(#{@types.length} types)"
50
+ end
51
+
52
+ def to_s
53
+ @types.map.with_index do |type, index|
54
+ "#{@keys[index]} => #{type.to_s}"
55
+ end.join("\n")
56
+ end
57
+
58
+ # % use :: String -> Integer
59
+ def use(old_type_exp)
60
+ raise "Empty old_type_exp: #{old_type_exp}" if old_type_exp.nil? || old_type_exp.strip == ''
61
+
62
+ ast_type = TypeExp.parse(old_type_exp)
63
+ raise "No AST type for #{old_type_exp}" if ast_type.nil?
64
+
65
+ key = ast_type.to_s
66
+ ti = lookup[key]
67
+ return ti if ti
68
+
69
+ ti = @types.length
70
+ @types[ti] = "Placeholder"
71
+ @lookup[key] = ti
72
+ @keys[ti] = key
73
+ @types[ti] = build_portable_type(ast_type)
74
+ ti
75
+ end
76
+
77
+ # % build_portable_type :: NamedType | ArrayType | TupleType -> PortableType
78
+ # __ :build_portable_type, { ast_type: TypedArray[TypeExp::ArrayType | TypeExp::TupleType | TypeExp::NamedType] } => PortableType
79
+ def build_portable_type(ast_type)
80
+ case ast_type
81
+ when TypeExp::ArrayType
82
+ ArrayType.new(use(ast_type.item), ast_type.len, registry: self)
83
+ when TypeExp::TupleType
84
+ TupleType.new(ast_type.params.map { |param| use(param) })
85
+ when TypeExp::NamedType
86
+ build_portable_type_from_named_type(ast_type)
87
+ else
88
+ raise "Unknown type: #{ast_type.class}"
89
+ end
90
+ end
91
+
92
+ # % build_portable_type_from_named_type :: NamedType -> PortableType
93
+ def build_portable_type_from_named_type(named_type)
94
+ name = named_type.name
95
+ params = named_type.params
96
+
97
+ definition = @old_types[name]
98
+ return build_from_definition(name, definition) if definition
99
+
100
+ primitive = as_primitive(name)
101
+ return primitive if primitive
102
+
103
+ case name
104
+ when 'Vec'
105
+ item_index = use(params[0].to_s)
106
+ SequenceType.new(type: item_index, registry: self)
107
+ when 'Option'
108
+ item_index = use(params[0].to_s)
109
+ VariantType.option(item_index, self)
110
+ when 'Result'
111
+ ok_index = use(params[0].to_s)
112
+ err_index = use(params[1].to_s)
113
+ VariantType.result(ok_index, err_index, self)
114
+ when 'Compact'
115
+ # item_index = use(params[0].to_s)
116
+ # CompactType.new(type: item_index, registry: self)
117
+ CompactType.new
118
+ when 'Null'
119
+ UnitType.new
120
+ else
121
+ raise "Unknown type: #{name}"
122
+ end
123
+ end
124
+
125
+ # % as_primitive :: String -> PrimitiveType | nil
126
+ def as_primitive(name)
127
+ case name.downcase
128
+ when /^i\d+$/
129
+ PrimitiveType.new(primitive: "I#{name[1..]}".to_sym)
130
+ when /^u\d+$/
131
+ PrimitiveType.new(primitive: "U#{name[1..]}".to_sym)
132
+ when /^bool$/
133
+ PrimitiveType.new(primitive: :Bool)
134
+ when /^str$/, /^text$/
135
+ PrimitiveType.new(primitive: :Str)
136
+ else
137
+ nil
138
+ end
139
+ end
140
+
141
+ # % build_from_definition :: String -> OldTypeDefinition -> PortableType | TypeAlias
142
+ #
143
+ # type OldTypeDefinition = String | OldEnumDefinition | OldStructDefinition
144
+ # type OldEnumDefinition = {
145
+ # _enum: String[] | Hash<Symbol, Any>,
146
+ # }
147
+ # type OldStructDefinition = {
148
+ # _struct: Hash<Symbol, Any>
149
+ # }
150
+ def build_from_definition(name, definition) # rubocop:disable Metrics/MethodLength
151
+ case definition
152
+ when String
153
+ # TypeAlias.new(name, use(definition))
154
+ alias_type_id = use(definition)
155
+ # p "alias_type_id: #{alias_type_id}"
156
+ types[alias_type_id]
157
+ when Hash
158
+ if definition['_enum']
159
+ _build_portable_type_from_enum_definition(definition)
160
+ elsif definition['_set']
161
+ raise 'Sets are not supported'
162
+ else
163
+ _build_portable_type_from_struct_definition(definition)
164
+ end
165
+ end
166
+ end
167
+
168
+ private
169
+
170
+ def _indexed_enum?(definition)
171
+ definition['_enum'].is_a?(::Hash) && definition['_enum'].values.all? { |value| value.is_a?(::Integer) }
172
+ end
173
+
174
+ # % _build_portable_type_from_enum_definition :: Hash<Symbol, Any> -> VariantType
175
+ # { '_enum' => ['A', 'B', 'C'] }
176
+ def _build_portable_type_from_enum_definition(definition)
177
+ variants =
178
+ if definition['_enum'].is_a?(::Array)
179
+ # Simple array enum:
180
+ # {
181
+ # '_enum' => ['A', 'B', 'C']
182
+ # }
183
+ definition['_enum'].map.with_index do |variant_name, index|
184
+ SimpleVariant.new(name: variant_name.to_sym, index:)
185
+ end
186
+ elsif definition['_enum'].is_a?(::Hash)
187
+ if _indexed_enum?(definition)
188
+ # Indexed enum:
189
+ # {
190
+ # '_enum' => {
191
+ # 'Variant1' => 0,
192
+ # 'Variant2' => 1,
193
+ # 'Variant3' => 2
194
+ # }
195
+ # }
196
+ definition['_enum'].map do |variant_name, index|
197
+ SimpleVariant.new(name: variant_name.to_sym, index:)
198
+ end
199
+ else
200
+ # Mixed enum:
201
+ # {
202
+ # '_enum' => {
203
+ # 'A' => 'u32',
204
+ # 'B' => {a: 'u32', b: 'u32'},
205
+ # 'C' => null,
206
+ # 'D' => ['u32', 'u32']
207
+ # }
208
+ # }
209
+ definition['_enum'].map.with_index do |(variant_name, variant_def), index|
210
+ case variant_def
211
+ when ::String
212
+ TupleVariant.new(
213
+ name: variant_name.to_sym,
214
+ index:,
215
+ tuple: TupleType.new(
216
+ tuple: [use(variant_def)],
217
+ registry: self
218
+ ),
219
+ )
220
+ when ::Array
221
+ TupleVariant.new(
222
+ name: variant_name.to_sym,
223
+ index:,
224
+ tuple: TupleType.new(
225
+ tuple: variant_def.map { |field_type| use(field_type) },
226
+ registry: self
227
+ )
228
+ )
229
+ when ::Hash
230
+ StructVariant.new(
231
+ name: variant_name.to_sym,
232
+ index:,
233
+ struct: StructType.new(
234
+ fields: variant_def.map do |field_name, field_type|
235
+ Field.new(name: field_name.to_s, type: use(field_type))
236
+ end,
237
+ registry: self
238
+ )
239
+ )
240
+ else
241
+ raise "Unknown variant type for #{variant_name}: #{variant_def.class}"
242
+ end
243
+ end
244
+ end
245
+ end
246
+ VariantType.new(variants:, registry: self)
247
+ end
248
+
249
+ # % _build_portable_type_from_struct_definition :: Hash<String, Any> -> StructType
250
+ def _build_portable_type_from_struct_definition(definition)
251
+ fields = definition.map do |field_name, field_type|
252
+ Field.new(name: field_name.to_s, type: use(field_type))
253
+ end
254
+ StructType.new(fields:, registry: self)
255
+ end
256
+ end
257
+ end
258
+
259
+ module ScaleRb
260
+ class OldRegistry
261
+ module TypeExp
262
+ class Tokenizer
263
+ attr_reader :tokens, :index
264
+
265
+ # % tokenize :: String -> [String]
266
+ def initialize(type_exp)
267
+ @tokens = tokenize(type_exp)
268
+ @index = 0
269
+ end
270
+
271
+ # % next_token :: -> String
272
+ def next_token
273
+ token = @tokens[@index]
274
+ @index += 1
275
+ token
276
+ end
277
+
278
+ # % peek_token :: -> String
279
+ def peek_token
280
+ @tokens[@index]
281
+ end
282
+
283
+ # % eof? :: -> Bool
284
+ def eof?
285
+ @index >= @tokens.length
286
+ end
287
+
288
+ private
289
+
290
+ def tokenize(type_exp)
291
+ tokens = []
292
+ current_token = ''
293
+
294
+ type_exp.each_char do |char|
295
+ case char
296
+ when /[a-zA-Z0-9_]/
297
+ current_token += char
298
+ when ':', '<', '>', '(', ')', '[', ']', ',', ';', '&', "'"
299
+ tokens << current_token unless current_token.empty?
300
+ if char == ':' && tokens.last == ':'
301
+ tokens[-1] = '::'
302
+ else
303
+ tokens << char
304
+ end
305
+ current_token = ''
306
+ when /\s/
307
+ tokens << current_token unless current_token.empty?
308
+ current_token = ''
309
+ else
310
+ raise abort
311
+ end
312
+ end
313
+
314
+ tokens << current_token unless current_token.empty?
315
+ tokens
316
+ end
317
+ end
318
+
319
+ class NamedType
320
+ attr_reader :name, :params
321
+
322
+ def initialize(name, params)
323
+ @name = name
324
+ @params = params
325
+ end
326
+
327
+ def to_s
328
+ params.empty? ? name : "#{name}<#{params.map(&:to_s).join(', ')}>"
329
+ end
330
+ end
331
+
332
+ class ArrayType
333
+ attr_reader :item, :len
334
+
335
+ def initialize(item, len)
336
+ @item = item
337
+ @len = len
338
+ end
339
+
340
+ def to_s
341
+ "[#{item}; #{len}]"
342
+ end
343
+ end
344
+
345
+ class TupleType
346
+ attr_reader :params
347
+
348
+ def initialize(params)
349
+ @params = params
350
+ end
351
+
352
+ def to_s
353
+ "(#{params.map(&:to_s).join(', ')})"
354
+ end
355
+ end
356
+
357
+ # % print :: NamedType | ArrayType | TupleType -> String
358
+ def self.print(type)
359
+ type.to_s
360
+ end
361
+
362
+ # % parse :: String -> NamedType | ArrayType | TupleType
363
+ def self.parse(type_exp)
364
+ TypeExpParser.new(type_exp).parse
365
+ end
366
+
367
+ class TypeExpParser
368
+ def initialize(type_exp)
369
+ @type_exp = type_exp
370
+ @tokenizer = Tokenizer.new(type_exp)
371
+ @current_token = @tokenizer.next_token
372
+ end
373
+
374
+ def parse
375
+ build_type
376
+ end
377
+
378
+ private
379
+
380
+ # Consume and return the current token, or nil if it doesn't equal the expected token.
381
+ def expect(token)
382
+ return unless @current_token == token
383
+
384
+ current_token = @current_token
385
+ @current_token = @tokenizer.next_token
386
+ current_token
387
+ end
388
+
389
+ def expect!(token)
390
+ expect(token) || raise("Expected #{token}, got #{@current_token}")
391
+ end
392
+
393
+ # Consume and return the current token if it matches the expected regex pattern.
394
+ def expect_regex(pattern)
395
+ return unless pattern.match?(@current_token)
396
+
397
+ current_token = @current_token
398
+ @current_token = @tokenizer.next_token
399
+ current_token
400
+ end
401
+
402
+ def expect_regex!(pattern)
403
+ expect_regex(pattern) || raise("Expected current token matching #{pattern.inspect}, got #{@current_token}")
404
+ end
405
+
406
+ # Consume and return a natural number (integer) if the current token matches.
407
+ def expect_nat
408
+ expect_regex(/^\d+$/)&.to_i
409
+ end
410
+
411
+ def expect_nat!
412
+ expect_nat || raise("Expected natural number, got #{@current_token}")
413
+ end
414
+
415
+ def expect_name
416
+ expect_regex(/^[a-zA-Z]\w*$/)
417
+ end
418
+
419
+ def expect_name!
420
+ expect_name || raise("Expected name, got #{@current_token}")
421
+ end
422
+
423
+ def list(sep, &block)
424
+ result = []
425
+ item = block.call
426
+ return result if item.nil?
427
+
428
+ result << item
429
+ while expect(sep)
430
+ item = block.call
431
+ break if item.nil? # (A, B,)
432
+
433
+ result << item
434
+ end
435
+ result
436
+ end
437
+
438
+ def build_tuple_type
439
+ return nil unless expect('(')
440
+
441
+ params = list(',') { build_type }
442
+ expect!(')')
443
+
444
+ TupleType.new(params)
445
+ end
446
+
447
+ # [u8; 16; H128]
448
+ # [u8; 16]
449
+ def build_array_type
450
+ return nil unless expect('[')
451
+
452
+ item = build_type
453
+ raise "Expected array item, got #{@current_token}" if item.nil?
454
+
455
+ expect!(';')
456
+ len = expect_nat!
457
+
458
+ # [u8; 16; H128]
459
+ if expect(';')
460
+ expect_name! # Just consume the name
461
+ end
462
+
463
+ expect!(']')
464
+ ArrayType.new(item, len)
465
+ end
466
+
467
+ def build_named_type
468
+ name = nil
469
+ trait = nil
470
+ item = nil
471
+
472
+ if expect('<')
473
+ # Handle trait syntax: <T::Trait as OtherTrait>::Type
474
+ # name trait item
475
+ # '<T::InherentOfflineReport as InherentOfflineReport>::Inherent' -> 'InherentOfflineReport'
476
+ # '<T::Balance as HasCompact>' -> 'Compact<Balance>'
477
+ # '<T as Trait<I>>::Proposal' -> 'Proposal'
478
+ name = build_named_type.name
479
+ expect!('as')
480
+ trait = build_named_type.name
481
+ expect!('>')
482
+ else
483
+ name = expect_name
484
+ return if name.nil?
485
+ end
486
+
487
+ # Consume the :: and get the next name
488
+ item = expect_name while expect('::')
489
+
490
+ # Handle special cases
491
+ # From subsquid's code. But where are these coming from?
492
+ if name == 'InherentOfflineReport' && name == trait && item == 'Inherent'
493
+ # Do nothing
494
+ elsif name == 'exec' && item == 'StorageKey'
495
+ name = 'ContractStorageKey'
496
+ elsif name == 'Lookup' && item == 'Source'
497
+ name = 'LookupSource'
498
+ elsif name == 'Lookup' && item == 'Target'
499
+ name = 'LookupTarget'
500
+ elsif item
501
+ # '<T::Balance as HasCompact>::Item' will raise error
502
+ raise "Expected item, got #{item}" if trait == 'HasCompact'
503
+
504
+ name = item
505
+ elsif trait == 'HasCompact' # '<T::Balance as HasCompact>'
506
+ return NamedType.new('Compact', [NamedType.new(name, [])])
507
+ end
508
+
509
+ NamedType.new(name, type_parameters)
510
+ end
511
+
512
+ def type_parameters
513
+ if expect('<')
514
+ params = list(',') { expect_nat || build_type }
515
+ expect!('>')
516
+ else
517
+ params = []
518
+ end
519
+
520
+ params
521
+ end
522
+
523
+ # &[u8]
524
+ # &'static [u8]
525
+ def build_pointer_bytes
526
+ return nil unless expect('&') # &
527
+
528
+ expect("'") && expect!('static')
529
+ expect!('[')
530
+ expect!('u8')
531
+ expect!(']')
532
+ NamedType.new('Vec', [NamedType.new('u8', [])])
533
+ end
534
+
535
+ # % build_type :: TupleType | ArrayType | NamedType
536
+ def build_type
537
+ build_tuple_type || build_array_type || build_named_type || build_pointer_bytes
538
+ end
539
+ end
540
+ end
541
+ end
542
+ end
543
+
544
+ # require_relative '../../metadata/metadata'
545
+
546
+ # begin
547
+ # registry = ScaleRb::Metadata::Registry.new ScaleRb::Metadata::TYPES
548
+ # puts registry
549
+ # rescue StandardError => e
550
+ # puts e.message
551
+ # puts e.backtrace.join("\n")
552
+ # end
@@ -24,6 +24,16 @@ module ScaleRb
24
24
  "a_portable_registry"
25
25
  end
26
26
 
27
+ def to_s
28
+ "a_portable_registry"
29
+ end
30
+
31
+ def add_type(type)
32
+ type_id = @types.size
33
+ @types << type
34
+ type_id
35
+ end
36
+
27
37
  private
28
38
 
29
39
  __ :build_types, {}
@@ -36,33 +46,39 @@ module ScaleRb
36
46
  raise "No 'def' found: #{type}" if def_.nil?
37
47
 
38
48
  path = type._get(:type, :path)
49
+ params = type._get(:type, :params).map do |p|
50
+ name = p._get(:name)
51
+ type = p._get(:type)
52
+ type.nil? ? Param.new(name: name) : Param.new(name: name, type: type)
53
+ end
39
54
 
40
55
  type_name = def_.keys.first.to_sym
41
56
  type_def = def_._get(type_name)
42
- @types[id] = _build_type(id, type_name, type_def, path)
57
+ @types[id] = _build_type(id, type_name, type_def, path, params)
43
58
  end
44
59
  end
45
60
 
46
61
  # TODO: type_def better type definition
47
- __ :_build_type, { id: Ti, type_name: Symbol, type_def: Hash | String | Array, path: TypedArray[String] }, PortableType
48
- def _build_type(id, type_name, type_def, path)
62
+ __ :_build_type, { id: Ti, type_name: Symbol, type_def: Hash | String | Array, path: TypedArray[String], params: TypedArray[Field] }, PortableType
63
+ def _build_type(id, type_name, type_def, path, params)
49
64
  case type_name
50
65
  when :primitive
51
66
  # type_def: 'I32'
52
- PrimitiveType.new(primitive: type_def.to_sym, path: path)
67
+ PrimitiveType.new(primitive: type_def.to_sym, path: path, params: params)
53
68
  when :compact
54
69
  # type_def: { type: 1 }
55
- CompactType.new(type: type_def._get(:type), registry: self, path: path)
70
+ CompactType.new(type: type_def._get(:type), registry: self, path: path, params: params)
56
71
  when :sequence
57
72
  # type_def: { type: 9 }
58
- SequenceType.new(type: type_def._get(:type), registry: self, path: path)
73
+ SequenceType.new(type: type_def._get(:type), registry: self, path: path, params: params)
59
74
  when :bitSequence
60
75
  # type_def: {"bitStoreType"=>2, "bitOrderType"=>502}
61
76
  BitSequenceType.new(
62
77
  bit_store_type: type_def._get(:bitStoreType),
63
78
  bit_order_type: type_def._get(:bitOrderType),
64
79
  registry: self,
65
- path: path
80
+ path: path,
81
+ params: params
66
82
  )
67
83
  when :array
68
84
  # type_def: { len: 3, type: 1 }
@@ -70,11 +86,12 @@ module ScaleRb
70
86
  len: type_def._get(:len),
71
87
  type: type_def._get(:type),
72
88
  registry: self,
73
- path: path
89
+ path: path,
90
+ params: params
74
91
  )
75
92
  when :tuple
76
93
  # type_def: [1, 2, 3]
77
- TupleType.new(tuple: type_def, registry: self, path: path)
94
+ TupleType.new(tuple: type_def, registry: self, path: path, params: params)
78
95
  when :composite
79
96
  fields = type_def._get(:fields)
80
97
  first_field = fields.first
@@ -83,7 +100,7 @@ module ScaleRb
83
100
  return UnitType.new(path: path) if first_field.nil?
84
101
 
85
102
  # type_def: {"fields"=>[{"name"=>nil, "type"=>1}, {"name"=>nil, "type"=>2}]}
86
- return TupleType.new(tuple: fields.map { |f| f._get(:type) }, registry: self, path: path) unless first_field._get(:name)
103
+ return TupleType.new(tuple: fields.map { |f| f._get(:type) }, registry: self, path: path, params: params) unless first_field._get(:name)
87
104
 
88
105
  # type_def: { fields: [{ name: 'name', type: 1 }, { name: 'age', type: 2 }] }
89
106
  StructType.new(
@@ -91,7 +108,8 @@ module ScaleRb
91
108
  Field.new(name: field._get(:name), type: field._get(:type))
92
109
  end,
93
110
  registry: self,
94
- path: path
111
+ path: path,
112
+ params: params
95
113
  )
96
114
  when :variant
97
115
  variants = type_def._get(:variants)
@@ -126,7 +144,7 @@ module ScaleRb
126
144
  )
127
145
  end
128
146
  end
129
- VariantType.new(variants: variant_list, path: path)
147
+ VariantType.new(variants: variant_list, path: path, params: params)
130
148
  end
131
149
  end
132
150
  end
@@ -53,11 +53,15 @@ module ScaleRb
53
53
  # data: hex string
54
54
  # type: portable type id
55
55
  # optional: boolean
56
- # fallback: hex string
56
+ # fallback: hex string or u8array
57
57
  # returns nil or data
58
58
  def decode_storage(data, type, optional, fallback, registry)
59
- data ||= (optional ? nil : fallback)
60
- ScaleRb::Codec.decode(type, Utils.hex_to_u8a(data), registry)[0] if data
59
+ bytes = data.nil? ? nil : Utils.hex_to_u8a(data)
60
+ bytes = bytes.nil? ?
61
+ (optional ? nil : (fallback.is_a?(Array) ? fallback : Utils.hex_to_u8a(fallback))) :
62
+ bytes
63
+
64
+ ScaleRb::Codec.decode(type, bytes, registry)[0] if bytes
61
65
  end
62
66
 
63
67
  # storage_item: the storage item from metadata
@@ -69,8 +73,8 @@ module ScaleRb
69
73
  end
70
74
 
71
75
  def decode_storage3(data, pallet_name, item_name, metadata)
72
- registry = Metadata.build_registry(metadata)
73
- storage_item = Metadata.get_storage_item(pallet_name, item_name, metadata)
76
+ registry = metadata.build_registry
77
+ storage_item = metadata.storage(pallet_name, item_name)
74
78
  decode_storage2(data, storage_item, registry)
75
79
  end
76
80
  end