scale_rb 0.1.14 → 0.2.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/Gemfile.lock +1 -1
- data/lib/address.rb +85 -89
- data/lib/client/abstract_ws_client.rb +85 -81
- data/lib/client/http_client.rb +2 -170
- data/lib/client/http_client_metadata.rb +10 -8
- data/lib/client/http_client_storage.rb +180 -0
- data/lib/client/rpc_request_builder.rb +44 -42
- data/lib/codec.rb +28 -29
- data/lib/hasher.rb +39 -37
- data/lib/metadata/metadata.rb +130 -122
- data/lib/metadata/metadata_v10.rb +72 -69
- data/lib/metadata/metadata_v11.rb +78 -75
- data/lib/metadata/metadata_v12.rb +42 -39
- data/lib/metadata/metadata_v13.rb +71 -68
- data/lib/metadata/metadata_v14.rb +185 -181
- data/lib/metadata/metadata_v9.rb +92 -89
- data/lib/monkey_patching.rb +22 -22
- data/lib/portable_codec.rb +236 -232
- data/lib/scale_rb/version.rb +1 -1
- data/lib/scale_rb.rb +0 -1
- data/lib/storage_helper.rb +52 -50
- metadata +3 -2
@@ -0,0 +1,180 @@
|
|
1
|
+
module ScaleRb
|
2
|
+
module HttpClient
|
3
|
+
class << self
|
4
|
+
# get_storage3 is a more ruby style function
|
5
|
+
#
|
6
|
+
# pallet_name and storage_name is pascal style like 'darwinia_staking'
|
7
|
+
def get_storage3(url, pallet_name, storage_name, key_part1: nil, key_part2: nil, metadata: nil, at: nil)
|
8
|
+
# Get metadata if not provided, and cache it.
|
9
|
+
# The default dir is `metadata` dir under the caller's dir.
|
10
|
+
# You can change it by setting `SCALE_RB_METADATA_DIR` env variable
|
11
|
+
metadata = get_metadata_cached(url, at: at) if metadata.nil?
|
12
|
+
|
13
|
+
pallet_name = to_pascal pallet_name
|
14
|
+
storage_name = to_pascal storage_name
|
15
|
+
ScaleRb.logger.debug "#{pallet_name}.#{storage_name}(#{[key_part1, key_part2].compact.join(', ')})"
|
16
|
+
|
17
|
+
key = [key_part1, key_part2].compact.map { |part_of_key| c(part_of_key) }
|
18
|
+
ScaleRb.logger.debug "converted key: #{key}"
|
19
|
+
|
20
|
+
get_storage2(
|
21
|
+
url,
|
22
|
+
pallet_name,
|
23
|
+
storage_name,
|
24
|
+
key,
|
25
|
+
metadata,
|
26
|
+
at
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def query_storage_at(url, storage_keys, type_id, default, registry, at = nil)
|
33
|
+
result = state_queryStorageAt(url, storage_keys, at)
|
34
|
+
result.map do |item|
|
35
|
+
item['changes'].map do |change|
|
36
|
+
storage_key = change[0]
|
37
|
+
data = change[1] || default
|
38
|
+
storage = data.nil? ? nil : PortableCodec.decode(type_id, data._to_bytes, registry)[0]
|
39
|
+
{ storage_key: storage_key, storage: storage }
|
40
|
+
end
|
41
|
+
end.flatten
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_storage_keys_by_partial_key(url, partial_storage_key, start_key = nil, at = nil)
|
45
|
+
storage_keys = state_getKeysPaged(url, partial_storage_key, 1000, start_key, at)
|
46
|
+
if storage_keys.length == 1000
|
47
|
+
storage_keys + get_storage_keys_by_partial_key(url, partial_storage_key, storage_keys.last, at)
|
48
|
+
else
|
49
|
+
storage_keys
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def get_storages_by_partial_key(url, partial_storage_key, type_id_of_value, default, registry, at = nil)
|
54
|
+
storage_keys = get_storage_keys_by_partial_key(url, partial_storage_key, partial_storage_key, at)
|
55
|
+
storage_keys.each_slice(250).map do |slice|
|
56
|
+
query_storage_at(
|
57
|
+
url,
|
58
|
+
slice,
|
59
|
+
type_id_of_value,
|
60
|
+
default,
|
61
|
+
registry,
|
62
|
+
at
|
63
|
+
)
|
64
|
+
end.flatten
|
65
|
+
end
|
66
|
+
|
67
|
+
# 1. Plain
|
68
|
+
# key: nil
|
69
|
+
# value: { type: 3, modifier: 'Default', callback: '' }
|
70
|
+
#
|
71
|
+
# 2. Map
|
72
|
+
# key: { value: value, type: 0, hashers: ['Blake2128Concat'] }
|
73
|
+
# value: { type: 3, modifier: 'Default', callback: '' }
|
74
|
+
#
|
75
|
+
# 3. Map, but key.value is nil
|
76
|
+
# key: { value: nil, type: 0, hashers: ['Blake2128Concat'] }
|
77
|
+
# value: { type: 3, modifier: 'Default', callback: '' }
|
78
|
+
#
|
79
|
+
# example:
|
80
|
+
# 'System',
|
81
|
+
# 'Account',
|
82
|
+
# key = {
|
83
|
+
# value: [['0x724d50824542b56f422588421643c4a162b90b5416ef063f2266a1eae6651641'._to_bytes]], # [AccountId]
|
84
|
+
# type: 0,
|
85
|
+
# hashers: ['Blake2128Concat']
|
86
|
+
# },
|
87
|
+
# value = {
|
88
|
+
# type: 3,
|
89
|
+
# modifier: 'Default',
|
90
|
+
# callback: '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
|
91
|
+
# },
|
92
|
+
# ..
|
93
|
+
#
|
94
|
+
# TODO: part of the key is provided, but not all
|
95
|
+
def get_storage(url, pallet_name, item_name, key, value, registry, at = nil)
|
96
|
+
if key
|
97
|
+
if key[:value].nil? || key[:value].empty?
|
98
|
+
# map, but no key's value provided. get all storages under the partial storage key
|
99
|
+
partial_storage_key = StorageHelper.encode_storage_key(pallet_name, item_name)._to_hex
|
100
|
+
get_storages_by_partial_key(
|
101
|
+
url,
|
102
|
+
partial_storage_key,
|
103
|
+
value[:type],
|
104
|
+
value[:modifier] == 'Default' ? value[:fallback] : nil,
|
105
|
+
registry,
|
106
|
+
at
|
107
|
+
)
|
108
|
+
elsif key[:value].length != key[:hashers].length
|
109
|
+
# map with multi parts, but not have all values
|
110
|
+
partial_storage_key = StorageHelper.encode_storage_key(pallet_name, item_name, key, registry)._to_hex
|
111
|
+
get_storages_by_partial_key(
|
112
|
+
url,
|
113
|
+
partial_storage_key,
|
114
|
+
value[:type],
|
115
|
+
value[:modifier] == 'Default' ? value[:fallback] : nil,
|
116
|
+
registry,
|
117
|
+
at
|
118
|
+
)
|
119
|
+
end
|
120
|
+
else
|
121
|
+
storage_key = StorageHelper.encode_storage_key(pallet_name, item_name, key, registry)._to_hex
|
122
|
+
data = state_getStorage(url, storage_key, at)
|
123
|
+
StorageHelper.decode_storage(data, value[:type], value[:modifier] == 'Optional', value[:fallback], registry)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def get_storage2(url, pallet_name, item_name, value_of_key, metadata, at = nil)
|
128
|
+
raise 'Metadata should not be nil' if metadata.nil?
|
129
|
+
|
130
|
+
registry = Metadata.build_registry(metadata)
|
131
|
+
item = Metadata.get_storage_item(
|
132
|
+
pallet_name, item_name, metadata
|
133
|
+
)
|
134
|
+
raise "No such storage item: `#{pallet_name}`.`#{item_name}`" if item.nil?
|
135
|
+
|
136
|
+
modifier = item._get(:modifier) # Default | Optional
|
137
|
+
fallback = item._get(:fallback)
|
138
|
+
type = item._get(:type)
|
139
|
+
|
140
|
+
plain = type._get(:plain)
|
141
|
+
map = type._get(:map)
|
142
|
+
# debug
|
143
|
+
|
144
|
+
key, value =
|
145
|
+
if plain
|
146
|
+
[
|
147
|
+
nil,
|
148
|
+
{ type: plain,
|
149
|
+
modifier: modifier, fallback: fallback }
|
150
|
+
]
|
151
|
+
elsif map
|
152
|
+
[
|
153
|
+
{ value: value_of_key,
|
154
|
+
type: map._get(:key), hashers: map._get(:hashers) },
|
155
|
+
{ type: map._get(:value),
|
156
|
+
modifier: modifier, fallback: fallback }
|
157
|
+
]
|
158
|
+
else
|
159
|
+
raise 'NoSuchStorageType'
|
160
|
+
end
|
161
|
+
get_storage(url, pallet_name, item_name, key, value, registry, at)
|
162
|
+
end
|
163
|
+
|
164
|
+
def to_pascal(str)
|
165
|
+
str.split('_').collect(&:capitalize).join
|
166
|
+
end
|
167
|
+
|
168
|
+
# convert key to byte array
|
169
|
+
def c(key)
|
170
|
+
if key.start_with?('0x')
|
171
|
+
key._to_bytes
|
172
|
+
elsif key.to_i.to_s == key # check if key is a number
|
173
|
+
key.to_i
|
174
|
+
else
|
175
|
+
key
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -2,52 +2,54 @@
|
|
2
2
|
|
3
3
|
require 'json'
|
4
4
|
|
5
|
-
module
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
5
|
+
module ScaleRb
|
6
|
+
module RpcRequestBuilder
|
7
|
+
def build_json_rpc_body(method, params, id)
|
8
|
+
{
|
9
|
+
'id' => id,
|
10
|
+
'jsonrpc' => '2.0',
|
11
|
+
'method' => method,
|
12
|
+
'params' => params.reject(&:nil?)
|
13
|
+
}.to_json
|
14
|
+
end
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
def respond_to_missing?(*_args)
|
17
|
+
true
|
18
|
+
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
20
|
+
# example:
|
21
|
+
# state_getStorage(1, '0x363a..', 563_868)
|
22
|
+
#
|
23
|
+
# ==
|
24
|
+
#
|
25
|
+
# build_json_rpc_body('state_getStorage', ['0x363a..', 563_868], 1)
|
26
|
+
def method_missing(method, *args)
|
27
|
+
build_json_rpc_body(method, args[1..], args[0])
|
28
|
+
end
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
30
|
+
###################################
|
31
|
+
# derived functions
|
32
|
+
###################################
|
33
|
+
def derived_state_get_storage(rpc_id, pallet_name, item_name, key = nil, registry = nil)
|
34
|
+
storage_key = StorageHelper.encode_storage_key(pallet_name, item_name, key, registry)._to_hex
|
35
|
+
state_getStorage(rpc_id, [storage_key])
|
36
|
+
end
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
def derived_state_subscribe_storage(rpc_id, pallet_name, item_name, key = nil, registry = nil)
|
39
|
+
storage_key = StorageHelper.encode_storage_key(pallet_name, item_name, key, registry)._to_hex
|
40
|
+
state_subscribeStorage(rpc_id, [storage_key])
|
41
|
+
end
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
43
|
+
def derived_eth_call(rpc_id, to, data, at = nil)
|
44
|
+
eth_call(
|
45
|
+
rpc_id,
|
46
|
+
[
|
47
|
+
{
|
48
|
+
'from' => nil, 'to' => to, 'data' => data
|
49
|
+
},
|
50
|
+
at
|
51
|
+
]
|
52
|
+
)
|
53
|
+
end
|
52
54
|
end
|
53
55
|
end
|
data/lib/codec.rb
CHANGED
@@ -145,12 +145,12 @@ module ScaleRb
|
|
145
145
|
when 0
|
146
146
|
[bytes[0] >> 2, bytes[1..]]
|
147
147
|
when 1
|
148
|
-
[bytes[0..1].
|
148
|
+
[bytes[0..1]._flip._to_uint >> 2, bytes[2..]]
|
149
149
|
when 2
|
150
|
-
[bytes[0..3].
|
150
|
+
[bytes[0..3]._flip._to_uint >> 2, bytes[4..]]
|
151
151
|
when 3
|
152
152
|
length = 4 + (bytes[0] >> 2)
|
153
|
-
[bytes[1..length].
|
153
|
+
[bytes[1..length]._flip._to_uint, bytes[length + 1..]]
|
154
154
|
else
|
155
155
|
raise Unreachable, 'type: Compact'
|
156
156
|
end
|
@@ -191,9 +191,9 @@ module ScaleRb
|
|
191
191
|
# Decode
|
192
192
|
class << self
|
193
193
|
def decode(type, bytes, registry = {})
|
194
|
-
logger.debug '--------------------------------------------------'
|
195
|
-
debug 'decoding type', type
|
196
|
-
debug 'bytes', bytes&.length
|
194
|
+
# logger.debug '--------------------------------------------------'
|
195
|
+
# debug 'decoding type', type
|
196
|
+
# debug 'bytes', bytes&.length
|
197
197
|
|
198
198
|
if type.instance_of?(String)
|
199
199
|
return decode_bytes(bytes) if bytes?(type) # Bytes
|
@@ -220,9 +220,9 @@ module ScaleRb
|
|
220
220
|
|
221
221
|
def decode_bytes(bytes)
|
222
222
|
length, remaining_bytes = _do_decode_compact(bytes)
|
223
|
-
value = remaining_bytes[0...length].
|
224
|
-
debug 'length', length
|
225
|
-
debug 'value', value
|
223
|
+
value = remaining_bytes[0...length]._to_hex
|
224
|
+
# debug 'length', length
|
225
|
+
# debug 'value', value
|
226
226
|
[
|
227
227
|
value,
|
228
228
|
remaining_bytes[length..]
|
@@ -238,7 +238,7 @@ module ScaleRb
|
|
238
238
|
else
|
239
239
|
raise InvalidBytesError, 'type: Boolean'
|
240
240
|
end
|
241
|
-
debug 'value', value
|
241
|
+
# debug 'value', value
|
242
242
|
[value, bytes[1..]]
|
243
243
|
end
|
244
244
|
|
@@ -246,9 +246,9 @@ module ScaleRb
|
|
246
246
|
length, remaining_bytes = _do_decode_compact(bytes)
|
247
247
|
raise NotEnoughBytesError, 'type: String' if remaining_bytes.length < length
|
248
248
|
|
249
|
-
value = remaining_bytes[0...length].
|
250
|
-
debug 'byte length', length
|
251
|
-
debug 'value', value.inspect
|
249
|
+
value = remaining_bytes[0...length]._to_utf8
|
250
|
+
# debug 'byte length', length
|
251
|
+
# debug 'value', value.inspect
|
252
252
|
[
|
253
253
|
value,
|
254
254
|
remaining_bytes[length..]
|
@@ -260,8 +260,8 @@ module ScaleRb
|
|
260
260
|
byte_length = bit_length / 8
|
261
261
|
raise NotEnoughBytesError, "type: #{type}" if bytes.length < byte_length
|
262
262
|
|
263
|
-
value = bytes[0...byte_length].
|
264
|
-
debug 'value', value
|
263
|
+
value = bytes[0...byte_length]._flip._to_int(bit_length)
|
264
|
+
# debug 'value', value
|
265
265
|
[
|
266
266
|
value,
|
267
267
|
bytes[byte_length..]
|
@@ -273,8 +273,8 @@ module ScaleRb
|
|
273
273
|
byte_length = bit_length / 8
|
274
274
|
raise NotEnoughBytesError, "type: #{type_def}" if bytes.length < byte_length
|
275
275
|
|
276
|
-
value = bytes[0...byte_length].
|
277
|
-
debug 'value', value
|
276
|
+
value = bytes[0...byte_length]._flip._to_uint
|
277
|
+
# debug 'value', value
|
278
278
|
[
|
279
279
|
value,
|
280
280
|
bytes[byte_length..]
|
@@ -282,9 +282,8 @@ module ScaleRb
|
|
282
282
|
end
|
283
283
|
|
284
284
|
def decode_compact(bytes)
|
285
|
-
|
286
|
-
debug 'value', result[0]
|
287
|
-
result
|
285
|
+
_do_decode_compact(bytes)
|
286
|
+
# debug 'value', result[0]
|
288
287
|
end
|
289
288
|
|
290
289
|
def decode_option(type_def, bytes, registry = {})
|
@@ -304,7 +303,7 @@ module ScaleRb
|
|
304
303
|
def decode_vec(type_def, bytes, registry = {})
|
305
304
|
inner_type = parse_vec(type_def)
|
306
305
|
length, remaining_bytes = _do_decode_compact(bytes)
|
307
|
-
debug 'length', length
|
306
|
+
# debug 'length', length
|
308
307
|
_decode_types([inner_type] * length, remaining_bytes, registry)
|
309
308
|
end
|
310
309
|
|
@@ -331,7 +330,7 @@ module ScaleRb
|
|
331
330
|
raise IndexOutOfRangeError, "type: #{type_def}" if index > items.length - 1
|
332
331
|
|
333
332
|
item = items.to_a[index] # 'name' or [:name, inner_type]
|
334
|
-
debug 'value', item.inspect
|
333
|
+
# debug 'value', item.inspect
|
335
334
|
return [item, bytes[1..]] if item.instance_of?(String)
|
336
335
|
|
337
336
|
value, remaining_bytes = decode(item[1], bytes[1..], registry)
|
@@ -353,9 +352,9 @@ module ScaleRb
|
|
353
352
|
# Encode
|
354
353
|
class << self
|
355
354
|
def encode(type, value, registry = {})
|
356
|
-
logger.debug '--------------------------------------------------'
|
357
|
-
debug 'encoding type', type
|
358
|
-
debug 'value', value
|
355
|
+
# logger.debug '--------------------------------------------------'
|
356
|
+
# debug 'encoding type', type
|
357
|
+
# debug 'value', value
|
359
358
|
|
360
359
|
if type.instance_of?(String)
|
361
360
|
return encode_bytes(value) if bytes?(type)
|
@@ -397,16 +396,16 @@ module ScaleRb
|
|
397
396
|
|
398
397
|
def encode_compact(value)
|
399
398
|
return [value << 2] if (value >= 0) && (value < 64)
|
400
|
-
return ((value << 2) + 1).
|
401
|
-
return ((value << 2) + 2).
|
399
|
+
return ((value << 2) + 1)._to_bytes._flip if value < 2**14
|
400
|
+
return ((value << 2) + 2)._to_bytes._flip if value < 2**30
|
402
401
|
|
403
|
-
bytes = value.
|
402
|
+
bytes = value._to_bytes._flip
|
404
403
|
[(((bytes.length - 4) << 2) + 3)] + bytes
|
405
404
|
end
|
406
405
|
|
407
406
|
def encode_uint(type, value)
|
408
407
|
bit_length = type[1..].to_i
|
409
|
-
value.
|
408
|
+
value._to_bytes(bit_length)._flip
|
410
409
|
end
|
411
410
|
|
412
411
|
def encode_option(type, value, registry = {})
|
data/lib/hasher.rb
CHANGED
@@ -3,52 +3,54 @@
|
|
3
3
|
require 'xxhash'
|
4
4
|
require 'blake2b'
|
5
5
|
|
6
|
-
module
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
6
|
+
module ScaleRb
|
7
|
+
module Hasher
|
8
|
+
class << self
|
9
|
+
# params:
|
10
|
+
# hasher: 'Identity' | 'Twox64Concat' | 'Blake2128Concat'
|
11
|
+
# bytes: u8 array
|
12
|
+
# return: u8 array
|
13
|
+
def apply_hasher(hasher, bytes)
|
14
|
+
function_name = hasher.gsub('_', '')._underscore
|
15
|
+
Hasher.send(function_name, bytes)
|
16
|
+
end
|
15
17
|
end
|
16
|
-
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
class << self
|
20
|
+
def identity(bytes)
|
21
|
+
bytes
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
def twox64_concat(bytes)
|
25
|
+
data = bytes._to_utf8
|
26
|
+
twox64(data) + bytes
|
27
|
+
end
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
def blake2128_concat(bytes)
|
30
|
+
blake2_128(bytes) + bytes
|
31
|
+
end
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
def twox64(str)
|
34
|
+
result = XXhash.xxh64 str, 0
|
35
|
+
result._to_bytes.reverse
|
36
|
+
end
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
38
|
+
def twox128(str)
|
39
|
+
bytes = []
|
40
|
+
2.times do |i|
|
41
|
+
result = XXhash.xxh64 str, i
|
42
|
+
bytes += result._to_bytes.reverse
|
43
|
+
end
|
44
|
+
bytes
|
42
45
|
end
|
43
|
-
bytes
|
44
|
-
end
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
|
47
|
+
def blake2_128(bytes)
|
48
|
+
Blake2b.hex(bytes, 16)._to_bytes
|
49
|
+
end
|
49
50
|
|
50
|
-
|
51
|
-
|
51
|
+
def blake2_256(bytes)
|
52
|
+
Blake2b.hex(bytes, 32)._to_bytes
|
53
|
+
end
|
52
54
|
end
|
53
55
|
end
|
54
56
|
end
|