scale_rb 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +6 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +47 -0
- data/LICENSE.txt +21 -0
- data/README.md +42 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/metadata +41 -0
- data/bin/setup +8 -0
- data/lib/client/client.rb +76 -0
- data/lib/client/rpc.rb +60 -0
- data/lib/codec.rb +387 -0
- data/lib/hasher.rb +54 -0
- data/lib/metadata.rb +199 -0
- data/lib/metadata_v14.rb +21 -0
- data/lib/monkey_patching.rb +113 -0
- data/lib/portable_codec.rb +251 -0
- data/lib/registry.rb +13 -0
- data/lib/scale_rb/version.rb +3 -0
- data/lib/scale_rb.rb +39 -0
- data/lib/storage_helper.rb +38 -0
- data/scale_rb.gemspec +31 -0
- metadata +99 -0
data/lib/codec.rb
ADDED
@@ -0,0 +1,387 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# TODO: set, bitvec
|
4
|
+
|
5
|
+
def bytes?(type)
|
6
|
+
type.downcase == 'bytes'
|
7
|
+
end
|
8
|
+
|
9
|
+
def boolean?(type)
|
10
|
+
type.downcase == 'bool' || type.downcase == 'boolean'
|
11
|
+
end
|
12
|
+
|
13
|
+
def string?(type)
|
14
|
+
type.downcase == 'str' || type.downcase == 'string' || type.downcase == 'text'
|
15
|
+
end
|
16
|
+
|
17
|
+
def compact?(type)
|
18
|
+
type.downcase == 'compact' ||
|
19
|
+
(type[0..7].downcase == 'compact<' && type[-1] == '>')
|
20
|
+
end
|
21
|
+
|
22
|
+
def int?(type)
|
23
|
+
type[0].downcase == 'i' && type[1..] =~ /\A(8|16|32|64|128|256|512)\z/
|
24
|
+
end
|
25
|
+
|
26
|
+
def uint?(type)
|
27
|
+
type[0].downcase == 'u' && type[1..] =~ /\A(8|16|32|64|128|256|512)\z/
|
28
|
+
end
|
29
|
+
|
30
|
+
# def bitvec?(type)
|
31
|
+
# end
|
32
|
+
|
33
|
+
def option?(type)
|
34
|
+
type[0..6].downcase == 'option<' && type[-1] == '>'
|
35
|
+
end
|
36
|
+
|
37
|
+
def array?(type)
|
38
|
+
type[0] == '[' && type[-1] == ']'
|
39
|
+
end
|
40
|
+
|
41
|
+
def vec?(type)
|
42
|
+
type[0..3].downcase == 'vec<' && type[-1] == '>'
|
43
|
+
end
|
44
|
+
|
45
|
+
def tuple?(type)
|
46
|
+
type[0] == '(' && type[-1] == ')'
|
47
|
+
end
|
48
|
+
|
49
|
+
def struct?(type)
|
50
|
+
type.instance_of?(Hash)
|
51
|
+
end
|
52
|
+
|
53
|
+
def enum?(type)
|
54
|
+
type.instance_of?(Hash) && type.key?(:_enum)
|
55
|
+
end
|
56
|
+
|
57
|
+
def parse_fixed_array(type)
|
58
|
+
scan_out = type.scan(/\A\[\s*(.+)\s*;\s*(\d+)\s*\]\z/)
|
59
|
+
raise ScaleRb::TypeParseError, type if scan_out.empty?
|
60
|
+
raise ScaleRb::TypeParseError, type if scan_out[0].length != 2
|
61
|
+
|
62
|
+
inner_type = scan_out[0][0]
|
63
|
+
length = scan_out[0][1].to_i
|
64
|
+
[inner_type, length]
|
65
|
+
end
|
66
|
+
|
67
|
+
module ScaleRb
|
68
|
+
class Error < StandardError; end
|
69
|
+
class NotImplemented < Error; end
|
70
|
+
class NilTypeError < Error; end
|
71
|
+
class TypeParseError < Error; end
|
72
|
+
class NotEnoughBytesError < Error; end
|
73
|
+
class InvalidBytesError < Error; end
|
74
|
+
class Unreachable < Error; end
|
75
|
+
class IndexOutOfRangeError < Error; end
|
76
|
+
class LengthNotEqualErr < Error; end
|
77
|
+
class InvalidValueError < Error; end
|
78
|
+
|
79
|
+
class << self
|
80
|
+
def decode(type, bytes, registry = {})
|
81
|
+
logger.debug '--------------------------------------------------'
|
82
|
+
debug 'decoding type', type
|
83
|
+
debug 'bytes', bytes&.length
|
84
|
+
|
85
|
+
if type.instance_of?(String)
|
86
|
+
return decode_bytes(bytes) if bytes?(type) # Bytes
|
87
|
+
return decode_boolean(bytes) if boolean?(type) # Boolean
|
88
|
+
return decode_string(bytes) if string?(type) # String
|
89
|
+
return decode_int(type, bytes) if int?(type) # i8, i16...
|
90
|
+
return decode_uint(type, bytes) if uint?(type) # u8, u16...
|
91
|
+
return decode_compact(bytes) if compact?(type) # Compact<>
|
92
|
+
return decode_option(type, bytes, registry) if option?(type) # Option<>
|
93
|
+
return decode_array(type, bytes, registry) if array?(type) # [u8; 3]
|
94
|
+
return decode_vec(type, bytes, registry) if vec?(type) # Vec<u8>
|
95
|
+
return decode_tuple(type, bytes, registry) if tuple?(type) # (u8, u8)
|
96
|
+
|
97
|
+
# search the type from registry if not the types above
|
98
|
+
registry_type = get_final_type_from_registry(registry, type)
|
99
|
+
return decode(registry_type, bytes, registry) if registry_type
|
100
|
+
elsif type.instance_of?(Hash)
|
101
|
+
return decode_enum(type, bytes, registry) if enum?(type)
|
102
|
+
return decode_struct(type, bytes, registry) if struct?(type)
|
103
|
+
end
|
104
|
+
|
105
|
+
raise NotImplemented, "type: #{type.inspect}"
|
106
|
+
end
|
107
|
+
|
108
|
+
def decode_bytes(bytes)
|
109
|
+
length, remaining_bytes = do_decode_compact(bytes)
|
110
|
+
value = remaining_bytes[0...length].to_hex
|
111
|
+
debug 'length', length
|
112
|
+
debug 'value', value
|
113
|
+
[
|
114
|
+
value,
|
115
|
+
remaining_bytes[length..]
|
116
|
+
]
|
117
|
+
end
|
118
|
+
|
119
|
+
def decode_boolean(bytes)
|
120
|
+
value =
|
121
|
+
if bytes[0] == 0x00
|
122
|
+
false
|
123
|
+
elsif bytes[0] == 0x01
|
124
|
+
true
|
125
|
+
else
|
126
|
+
raise InvalidBytesError, 'type: Boolean'
|
127
|
+
end
|
128
|
+
debug 'value', value
|
129
|
+
[value, bytes[1..]]
|
130
|
+
end
|
131
|
+
|
132
|
+
def decode_string(bytes)
|
133
|
+
length, remaining_bytes = do_decode_compact(bytes)
|
134
|
+
raise NotEnoughBytesError, 'type: String' if remaining_bytes.length < length
|
135
|
+
|
136
|
+
value = remaining_bytes[0...length].to_utf8
|
137
|
+
debug 'byte length', length
|
138
|
+
debug 'value', value.inspect
|
139
|
+
[
|
140
|
+
value,
|
141
|
+
remaining_bytes[length..]
|
142
|
+
]
|
143
|
+
end
|
144
|
+
|
145
|
+
def decode_int(type, bytes)
|
146
|
+
bit_length = type[1..].to_i
|
147
|
+
byte_length = bit_length / 8
|
148
|
+
raise NotEnoughBytesError, "type: #{type}" if bytes.length < byte_length
|
149
|
+
|
150
|
+
value = bytes[0...byte_length].flip.to_int(bit_length)
|
151
|
+
debug 'value', value
|
152
|
+
[
|
153
|
+
value,
|
154
|
+
bytes[byte_length..]
|
155
|
+
]
|
156
|
+
end
|
157
|
+
|
158
|
+
def decode_uint(type, bytes)
|
159
|
+
bit_length = type[1..].to_i
|
160
|
+
byte_length = bit_length / 8
|
161
|
+
raise NotEnoughBytesError, "type: #{type}" if bytes.length < byte_length
|
162
|
+
|
163
|
+
value = bytes[0...byte_length].flip.to_uint
|
164
|
+
debug 'value', value
|
165
|
+
[
|
166
|
+
value,
|
167
|
+
bytes[byte_length..]
|
168
|
+
]
|
169
|
+
end
|
170
|
+
|
171
|
+
def decode_compact(bytes)
|
172
|
+
result = do_decode_compact(bytes)
|
173
|
+
debug 'value', result[0]
|
174
|
+
result
|
175
|
+
end
|
176
|
+
|
177
|
+
def decode_option(type, bytes, registry = {})
|
178
|
+
inner_type = type.scan(/\A[O|o]ption<(.+)>\z/).first.first
|
179
|
+
|
180
|
+
return [nil, bytes[1..]] if bytes[0] == 0x00
|
181
|
+
return decode(inner_type, bytes[1..], registry) if bytes[0] == 0x01
|
182
|
+
|
183
|
+
raise InvalidBytesError, "type: #{type}"
|
184
|
+
end
|
185
|
+
|
186
|
+
def decode_array(type, bytes, registry = {})
|
187
|
+
inner_type, length = parse_fixed_array(type)
|
188
|
+
_decode_types([inner_type] * length, bytes, registry)
|
189
|
+
end
|
190
|
+
|
191
|
+
def decode_vec(type, bytes, registry = {})
|
192
|
+
inner_type = type.scan(/\A[V|v]ec<(.+)>\z/).first.first
|
193
|
+
length, remaining_bytes = do_decode_compact(bytes)
|
194
|
+
debug 'length', length
|
195
|
+
_decode_types([inner_type] * length, remaining_bytes, registry)
|
196
|
+
end
|
197
|
+
|
198
|
+
def decode_tuple(tuple_type, bytes, registry = {})
|
199
|
+
inner_types = tuple_type.scan(/\A\(\s*(.+)\s*\)\z/)[0][0].split(',').map(&:strip)
|
200
|
+
_decode_types(inner_types, bytes, registry)
|
201
|
+
end
|
202
|
+
|
203
|
+
# TODO: custrom index
|
204
|
+
def decode_enum(enum_type, bytes, registry = {})
|
205
|
+
index = bytes[0]
|
206
|
+
raise IndexOutOfRangeError, "type: #{enum_type}" if index > enum_type[:_enum].length - 1
|
207
|
+
|
208
|
+
remaining_bytes = bytes[1..]
|
209
|
+
if enum_type[:_enum].instance_of?(Hash)
|
210
|
+
key = enum_type[:_enum].keys[index]
|
211
|
+
type = enum_type[:_enum].values[index]
|
212
|
+
|
213
|
+
value, remaining_bytes = decode(type, remaining_bytes, registry)
|
214
|
+
[
|
215
|
+
{ key => value },
|
216
|
+
remaining_bytes
|
217
|
+
]
|
218
|
+
elsif enum_type[:_enum].instance_of?(Array)
|
219
|
+
value = enum_type[:_enum][index]
|
220
|
+
debug 'value', value.inspect
|
221
|
+
[
|
222
|
+
value,
|
223
|
+
remaining_bytes
|
224
|
+
]
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def decode_struct(struct, bytes, registry = {})
|
229
|
+
values, remaining_bytes = _decode_types(struct.values, bytes, registry)
|
230
|
+
[
|
231
|
+
[struct.keys, values].transpose.to_h,
|
232
|
+
remaining_bytes
|
233
|
+
]
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def self.get_final_type_from_registry(registry, type)
|
238
|
+
mapped_type = registry[type]
|
239
|
+
if mapped_type.nil?
|
240
|
+
nil
|
241
|
+
elsif registry[mapped_type].nil?
|
242
|
+
mapped_type
|
243
|
+
else
|
244
|
+
get_final_type_from_registry(registry, mapped_type)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
def self._decode_types(type_list, bytes, registry = {})
|
249
|
+
if type_list.empty?
|
250
|
+
[[], bytes]
|
251
|
+
else
|
252
|
+
value, remaining_bytes = decode(type_list.first, bytes, registry)
|
253
|
+
value_list, remaining_bytes = _decode_types(type_list[1..], remaining_bytes, registry)
|
254
|
+
[[value] + value_list, remaining_bytes]
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
def self.do_decode_compact(bytes)
|
259
|
+
case bytes[0] & 3
|
260
|
+
when 0
|
261
|
+
[bytes[0] >> 2, bytes[1..]]
|
262
|
+
when 1
|
263
|
+
[bytes[0..1].flip.to_uint >> 2, bytes[2..]]
|
264
|
+
when 2
|
265
|
+
[bytes[0..3].flip.to_uint >> 2, bytes[4..]]
|
266
|
+
when 3
|
267
|
+
length = 4 + (bytes[0] >> 2)
|
268
|
+
[bytes[1..length].flip.to_uint, bytes[length + 1..]]
|
269
|
+
else
|
270
|
+
raise Unreachable, 'type: Compact'
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
class << self
|
275
|
+
def encode(type, value, registry = {})
|
276
|
+
logger.debug '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>'
|
277
|
+
logger.debug " type: #{type}"
|
278
|
+
logger.debug " value: #{value}"
|
279
|
+
|
280
|
+
bytes = do_encode(type, value, registry)
|
281
|
+
|
282
|
+
logger.debug " encoded: #{bytes}"
|
283
|
+
bytes
|
284
|
+
end
|
285
|
+
|
286
|
+
def do_encode(type, value, registry = {})
|
287
|
+
if type.instance_of?(String)
|
288
|
+
return encode_bytes(value) if bytes?(type)
|
289
|
+
return encode_boolean(value) if boolean?(type)
|
290
|
+
return encode_string(value) if string?(type)
|
291
|
+
return encode_compact(value) if compact?(type)
|
292
|
+
return encode_uint(type, value) if uint?(type)
|
293
|
+
return encode_option(type, value, registry) if option?(type)
|
294
|
+
return encode_array(type, value, registry) if array?(type)
|
295
|
+
return encode_vec(type, value, registry) if vec?(type)
|
296
|
+
return encode_tuple(type, value, registry) if tuple?(type)
|
297
|
+
|
298
|
+
registry_type = get_final_type_from_registry(registry, type)
|
299
|
+
return do_encode(registry_type, value, registry) if registry_type
|
300
|
+
elsif type.instance_of?(Hash)
|
301
|
+
return encode_enum(type, value, registry) if enum?(type)
|
302
|
+
return encode_struct(type, value, registry) if struct?(type)
|
303
|
+
end
|
304
|
+
|
305
|
+
raise NotImplemented, "type: #{type}, value: #{value.inspect}"
|
306
|
+
end
|
307
|
+
|
308
|
+
def encode_bytes(value)
|
309
|
+
encode_compact(value.length) + value
|
310
|
+
end
|
311
|
+
|
312
|
+
def encode_boolean(value)
|
313
|
+
return [0x00] if value == false
|
314
|
+
return [0x01] if value == true
|
315
|
+
|
316
|
+
raise InvalidValueError, "type: Boolean, value: #{value.inspect}"
|
317
|
+
end
|
318
|
+
|
319
|
+
def encode_string(string)
|
320
|
+
body = string.unpack('C*')
|
321
|
+
prefix = encode_compact(body.length)
|
322
|
+
prefix + body
|
323
|
+
end
|
324
|
+
|
325
|
+
def encode_compact(value)
|
326
|
+
return [value << 2] if (value >= 0) && (value < 64)
|
327
|
+
return ((value << 2) + 1).to_bytes.flip if value < 2**14
|
328
|
+
return ((value << 2) + 2).to_bytes.flip if value < 2**30
|
329
|
+
|
330
|
+
bytes = value.to_bytes.flip
|
331
|
+
[(((bytes.length - 4) << 2) + 3)] + bytes
|
332
|
+
end
|
333
|
+
|
334
|
+
def encode_uint(type, value)
|
335
|
+
bit_length = type[1..].to_i
|
336
|
+
value.to_bytes(bit_length).flip
|
337
|
+
end
|
338
|
+
|
339
|
+
def encode_option(type, value, registry = {})
|
340
|
+
return [0x00] if value.nil?
|
341
|
+
|
342
|
+
inner_type = type.scan(/\A[O|o]ption<(.+)>\z/).first.first
|
343
|
+
[0x01] + do_encode(inner_type, value, registry)
|
344
|
+
end
|
345
|
+
|
346
|
+
def encode_array(type, array, registry = {})
|
347
|
+
inner_type, length = parse_fixed_array(type)
|
348
|
+
raise LengthNotEqualErr, "type: #{type}, value: #{array.inspect}" if length != array.length
|
349
|
+
|
350
|
+
_encode_types([inner_type] * length, array, registry)
|
351
|
+
end
|
352
|
+
|
353
|
+
def encode_vec(type, array, registry = {})
|
354
|
+
inner_type = type.scan(/\A[V|v]ec<(.+)>\z/).first.first
|
355
|
+
length_bytes = encode_compact(array.length)
|
356
|
+
length_bytes + _encode_types([inner_type] * array.length, array, registry)
|
357
|
+
end
|
358
|
+
|
359
|
+
def encode_tuple(tuple_type, tuple, registry = {})
|
360
|
+
inner_types = tuple_type.scan(/\A\(\s*(.+)\s*\)\z/)[0][0].split(',').map(&:strip)
|
361
|
+
_encode_types(inner_types, tuple, registry)
|
362
|
+
end
|
363
|
+
|
364
|
+
def encode_enum(enum_type, enum, registry = {})
|
365
|
+
key = enum.keys.first
|
366
|
+
value = enum.values.first
|
367
|
+
value_type = enum_type[:_enum][key]
|
368
|
+
index = enum_type[:_enum].keys.index(key)
|
369
|
+
encode_uint('u8', index) + do_encode(value_type, value, registry)
|
370
|
+
end
|
371
|
+
|
372
|
+
def encode_struct(struct_type, struct, registry = {})
|
373
|
+
_encode_types(struct_type.values, struct.values, registry)
|
374
|
+
end
|
375
|
+
|
376
|
+
def _encode_types(type_list, value_list, registry = {})
|
377
|
+
raise LengthNotEqualErr, "type: #{type_list}, value: #{value_list.inspect}" if type_list.length != value_list.length
|
378
|
+
|
379
|
+
if type_list.empty?
|
380
|
+
[]
|
381
|
+
else
|
382
|
+
bytes = do_encode(type_list.first, value_list.first, registry)
|
383
|
+
bytes + _encode_types(type_list[1..], value_list[1..], registry)
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
data/lib/hasher.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'xxhash'
|
4
|
+
require 'blake2b'
|
5
|
+
|
6
|
+
module Hasher
|
7
|
+
class << self
|
8
|
+
# params:
|
9
|
+
# hasher: 'Identity' | 'Twox64Concat' | 'Blake2128Concat'
|
10
|
+
# bytes: u8 array
|
11
|
+
# return: u8 array
|
12
|
+
def apply_hasher(hasher, bytes)
|
13
|
+
function_name = hasher.gsub('_', '').underscore
|
14
|
+
Hasher.send(function_name, bytes)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class << self
|
19
|
+
def identity(bytes)
|
20
|
+
bytes
|
21
|
+
end
|
22
|
+
|
23
|
+
def twox64_concat(bytes)
|
24
|
+
data = bytes.to_utf8
|
25
|
+
twox64(data) + bytes
|
26
|
+
end
|
27
|
+
|
28
|
+
def blake2128_concat(bytes)
|
29
|
+
blake2_128(bytes) + bytes
|
30
|
+
end
|
31
|
+
|
32
|
+
def twox64(str)
|
33
|
+
result = XXhash.xxh64 str, 0
|
34
|
+
result.to_bytes.reverse
|
35
|
+
end
|
36
|
+
|
37
|
+
def twox128(str)
|
38
|
+
bytes = []
|
39
|
+
2.times do |i|
|
40
|
+
result = XXhash.xxh64 str, i
|
41
|
+
bytes += result.to_bytes.reverse
|
42
|
+
end
|
43
|
+
bytes
|
44
|
+
end
|
45
|
+
|
46
|
+
def blake2_128(bytes)
|
47
|
+
Blake2b.hex(bytes, 16).to_bytes
|
48
|
+
end
|
49
|
+
|
50
|
+
def blake2_256(bytes)
|
51
|
+
Blake2b.hex(bytes, 32).to_bytes
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/metadata.rb
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Metadata
|
4
|
+
class << self
|
5
|
+
def decode_metadata(bytes)
|
6
|
+
metadata, = ScaleRb.decode('MetadataTop', bytes, TYPES)
|
7
|
+
metadata
|
8
|
+
end
|
9
|
+
|
10
|
+
def build_registry(metadata)
|
11
|
+
raise ScaleRb::NotImplemented, metadata._get(:metadata).keys.first unless metadata._get(:metadata)._key?(:v14)
|
12
|
+
|
13
|
+
metadata_v14 = metadata._get(:metadata)._get(:v14)
|
14
|
+
MetadataV14.build_registry(metadata_v14)
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_storage_item(pallet_name, item_name, metadata)
|
18
|
+
raise ScaleRb::NotImplemented, metadata._get(:metadata).keys.first unless metadata._get(:metadata)._key?(:v14)
|
19
|
+
|
20
|
+
metadata_v14 = metadata._get(:metadata)._get(:v14)
|
21
|
+
MetadataV14.get_storage_item(pallet_name, item_name, metadata_v14)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
TYPES = {
|
26
|
+
'MetadataTop' => {
|
27
|
+
magic_number: 'U32',
|
28
|
+
metadata: 'Metadata'
|
29
|
+
},
|
30
|
+
'Metadata' => {
|
31
|
+
_enum: {
|
32
|
+
v0: 'MetadataV0',
|
33
|
+
v1: 'MetadataV1',
|
34
|
+
v2: 'MetadataV2',
|
35
|
+
v3: 'MetadataV3',
|
36
|
+
v4: 'MetadataV4',
|
37
|
+
v5: 'MetadataV5',
|
38
|
+
v6: 'MetadataV6',
|
39
|
+
v7: 'MetadataV7',
|
40
|
+
v8: 'MetadataV8',
|
41
|
+
v9: 'MetadataV9',
|
42
|
+
v10: 'MetadataV10',
|
43
|
+
v11: 'MetadataV11',
|
44
|
+
v12: 'MetadataV12',
|
45
|
+
v13: 'MetadataV13',
|
46
|
+
v14: 'MetadataV14'
|
47
|
+
}
|
48
|
+
},
|
49
|
+
|
50
|
+
'MetadataV14' => {
|
51
|
+
lookup: 'PortableRegistry',
|
52
|
+
pallets: 'Vec<PalletMetadataV14>',
|
53
|
+
extrinsic: 'ExtrinsicMetadataV14',
|
54
|
+
type: 'SiLookupTypeId'
|
55
|
+
},
|
56
|
+
|
57
|
+
# PortableRegistry begin
|
58
|
+
'PortableRegistry' => {
|
59
|
+
types: 'Vec<PortableTypeV14>'
|
60
|
+
},
|
61
|
+
'PortableTypeV14' => {
|
62
|
+
id: 'Si1LookupTypeId',
|
63
|
+
type: 'Si1Type'
|
64
|
+
},
|
65
|
+
'Si1LookupTypeId' => 'Compact',
|
66
|
+
'Si1Type' => {
|
67
|
+
path: 'Si1Path',
|
68
|
+
params: 'Vec<Si1TypeParameter>',
|
69
|
+
def: 'Si1TypeDef',
|
70
|
+
docs: 'Vec<Text>'
|
71
|
+
},
|
72
|
+
'Si1Path' => 'Vec<Text>',
|
73
|
+
'Si1TypeParameter' => {
|
74
|
+
name: 'Text',
|
75
|
+
type: 'Option<Si1LookupTypeId>'
|
76
|
+
},
|
77
|
+
'Si1TypeDef' => {
|
78
|
+
_enum: {
|
79
|
+
composite: 'Si1TypeDefComposite',
|
80
|
+
variant: 'Si1TypeDefVariant',
|
81
|
+
sequence: 'Si1TypeDefSequence',
|
82
|
+
array: 'Si1TypeDefArray',
|
83
|
+
tuple: 'Si1TypeDefTuple',
|
84
|
+
primitive: 'Si1TypeDefPrimitive',
|
85
|
+
compact: 'Si1TypeDefCompact',
|
86
|
+
bitSequence: 'Si1TypeDefBitSequence',
|
87
|
+
historicMetaCompat: 'Text' # TODO: sanitize?
|
88
|
+
}
|
89
|
+
},
|
90
|
+
'Si1TypeDefComposite' => {
|
91
|
+
fields: 'Vec<Si1Field>'
|
92
|
+
},
|
93
|
+
'Si1Field' => {
|
94
|
+
name: 'Option<Text>',
|
95
|
+
type: 'Si1LookupTypeId',
|
96
|
+
typeName: 'Option<Text>',
|
97
|
+
docs: 'Vec<Text>'
|
98
|
+
},
|
99
|
+
'Si1TypeDefVariant' => {
|
100
|
+
variants: 'Vec<Si1Variant>'
|
101
|
+
},
|
102
|
+
'Si1Variant' => {
|
103
|
+
name: 'Text',
|
104
|
+
fields: 'Vec<Si1Field>',
|
105
|
+
index: 'u8',
|
106
|
+
docs: 'Vec<Text>'
|
107
|
+
},
|
108
|
+
'Si1TypeDefSequence' => {
|
109
|
+
type: 'Si1LookupTypeId'
|
110
|
+
},
|
111
|
+
'Si1TypeDefArray' => {
|
112
|
+
len: 'u32',
|
113
|
+
type: 'Si1LookupTypeId'
|
114
|
+
},
|
115
|
+
'Si1TypeDefTuple' => 'Vec<Si1LookupTypeId>',
|
116
|
+
'Si1TypeDefPrimitive' => {
|
117
|
+
_enum: %w[
|
118
|
+
Bool Char Str U8 U16 U32 U64 U128 U256 I8 I16 I32 I64 I128 I256
|
119
|
+
]
|
120
|
+
},
|
121
|
+
'Si1TypeDefCompact' => {
|
122
|
+
type: 'Si1LookupTypeId'
|
123
|
+
},
|
124
|
+
'Si1TypeDefBitSequence' => {
|
125
|
+
bitStoreType: 'Si1LookupTypeId',
|
126
|
+
bitOrderType: 'Si1LookupTypeId'
|
127
|
+
},
|
128
|
+
# PortableRegistry end
|
129
|
+
|
130
|
+
# PalletMetadataV14 begin
|
131
|
+
'PalletMetadataV14' => {
|
132
|
+
name: 'Text',
|
133
|
+
storage: 'Option<PalletStorageMetadataV14>',
|
134
|
+
calls: 'Option<PalletCallMetadataV14>',
|
135
|
+
events: 'Option<PalletEventMetadataV14>',
|
136
|
+
constants: 'Vec<PalletConstantMetadataV14>',
|
137
|
+
errors: 'Option<PalletErrorMetadataV14>',
|
138
|
+
index: 'U8'
|
139
|
+
},
|
140
|
+
'PalletStorageMetadataV14' => {
|
141
|
+
prefix: 'Text',
|
142
|
+
items: 'Vec<StorageEntryMetadataV14>'
|
143
|
+
},
|
144
|
+
'StorageEntryMetadataV14' => {
|
145
|
+
name: 'Text',
|
146
|
+
modifier: 'StorageEntryModifierV14',
|
147
|
+
type: 'StorageEntryTypeV14',
|
148
|
+
fallback: 'Bytes',
|
149
|
+
docs: 'Vec<Text>'
|
150
|
+
},
|
151
|
+
'StorageEntryModifierV14' => {
|
152
|
+
_enum: %w[Optional Default Required]
|
153
|
+
},
|
154
|
+
'StorageEntryTypeV14' => {
|
155
|
+
_enum: {
|
156
|
+
plain: 'SiLookupTypeId',
|
157
|
+
map: {
|
158
|
+
hashers: 'Vec<StorageHasherV14>',
|
159
|
+
key: 'SiLookupTypeId',
|
160
|
+
value: 'SiLookupTypeId'
|
161
|
+
}
|
162
|
+
}
|
163
|
+
},
|
164
|
+
'StorageHasherV14' => {
|
165
|
+
_enum: %w[Blake2128 Blake2256 Blake2128Concat Twox128 Twox256 Twox64Concat Identity]
|
166
|
+
},
|
167
|
+
'PalletCallMetadataV14' => {
|
168
|
+
type: 'Si1LookupTypeId'
|
169
|
+
},
|
170
|
+
'PalletEventMetadataV14' => {
|
171
|
+
type: 'SiLookupTypeId'
|
172
|
+
},
|
173
|
+
'PalletConstantMetadataV14' => {
|
174
|
+
name: 'Text',
|
175
|
+
type: 'SiLookupTypeId',
|
176
|
+
value: 'Bytes',
|
177
|
+
docs: 'Vec<Text>'
|
178
|
+
},
|
179
|
+
'PalletErrorMetadataV14' => {
|
180
|
+
type: 'SiLookupTypeId'
|
181
|
+
},
|
182
|
+
# PalletMetadataV14 end
|
183
|
+
|
184
|
+
# ExtrinsicMetadataV14 begin
|
185
|
+
'ExtrinsicMetadataV14' => {
|
186
|
+
type: 'SiLookupTypeId',
|
187
|
+
version: 'u8',
|
188
|
+
signedExtensions: 'Vec<SignedExtensionMetadataV14>'
|
189
|
+
},
|
190
|
+
'SignedExtensionMetadataV14' => {
|
191
|
+
identifier: 'Text',
|
192
|
+
type: 'SiLookupTypeId',
|
193
|
+
additionalSigned: 'SiLookupTypeId'
|
194
|
+
},
|
195
|
+
# ExtrinsicMetadataV14 end
|
196
|
+
|
197
|
+
'SiLookupTypeId' => 'Compact'
|
198
|
+
}.freeze
|
199
|
+
end
|
data/lib/metadata_v14.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MetadataV14
|
4
|
+
class << self
|
5
|
+
def build_registry(metadata)
|
6
|
+
types = metadata._get(:lookup)._get(:types)
|
7
|
+
types.map { |type| [type._get(:id), type._get(:type)] }.to_h
|
8
|
+
end
|
9
|
+
|
10
|
+
def get_storage_item(pallet_name, item_name, metadata)
|
11
|
+
pallet =
|
12
|
+
metadata._get(:pallets).find do |p|
|
13
|
+
p._get(:name) == pallet_name
|
14
|
+
end
|
15
|
+
|
16
|
+
pallet._get(:storage)._get(:items).find do |item|
|
17
|
+
item._get(:name) == item_name
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|