scale_rb 0.1.11 → 0.1.14
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 +2 -2
- data/lib/address.rb +43 -35
- data/lib/client/http_client.rb +63 -11
- data/lib/client/http_client_metadata.rb +76 -0
- data/lib/scale_rb/version.rb +1 -1
- data/lib/storage_helper.rb +11 -11
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 82a0911194368a4fcefec7a414694346f087c0ded749d3865f6732f27c8afef0
|
4
|
+
data.tar.gz: 14b34a748f835c527726ebd42440cced5ed8b5c0d954cb15c41e288ce3e5aff6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 805efca604cc93794b5c1d4ee3dd1785d74d6a049b55f0ecc0503c85869c2759a37380b6735b8ecf874b6b33b31492f7b203870b7b414758740545821f98db19
|
7
|
+
data.tar.gz: d5f577ec96adf7a51ef7044b0d5f8bc874e3a12daf66e3cc743677a6a095ddda909267b941dd15a06646dc941caeabe810fd960140c1c94261d173796ee40b9d
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
scale_rb (0.1.
|
4
|
+
scale_rb (0.1.14)
|
5
5
|
base58
|
6
6
|
blake2b_rs (~> 0.1.4)
|
7
7
|
xxhash
|
@@ -14,7 +14,7 @@ GEM
|
|
14
14
|
ffi (~> 1.0)
|
15
15
|
thermite (~> 0)
|
16
16
|
diff-lcs (1.5.0)
|
17
|
-
ffi (1.
|
17
|
+
ffi (1.16.3)
|
18
18
|
minitar (0.9)
|
19
19
|
rake (12.3.3)
|
20
20
|
rspec (3.11.0)
|
data/lib/address.rb
CHANGED
@@ -14,7 +14,7 @@ class Address
|
|
14
14
|
# Darwinia Live
|
15
15
|
18,
|
16
16
|
# Dothereum (SS58, AccountId)
|
17
|
-
20, 21,
|
17
|
+
20, 21,
|
18
18
|
# Generic Substrate wildcard (SS58, AccountId)
|
19
19
|
42, 43,
|
20
20
|
|
@@ -30,54 +30,62 @@ class Address
|
|
30
30
|
]
|
31
31
|
|
32
32
|
class << self
|
33
|
-
|
34
33
|
def array_to_hex_string(arr)
|
35
34
|
body = arr.map { |i| i.to_s(16).rjust(2, '0') }.join
|
36
35
|
"0x#{body}"
|
37
36
|
end
|
38
37
|
|
39
|
-
def decode(address, addr_type = 42,
|
38
|
+
def decode(address, addr_type = 42, _ignore_checksum = true)
|
40
39
|
decoded = Base58.base58_to_binary(address, :bitcoin)
|
41
40
|
is_pubkey = decoded.size == 35
|
42
41
|
|
43
|
-
size = decoded.size - (
|
42
|
+
size = decoded.size - (is_pubkey ? 2 : 1)
|
43
|
+
|
44
|
+
prefix = decoded[0, 1].unpack1('C*')
|
44
45
|
|
45
|
-
|
46
|
+
raise 'Invalid address type' unless TYPES.include?(addr_type)
|
46
47
|
|
47
|
-
raise "Invalid address type" unless TYPES.include?(addr_type)
|
48
|
-
|
49
48
|
hash_bytes = make_hash(decoded[0, size])
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
49
|
+
is_valid_checksum =
|
50
|
+
if is_pubkey
|
51
|
+
decoded[-2].unpack1('C*') == hash_bytes[0] && decoded[-1].unpack1('C*') == hash_bytes[1]
|
52
|
+
else
|
53
|
+
decoded[-1].unpack1('C*') == hash_bytes[0]
|
54
|
+
end
|
55
55
|
|
56
56
|
# raise "Invalid decoded address checksum" unless is_valid_checksum && ignore_checksum
|
57
57
|
|
58
|
-
decoded[1...size].
|
58
|
+
decoded[1...size].unpack1('H*')
|
59
59
|
end
|
60
60
|
|
61
|
-
|
62
61
|
def encode(pubkey, addr_type = 42)
|
63
62
|
pubkey = pubkey[2..-1] if pubkey =~ /^0x/i
|
64
|
-
key = [pubkey].pack(
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
63
|
+
key = [pubkey].pack('H*')
|
64
|
+
|
65
|
+
pubkey_bytes = key.bytes
|
66
|
+
|
67
|
+
checksum_length = case pubkey_bytes.length
|
68
|
+
when 32, 33
|
69
|
+
2
|
70
|
+
when 1, 2, 4, 8
|
71
|
+
1
|
72
|
+
else
|
73
|
+
raise 'Invalid pubkey length'
|
74
|
+
end
|
75
|
+
|
76
|
+
ss58_format_bytes = if addr_type < 64
|
77
|
+
[addr_type].pack('C*')
|
78
|
+
else
|
79
|
+
[
|
80
|
+
((ss58_format & 0b0000_0000_1111_1100) >> 2) | 0b0100_0000,
|
81
|
+
(ss58_format >> 8) | ((ss58_format & 0b0000_0000_0000_0011) << 6)
|
82
|
+
].pack('C*')
|
83
|
+
end
|
84
|
+
|
85
|
+
input_bytes = ss58_format_bytes.bytes + pubkey_bytes
|
86
|
+
checksum = Blake2b.hex(SS58_PREFIX.bytes + input_bytes, 64).to_bytes
|
87
|
+
|
88
|
+
Base58.binary_to_base58((input_bytes + checksum[0...checksum_length]).pack('C*'), :bitcoin)
|
81
89
|
end
|
82
90
|
|
83
91
|
def make_hash(body)
|
@@ -87,11 +95,11 @@ class Address
|
|
87
95
|
def is_ss58_address?(address)
|
88
96
|
begin
|
89
97
|
decode(address)
|
90
|
-
rescue
|
98
|
+
rescue StandardError
|
91
99
|
return false
|
92
100
|
end
|
93
|
-
|
101
|
+
true
|
94
102
|
end
|
95
|
-
|
96
103
|
end
|
97
|
-
end
|
104
|
+
end
|
105
|
+
|
data/lib/client/http_client.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'uri'
|
4
4
|
require 'net/http'
|
5
5
|
require 'json'
|
6
|
+
require_relative './http_client_metadata'
|
6
7
|
|
7
8
|
# TODO: method_name = cmd.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
|
8
9
|
module ScaleRb
|
@@ -129,17 +130,30 @@ module ScaleRb
|
|
129
130
|
#
|
130
131
|
# TODO: part of the key is provided, but not all
|
131
132
|
def get_storage(url, pallet_name, item_name, key, value, registry, at = nil)
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
133
|
+
if key
|
134
|
+
if key[:value].nil? || key[:value].empty?
|
135
|
+
# map, but no key's value provided. get all storages under the partial storage key
|
136
|
+
partial_storage_key = StorageHelper.encode_storage_key(pallet_name, item_name).to_hex
|
137
|
+
get_storages_by_partial_key(
|
138
|
+
url,
|
139
|
+
partial_storage_key,
|
140
|
+
value[:type],
|
141
|
+
value[:modifier] == 'Default' ? value[:fallback] : nil,
|
142
|
+
registry,
|
143
|
+
at
|
144
|
+
)
|
145
|
+
elsif key[:value].length != key[:hashers].length
|
146
|
+
# map with multi part, but only provide part value
|
147
|
+
partial_storage_key = StorageHelper.encode_storage_key(pallet_name, item_name, key, registry).to_hex
|
148
|
+
get_storages_by_partial_key(
|
149
|
+
url,
|
150
|
+
partial_storage_key,
|
151
|
+
value[:type],
|
152
|
+
value[:modifier] == 'Default' ? value[:fallback] : nil,
|
153
|
+
registry,
|
154
|
+
at
|
155
|
+
)
|
156
|
+
end
|
143
157
|
else
|
144
158
|
storage_key = StorageHelper.encode_storage_key(pallet_name, item_name, key, registry).to_hex
|
145
159
|
data = state_getStorage(url, storage_key, at)
|
@@ -178,6 +192,44 @@ module ScaleRb
|
|
178
192
|
end
|
179
193
|
get_storage(url, pallet_name, item_name, key, value, registry, at)
|
180
194
|
end
|
195
|
+
|
196
|
+
# get_storage3 is a more ruby style function
|
197
|
+
#
|
198
|
+
# pallet_name and storage_name is pascal style like 'darwinia_staking'
|
199
|
+
def get_storage3(url, metadata, pallet_name, storage_name, key_part1: nil, key_part2: nil, at: nil)
|
200
|
+
pallet_name = to_pascal pallet_name
|
201
|
+
storage_name = to_pascal storage_name
|
202
|
+
ScaleRb.logger.debug "#{pallet_name}.#{storage_name}(#{[key_part1, key_part2].compact.join(', ')})"
|
203
|
+
|
204
|
+
key = [key_part1, key_part2].compact.map { |part_of_key| c(part_of_key) }
|
205
|
+
ScaleRb.logger.debug "converted key: #{key}"
|
206
|
+
|
207
|
+
get_storage2(
|
208
|
+
url,
|
209
|
+
pallet_name,
|
210
|
+
storage_name,
|
211
|
+
key,
|
212
|
+
metadata,
|
213
|
+
at
|
214
|
+
)
|
215
|
+
end
|
216
|
+
|
217
|
+
private
|
218
|
+
|
219
|
+
def to_pascal(str)
|
220
|
+
str.split('_').collect(&:capitalize).join
|
221
|
+
end
|
222
|
+
|
223
|
+
# convert key to byte array
|
224
|
+
def c(key)
|
225
|
+
if key.start_with?('0x')
|
226
|
+
key.to_bytes
|
227
|
+
elsif key.to_i.to_s == key # check if key is a number
|
228
|
+
key.to_i
|
229
|
+
else
|
230
|
+
key
|
231
|
+
end
|
232
|
+
end
|
181
233
|
end
|
182
234
|
end
|
183
235
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module ScaleRb
|
5
|
+
module HttpClient
|
6
|
+
class << self
|
7
|
+
# cached version of get_metadata
|
8
|
+
# get metadata from cache first
|
9
|
+
def get_metadata_cached(url, at: nil, dir: File.join(Dir.pwd, 'metadata'))
|
10
|
+
# if at
|
11
|
+
# require_block_hash_correct(url, at)
|
12
|
+
# else
|
13
|
+
# at = ScaleRb::HttpClient.chain_getFinalizedHead(url)
|
14
|
+
# end
|
15
|
+
at = ScaleRb::HttpClient.chain_getFinalizedHead(url) if at.nil?
|
16
|
+
spec_name, spec_version = get_spec(url, at)
|
17
|
+
|
18
|
+
# get metadata from cache first
|
19
|
+
metadata = metadata_cached(
|
20
|
+
spec_name: spec_name,
|
21
|
+
spec_version: spec_version,
|
22
|
+
dir: dir
|
23
|
+
)
|
24
|
+
return metadata if metadata
|
25
|
+
|
26
|
+
# get metadata from rpc
|
27
|
+
metadata = ScaleRb::HttpClient.get_metadata(url, at)
|
28
|
+
|
29
|
+
# cache it
|
30
|
+
puts "caching metadata `#{spec_name}_#{spec_version}.json`"
|
31
|
+
save_metadata_to_file(
|
32
|
+
spec_name: spec_name,
|
33
|
+
spec_version: spec_version,
|
34
|
+
metadata: metadata,
|
35
|
+
dir: dir
|
36
|
+
)
|
37
|
+
|
38
|
+
metadata
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def get_spec(url, at)
|
44
|
+
runtime_version = ScaleRb::HttpClient.state_getRuntimeVersion(url, at)
|
45
|
+
spec_name = runtime_version['specName']
|
46
|
+
spec_version = runtime_version['specVersion']
|
47
|
+
[spec_name, spec_version]
|
48
|
+
end
|
49
|
+
|
50
|
+
def metadata_cached(spec_name:, spec_version:, dir:)
|
51
|
+
raise 'spec_version is required' unless spec_version
|
52
|
+
raise 'spec_name is required' unless spec_name
|
53
|
+
|
54
|
+
file_path = File.join(dir, "#{spec_name}_#{spec_version}.json")
|
55
|
+
return unless File.exist?(file_path)
|
56
|
+
|
57
|
+
puts "found metadata `#{spec_name}_#{spec_version}.json` in cache"
|
58
|
+
JSON.parse(File.read(file_path))
|
59
|
+
end
|
60
|
+
|
61
|
+
def save_metadata_to_file(spec_name:, spec_version:, metadata:, dir:)
|
62
|
+
FileUtils.mkdir_p(dir)
|
63
|
+
|
64
|
+
File.open(File.join(dir, "#{spec_name}_#{spec_version}.json"), 'w') do |f|
|
65
|
+
f.write(JSON.pretty_generate(metadata))
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def require_block_hash_correct(url, block_hash)
|
70
|
+
return unless ScaleRb::HttpClient.chain_getHeader(url, block_hash).nil?
|
71
|
+
|
72
|
+
raise 'Unable to retrieve header and parent from supplied hash'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/scale_rb/version.rb
CHANGED
data/lib/storage_helper.rb
CHANGED
@@ -12,26 +12,26 @@ module StorageHelper
|
|
12
12
|
|
13
13
|
if key && registry
|
14
14
|
|
15
|
-
key_types, key_values =
|
15
|
+
key_types, key_values, key_hashers =
|
16
16
|
if key[:hashers].length == 1
|
17
17
|
[
|
18
18
|
[key[:type]],
|
19
|
-
key[:value]
|
19
|
+
key[:value],
|
20
|
+
key[:hashers]
|
20
21
|
]
|
21
22
|
else
|
22
23
|
[
|
23
|
-
registry[key[:type]]._get(:def)._get(:tuple),
|
24
|
-
key[:value]
|
24
|
+
registry[key[:type]]._get(:def)._get(:tuple).first(key[:value].length),
|
25
|
+
key[:value],
|
26
|
+
key[:hashers].first(key[:value].length)
|
25
27
|
]
|
26
28
|
end
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
raise "Key's value doesn't match key's type, key's value: #{key_values.inspect}, but key's type: #{key_types.inspect}. Please check your key's value." if key_types.class != key_values.class || key_types.length != key_values.length
|
34
|
-
storage_key + PortableCodec._encode_types_with_hashers(key_types, key_values, registry, key[:hashers])
|
30
|
+
if key_types.class != key_values.class || key_types.length != key_values.length
|
31
|
+
raise "Key's value doesn't match key's type, key's value: #{key_values.inspect}, but key's type: #{key_types.inspect}. Please check your key's value."
|
32
|
+
end
|
33
|
+
|
34
|
+
storage_key + PortableCodec._encode_types_with_hashers(key_types, key_values, registry, key_hashers)
|
35
35
|
else
|
36
36
|
storage_key
|
37
37
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scale_rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aki Wu
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-10-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: blake2b_rs
|
@@ -76,6 +76,7 @@ files:
|
|
76
76
|
- lib/address.rb
|
77
77
|
- lib/client/abstract_ws_client.rb
|
78
78
|
- lib/client/http_client.rb
|
79
|
+
- lib/client/http_client_metadata.rb
|
79
80
|
- lib/client/rpc_request_builder.rb
|
80
81
|
- lib/codec.rb
|
81
82
|
- lib/hasher.rb
|