scale.rb 0.2.16 → 0.3.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 +4 -4
- data/.gitignore +1 -0
- data/Cargo.lock +8 -4
- data/Cargo.toml +2 -3
- data/Dockerfile +4 -1
- data/Gemfile.lock +43 -35
- data/README.md +44 -1
- data/Rakefile +6 -0
- data/exe/scale +39 -79
- data/lib/address.rb +3 -0
- data/lib/common.rb +163 -0
- data/lib/helper.rb +25 -8
- data/lib/metadata/metadata.rb +28 -18
- data/lib/metadata/metadata_v0.rb +24 -20
- data/lib/metadata/metadata_v1.rb +13 -9
- data/lib/metadata/metadata_v10.rb +2 -2
- data/lib/metadata/metadata_v11.rb +2 -2
- data/lib/metadata/metadata_v12.rb +9 -8
- data/lib/metadata/metadata_v13.rb +161 -0
- data/lib/metadata/metadata_v2.rb +2 -2
- data/lib/metadata/metadata_v3.rb +2 -2
- data/lib/metadata/metadata_v4.rb +21 -11
- data/lib/metadata/metadata_v5.rb +21 -11
- data/lib/metadata/metadata_v6.rb +9 -9
- data/lib/metadata/metadata_v7.rb +26 -15
- data/lib/metadata/metadata_v8.rb +9 -9
- data/lib/metadata/metadata_v9.rb +2 -2
- data/lib/scale.rb +41 -341
- data/lib/scale/base.rb +177 -95
- data/lib/scale/block.rb +17 -13
- data/lib/scale/trie.rb +1 -1
- data/lib/scale/types.rb +139 -40
- data/lib/scale/version.rb +1 -1
- data/lib/scale_bytes.rb +63 -0
- data/lib/substrate_client.rb +31 -17
- data/lib/type_builder.rb +279 -0
- data/lib/type_registry.rb +91 -0
- data/lib/type_registry/crab.json +676 -595
- data/lib/type_registry/darwinia.json +730 -554
- data/lib/type_registry/default.json +3 -2
- data/lib/type_registry/pangolin.json +771 -0
- data/scale.gemspec +7 -5
- data/scripts/mmr_root_to_sign.rb +10 -0
- data/src/lib.rs +80 -25
- metadata +59 -30
- data/lib/type_registry/edgeware.json +0 -124
- data/lib/type_registry/joystream.json +0 -49
- data/lib/type_registry/kulupu.json +0 -15
- data/lib/type_registry/plasm.json +0 -89
- data/lib/type_registry/robonomics.json +0 -39
- data/lib/type_registry/westend.json +0 -63
- data/src/storage_key.rs +0 -41
data/lib/scale/version.rb
CHANGED
data/lib/scale_bytes.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
module Scale
|
2
|
+
class Bytes
|
3
|
+
attr_reader :data, :bytes
|
4
|
+
attr_reader :offset
|
5
|
+
|
6
|
+
def initialize(data)
|
7
|
+
if (data.class == Array) && data.is_byte_array?
|
8
|
+
@bytes = data
|
9
|
+
elsif (data.class == String) && data.start_with?("0x") && (data.length % 2 == 0)
|
10
|
+
arr = data[2..].scan(/../).map(&:hex)
|
11
|
+
@bytes = arr
|
12
|
+
else
|
13
|
+
raise "Provided data is not valid"
|
14
|
+
end
|
15
|
+
|
16
|
+
@data = data
|
17
|
+
@offset = 0
|
18
|
+
end
|
19
|
+
|
20
|
+
def reset_offset
|
21
|
+
@offset = 0
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_next_bytes(length)
|
25
|
+
result = @bytes[@offset...@offset + length]
|
26
|
+
if result.length < length
|
27
|
+
str = @data[(2 + @offset * 2)..]
|
28
|
+
str = str.length > 40 ? (str[0...40]).to_s + "..." : str
|
29
|
+
raise "No enough data: #{str}, expect length: #{length}, but #{result.length}"
|
30
|
+
end
|
31
|
+
@offset += length
|
32
|
+
result
|
33
|
+
rescue RangeError => ex
|
34
|
+
puts "length: #{length}"
|
35
|
+
puts ex.message
|
36
|
+
puts ex.backtrace
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_remaining_bytes
|
40
|
+
@bytes[offset..]
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_hex_string
|
44
|
+
@bytes.bytes_to_hex
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_bin_string
|
48
|
+
@bytes.bytes_to_bin
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_ascii
|
52
|
+
@bytes[0...offset].pack("C*") + "<================================>" + @bytes[offset..].pack("C*")
|
53
|
+
end
|
54
|
+
|
55
|
+
def ==(other)
|
56
|
+
bytes == other.bytes && offset == other.offset
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_s
|
60
|
+
green(@bytes[0...offset].bytes_to_hex) + yellow(@bytes[offset..].bytes_to_hex[2..])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/substrate_client.rb
CHANGED
@@ -1,20 +1,30 @@
|
|
1
|
+
require "faye/websocket"
|
2
|
+
require "eventmachine"
|
1
3
|
|
2
4
|
def ws_request(url, payload)
|
3
5
|
result = nil
|
4
|
-
Kontena::Websocket::Client.connect(url, {}) do |client|
|
5
|
-
client.send(payload.to_json)
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
EM.run do
|
8
|
+
ws = Faye::WebSocket::Client.new(url)
|
9
|
+
|
10
|
+
ws.on :open do |event|
|
11
|
+
ws.send(payload.to_json)
|
12
|
+
end
|
13
|
+
|
14
|
+
ws.on :message do |event|
|
15
|
+
if event.data.include?("jsonrpc")
|
16
|
+
result = JSON.parse event.data
|
17
|
+
ws.close(3001, "data received")
|
18
|
+
EM.stop
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
ws.on :close do |event|
|
23
|
+
ws = nil
|
10
24
|
end
|
11
25
|
end
|
12
26
|
|
13
|
-
|
14
|
-
rescue Kontena::Websocket::CloseError => e
|
15
|
-
raise SubstrateClient::WebsocketError, e.reason
|
16
|
-
rescue Kontena::Websocket::Error => e
|
17
|
-
raise SubstrateClient::WebsocketError, e.reason
|
27
|
+
result
|
18
28
|
end
|
19
29
|
|
20
30
|
class SubstrateClient
|
@@ -29,6 +39,7 @@ class SubstrateClient
|
|
29
39
|
@url = url
|
30
40
|
@request_id = 1
|
31
41
|
@metadata_cache = {}
|
42
|
+
init_types_and_metadata
|
32
43
|
end
|
33
44
|
|
34
45
|
def request(method, params)
|
@@ -122,19 +133,22 @@ class SubstrateClient
|
|
122
133
|
events_data = state_getStorage storage_key, block_hash
|
123
134
|
|
124
135
|
scale_bytes = Scale::Bytes.new(events_data)
|
125
|
-
Scale::Types.get("Vec<EventRecord>").decode(scale_bytes).to_human
|
136
|
+
decoded = Scale::Types.get("Vec<EventRecord>").decode(scale_bytes).to_human
|
137
|
+
[events_data, decoded]
|
126
138
|
end
|
127
139
|
|
128
|
-
# Plain: client.get_storage("Sudo", "Key")
|
129
|
-
# Plain: client.get_storage("Balances", "TotalIssuance")
|
130
|
-
# Map: client.get_storage("System", "Account", ["0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"])
|
131
|
-
# DoubleMap: client.get_storage("ImOnline", "AuthoredBlocks", [2818, "0x749ddc93a65dfec3af27cc7478212cb7d4b0c0357fef35a0163966ab5333b757"])
|
132
140
|
def get_storage(module_name, storage_name, params = nil, block_hash = nil)
|
133
141
|
self.init_types_and_metadata(block_hash)
|
134
142
|
|
135
|
-
storage_key, return_type = SubstrateClient::Helper.generate_storage_key_from_metadata(@metadata, module_name, storage_name, params)
|
143
|
+
storage_key, return_type, storage_item = SubstrateClient::Helper.generate_storage_key_from_metadata(@metadata, module_name, storage_name, params)
|
144
|
+
|
136
145
|
data = self.state_getStorage(storage_key, block_hash)
|
137
|
-
|
146
|
+
|
147
|
+
if data.nil?
|
148
|
+
return if storage_item[:modifier] == "Optional"
|
149
|
+
|
150
|
+
data = storage_item[:fallback]
|
151
|
+
end
|
138
152
|
|
139
153
|
bytes = Scale::Bytes.new(data)
|
140
154
|
type = Scale::Types.get(return_type)
|
data/lib/type_builder.rb
ADDED
@@ -0,0 +1,279 @@
|
|
1
|
+
module Scale
|
2
|
+
module Types
|
3
|
+
class << self
|
4
|
+
|
5
|
+
# type_info: type_string or type_def
|
6
|
+
# type_string: hard coded type name, Compact, H128, Vec<Compact>, (U32, U128), ...
|
7
|
+
# type_def : struct, enum, set
|
8
|
+
#
|
9
|
+
# if type_string start_with Scale::Types::, it is treat as a hard coded type
|
10
|
+
def get(type_info)
|
11
|
+
if type_info.class == ::String
|
12
|
+
if type_info.start_with?('Scale::Types::')
|
13
|
+
return get_hard_coded_type(type_info)
|
14
|
+
end
|
15
|
+
|
16
|
+
# find the final type from registry
|
17
|
+
type_info = fix_name(type_info)
|
18
|
+
type_info = get_final_type_from_registry(type_info)
|
19
|
+
end
|
20
|
+
|
21
|
+
build_type(type_info)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def build_type(type_info)
|
26
|
+
# 1. hard coded types, 2. Vec<...>, 3. Option<...>, 4. [xx; x], 5. (x, y)
|
27
|
+
if type_info.class == ::String
|
28
|
+
type_string = fix_name(type_info)
|
29
|
+
if type_string =~ /\AVec<.+>\z/
|
30
|
+
build_vec(type_string)
|
31
|
+
elsif type_info =~ /\AOption<.+>\z/
|
32
|
+
build_option(type_string)
|
33
|
+
elsif type_info =~ /\A\[.+;\s*\d+\]\z/
|
34
|
+
build_array(type_string)
|
35
|
+
elsif type_info =~ /\A\(.+\)\z/
|
36
|
+
build_tuple(type_string)
|
37
|
+
else
|
38
|
+
get_hard_coded_type(type_string)
|
39
|
+
end
|
40
|
+
|
41
|
+
# 5. Struct, 6. Enum, 7. Set
|
42
|
+
else
|
43
|
+
|
44
|
+
if type_info["type"] == "struct"
|
45
|
+
build_struct(type_info)
|
46
|
+
elsif type_info["type"] == "enum"
|
47
|
+
build_enum(type_info)
|
48
|
+
elsif type_info["type"] == "set"
|
49
|
+
build_set(type_info)
|
50
|
+
else
|
51
|
+
raise Scale::TypeBuildError.new("Failed to build a type from #{type_info}")
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_final_type_from_registry(type_info)
|
58
|
+
type_registry = TypeRegistry.instance
|
59
|
+
if type_registry.types.nil?
|
60
|
+
raise TypeRegistryNotLoadYet
|
61
|
+
end
|
62
|
+
TypeRegistry.instance.get(type_info)
|
63
|
+
end
|
64
|
+
|
65
|
+
def get_hard_coded_type(type_name)
|
66
|
+
# type_name = rename(type_name)
|
67
|
+
type_name = (type_name.start_with?("Scale::Types::") ? type_name : "Scale::Types::#{type_name}")
|
68
|
+
type_name.constantize2
|
69
|
+
rescue => e
|
70
|
+
raise Scale::TypeBuildError.new("Failed to get the hard coded type named `#{type_name}`")
|
71
|
+
end
|
72
|
+
|
73
|
+
def build_vec(type_string)
|
74
|
+
inner_type_str = type_string.scan(/\AVec<(.+)>\z/).first.first
|
75
|
+
inner_type = get(inner_type_str)
|
76
|
+
|
77
|
+
type_name = "Vec_#{inner_type.name.gsub('Scale::Types::', '')}_"
|
78
|
+
|
79
|
+
if !Scale::Types.const_defined?(type_name)
|
80
|
+
klass = Class.new do
|
81
|
+
include Scale::Types::Vec
|
82
|
+
inner_type inner_type
|
83
|
+
end
|
84
|
+
Scale::Types.const_set type_name, klass
|
85
|
+
else
|
86
|
+
Scale::Types.const_get type_name
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def build_option(type_string)
|
91
|
+
inner_type_str = type_string.scan(/\AOption<(.+)>\z/).first.first
|
92
|
+
|
93
|
+
# an exception
|
94
|
+
# https://substrate.dev/docs/en/knowledgebase/advanced/codec#options
|
95
|
+
return get("Scale::Types::OptionBool") if inner_type_str.camelize2 == "Bool"
|
96
|
+
|
97
|
+
inner_type = get(inner_type_str)
|
98
|
+
|
99
|
+
type_name = "Option_#{inner_type.name.gsub('Scale::Types::', '')}_"
|
100
|
+
|
101
|
+
if !Scale::Types.const_defined?(type_name)
|
102
|
+
klass = Class.new do
|
103
|
+
include Scale::Types::Option
|
104
|
+
inner_type inner_type
|
105
|
+
end
|
106
|
+
Scale::Types.const_set type_name, klass
|
107
|
+
else
|
108
|
+
Scale::Types.const_get type_name
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def build_array(type_string)
|
113
|
+
scan_result = type_string.scan /\[(.+);\s*(\d+)\]/
|
114
|
+
|
115
|
+
#
|
116
|
+
inner_type_str = scan_result[0][0]
|
117
|
+
inner_type = get(inner_type_str)
|
118
|
+
|
119
|
+
#
|
120
|
+
len = scan_result[0][1].to_i
|
121
|
+
|
122
|
+
type_name = "Array_#{inner_type.name.gsub('Scale::Types::', '')}_#{len}_"
|
123
|
+
|
124
|
+
if !Scale::Types.const_defined?(type_name)
|
125
|
+
klass = Class.new do
|
126
|
+
include Scale::Types::Array
|
127
|
+
inner_type inner_type
|
128
|
+
length len
|
129
|
+
end
|
130
|
+
Scale::Types.const_set type_name, klass
|
131
|
+
else
|
132
|
+
Scale::Types.const_get type_name
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def build_tuple(type_string)
|
137
|
+
scan_result = type_string.scan /\A\((.+)\)\z/
|
138
|
+
inner_types_str = scan_result[0][0]
|
139
|
+
inner_type_strs = inner_types_str.split(",").map do |inner_type_str|
|
140
|
+
inner_type_str.strip
|
141
|
+
end
|
142
|
+
|
143
|
+
inner_types = inner_type_strs.map do |inner_type_str|
|
144
|
+
get(inner_type_str)
|
145
|
+
end
|
146
|
+
|
147
|
+
type_name = "Tuple_#{inner_types.map {|inner_type| inner_type.name.gsub('Scale::Types::', '')}.join("_")}_"
|
148
|
+
if !Scale::Types.const_defined?(type_name)
|
149
|
+
klass = Class.new do
|
150
|
+
include Scale::Types::Tuple
|
151
|
+
inner_types(*inner_types)
|
152
|
+
end
|
153
|
+
Scale::Types.const_set type_name, klass
|
154
|
+
else
|
155
|
+
Scale::Types.const_get type_name
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def build_struct(type_info)
|
160
|
+
# items: {"a" => Type}
|
161
|
+
items = type_info["type_mapping"].map do |item|
|
162
|
+
item_name = item[0]
|
163
|
+
item_type = get(item[1])
|
164
|
+
[item_name, item_type]
|
165
|
+
end.to_h
|
166
|
+
|
167
|
+
partials = []
|
168
|
+
items.each_pair do |item_name, item_type|
|
169
|
+
partials << item_name.camelize2 + 'In' + item_type.name.gsub('Scale::Types::', '')
|
170
|
+
end
|
171
|
+
type_name = "Struct_#{partials.join('_')}_"
|
172
|
+
|
173
|
+
if !Scale::Types.const_defined?(type_name)
|
174
|
+
klass = Class.new do
|
175
|
+
include Scale::Types::Struct
|
176
|
+
items(**items)
|
177
|
+
end
|
178
|
+
Scale::Types.const_set type_name, klass
|
179
|
+
else
|
180
|
+
Scale::Types.const_get type_name
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# not implemented: ["Compact", "Hex"]
|
185
|
+
def build_enum(type_info)
|
186
|
+
# type_info: [["Item1", "Compact"], [["Item2", "Hex"]]
|
187
|
+
if type_info.has_key?("type_mapping")
|
188
|
+
# items: {a: Type}
|
189
|
+
items = type_info["type_mapping"].map do |item|
|
190
|
+
item_name = item[0]
|
191
|
+
item_type = get(item[1])
|
192
|
+
[item_name.to_sym, item_type]
|
193
|
+
end.to_h
|
194
|
+
|
195
|
+
partials = []
|
196
|
+
items.each_pair do |item_name, item_type|
|
197
|
+
partials << item_name.to_s.camelize2 + 'In' + item_type.name.gsub('Scale::Types::', '')
|
198
|
+
end
|
199
|
+
type_name = "Enum_#{partials.join('_')}_"
|
200
|
+
|
201
|
+
if !Scale::Types.const_defined?(type_name)
|
202
|
+
klass = Class.new do
|
203
|
+
include Scale::Types::Enum
|
204
|
+
items(**items)
|
205
|
+
end
|
206
|
+
|
207
|
+
return Scale::Types.const_set type_name, klass
|
208
|
+
else
|
209
|
+
return Scale::Types.const_get type_name
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# [1, "hello"]
|
214
|
+
if type_info.has_key?("value_list")
|
215
|
+
type_name = "Enum#{type_info["value_list"].map {|value| value.to_s.camelize2}.join}"
|
216
|
+
|
217
|
+
if !Scale::Types.const_defined?(type_name)
|
218
|
+
klass = Class.new do
|
219
|
+
include Scale::Types::Enum
|
220
|
+
values *type_info["value_list"]
|
221
|
+
end
|
222
|
+
return Scale::Types.const_set type_name, klass
|
223
|
+
else
|
224
|
+
return Scale::Types.const_get type_name
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
|
230
|
+
# {
|
231
|
+
# value_type: u32,
|
232
|
+
# value_list: {
|
233
|
+
# "TransactionPayment" => 0b00000001,
|
234
|
+
# "Transfer" => 0b00000010,
|
235
|
+
# "Reserve" => 0b00000100,
|
236
|
+
# ...
|
237
|
+
# }
|
238
|
+
# }
|
239
|
+
def build_set(type_info)
|
240
|
+
type_name = "Set#{type_info["value_list"].keys.map(&:camelize2).join("")}"
|
241
|
+
if !Scale::Types.const_defined?(type_name)
|
242
|
+
bytes_length = type_info["value_type"][1..].to_i / 8
|
243
|
+
klass = Class.new do
|
244
|
+
include Scale::Types::Set
|
245
|
+
items type_info["value_list"], bytes_length
|
246
|
+
end
|
247
|
+
return Scale::Types.const_set type_name, klass
|
248
|
+
else
|
249
|
+
return Scale::Types.const_get type_name
|
250
|
+
end
|
251
|
+
Scale::Types.const_set fix(name), klass
|
252
|
+
end
|
253
|
+
|
254
|
+
def fix_name(type)
|
255
|
+
type = type.gsub("T::", "")
|
256
|
+
.gsub("<T>", "")
|
257
|
+
.gsub("<T as Trait>::", "")
|
258
|
+
.delete("\n")
|
259
|
+
.gsub(/(u)(\d+)/, 'U\2')
|
260
|
+
return "Bool" if type == "bool"
|
261
|
+
return "Null" if type == "()"
|
262
|
+
return "String" if type == "Vec<u8>"
|
263
|
+
return "Compact" if type == "Compact<u32>" || type == "Compact<U32>"
|
264
|
+
return "Address" if type == "<Lookup as StaticLookup>::Source"
|
265
|
+
return "Compact" if type == "<Balance as HasCompact>::Type"
|
266
|
+
return "Compact" if type == "<BlockNumber as HasCompact>::Type"
|
267
|
+
return "Compact" if type =~ /\ACompact<[a-zA-Z0-9\s]*>\z/
|
268
|
+
return "CompactMoment" if type == "<Moment as HasCompact>::Type"
|
269
|
+
return "CompactMoment" if type == "Compact<Moment>"
|
270
|
+
return "InherentOfflineReport" if type == "<InherentOfflineReport as InherentOfflineReport>::Inherent"
|
271
|
+
return "AccountData" if type == "AccountData<Balance>"
|
272
|
+
return "EventRecord" if type == "EventRecord<Event, Hash>"
|
273
|
+
|
274
|
+
type
|
275
|
+
end
|
276
|
+
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Scale
|
2
|
+
|
3
|
+
class TypeRegistry
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
# init by load, and will not change
|
7
|
+
attr_reader :spec_name, :types
|
8
|
+
attr_reader :versioning, :custom_types # optional
|
9
|
+
|
10
|
+
# will change by different spec version
|
11
|
+
attr_accessor :spec_version # optional
|
12
|
+
attr_accessor :metadata
|
13
|
+
|
14
|
+
def load(spec_name: nil, custom_types: nil)
|
15
|
+
@spec_name = nil
|
16
|
+
@types = nil
|
17
|
+
@versioning = nil
|
18
|
+
@custom_types = nil
|
19
|
+
|
20
|
+
default_types, _, _ = load_chain_spec_types("default")
|
21
|
+
|
22
|
+
if spec_name
|
23
|
+
begin
|
24
|
+
@spec_name = spec_name
|
25
|
+
spec_types, @versioning, @spec_version = load_chain_spec_types(spec_name)
|
26
|
+
@types = default_types.merge(spec_types)
|
27
|
+
rescue => ex
|
28
|
+
# TODO: check different errors
|
29
|
+
puts "There is no types json file named #{spec_name}"
|
30
|
+
@types = default_types
|
31
|
+
end
|
32
|
+
else
|
33
|
+
@spec_name = "default"
|
34
|
+
@types = default_types
|
35
|
+
end
|
36
|
+
|
37
|
+
self.custom_types = custom_types
|
38
|
+
true
|
39
|
+
end
|
40
|
+
|
41
|
+
def get(type_name)
|
42
|
+
all_types = self.all_types
|
43
|
+
type_traverse(type_name, all_types)
|
44
|
+
end
|
45
|
+
|
46
|
+
def custom_types=(custom_types)
|
47
|
+
@custom_types = custom_types.stringify_keys if (not custom_types.nil?) && custom_types.class.name == "Hash"
|
48
|
+
end
|
49
|
+
|
50
|
+
def all_types
|
51
|
+
all_types = {}.merge(@types)
|
52
|
+
|
53
|
+
if @spec_version && @versioning
|
54
|
+
@versioning.each do |item|
|
55
|
+
if @spec_version >= item["runtime_range"][0] &&
|
56
|
+
( item["runtime_range"][1].nil? || @spec_version <= item["runtime_range"][1] )
|
57
|
+
all_types.merge!(item["types"])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
all_types.merge!(@custom_types) if @custom_types
|
63
|
+
all_types
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def load_chain_spec_types(spec_name)
|
69
|
+
file = File.join File.expand_path("../..", __FILE__), "lib", "type_registry", "#{spec_name}.json"
|
70
|
+
json_string = File.open(file).read
|
71
|
+
json = JSON.parse(json_string)
|
72
|
+
|
73
|
+
runtime_id = json["runtime_id"]
|
74
|
+
|
75
|
+
[json["types"], json["versioning"], runtime_id]
|
76
|
+
end
|
77
|
+
|
78
|
+
def type_traverse(type, types)
|
79
|
+
if type.class == ::String
|
80
|
+
real_type = types[type]
|
81
|
+
|
82
|
+
return type if real_type.nil? || real_type == type
|
83
|
+
|
84
|
+
type_traverse(real_type, types)
|
85
|
+
else
|
86
|
+
type
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|