scale_rb 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -24,9 +24,15 @@ module ScaleRb
24
24
  UnsignedInteger = Types::Strict::Integer.constrained(gteq: 0)
25
25
  TypedArray = ->(type) { Types::Array.of(type) }
26
26
 
27
+ class Param < Dry::Struct
28
+ attribute :name, Types::Strict::String
29
+ attribute? :type, Ti
30
+ end
31
+
27
32
  class Base < Dry::Struct
28
33
  attribute? :registry, Registry
29
34
  attribute? :path, Types::Strict::Array.of(Types::Strict::String)
35
+ attribute? :params, Types::Strict::Array.of(Param)
30
36
 
31
37
  def t(type_id)
32
38
  raise 'No registry' unless registry
@@ -1,3 +1,3 @@
1
1
  module ScaleRb
2
- VERSION = '0.5.1'
2
+ VERSION = '0.5.2'
3
3
  end