scale.rb 0.1.0 → 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/.DS_Store +0 -0
- data/.gitignore +1 -0
- data/Cargo.lock +44 -0
- data/Cargo.toml +11 -0
- data/Dockerfile +2 -1
- data/Gemfile +2 -2
- data/Gemfile.lock +24 -3
- data/Makefile +13 -0
- data/README.md +32 -28
- data/Rakefile +2 -2
- data/bin/console +3 -3
- data/exe/scale +80 -0
- data/lib/metadata/metadata.rb +45 -40
- data/lib/metadata/metadata_v0.rb +206 -0
- data/lib/metadata/metadata_v1.rb +120 -0
- data/lib/metadata/metadata_v10.rb +38 -9
- data/lib/metadata/metadata_v11.rb +51 -0
- data/lib/metadata/metadata_v2.rb +51 -0
- data/lib/metadata/metadata_v3.rb +38 -9
- data/lib/metadata/metadata_v4.rb +126 -0
- data/lib/metadata/metadata_v5.rb +126 -0
- data/lib/metadata/metadata_v6.rb +101 -0
- data/lib/metadata/metadata_v7.rb +47 -18
- data/lib/metadata/metadata_v8.rb +44 -15
- data/lib/metadata/metadata_v9.rb +38 -9
- data/lib/scale.rb +279 -69
- data/lib/scale/base.rb +104 -75
- data/lib/scale/block.rb +115 -0
- data/lib/scale/types.rb +318 -84
- data/lib/scale/version.rb +1 -1
- data/lib/type_registry/darwinia.json +112 -0
- data/lib/type_registry/default.json +842 -0
- data/lib/type_registry/edgeware.json +124 -0
- data/lib/type_registry/joystream.json +49 -0
- data/lib/type_registry/kulupu.json +6 -0
- data/lib/type_registry/kusama.json +186 -0
- data/lib/type_registry/plasm.json +89 -0
- data/lib/type_registry/robonomics.json +39 -0
- data/lib/type_registry/test.json +31 -0
- data/lib/type_registry/westend.json +18 -0
- data/scale.gemspec +18 -15
- data/src/lib.rs +74 -0
- metadata +92 -12
data/lib/scale/base.rb
CHANGED
@@ -8,8 +8,8 @@ module Scale
|
|
8
8
|
@value = value
|
9
9
|
end
|
10
10
|
|
11
|
-
def ==(
|
12
|
-
|
11
|
+
def ==(other)
|
12
|
+
value == other.value
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
@@ -21,18 +21,18 @@ module Scale
|
|
21
21
|
def decode(scale_bytes)
|
22
22
|
byte = scale_bytes.get_next_bytes(1)
|
23
23
|
if byte == [0]
|
24
|
-
|
24
|
+
new(nil)
|
25
25
|
elsif byte == [1]
|
26
|
-
if self::INNER_TYPE_STR ==
|
27
|
-
|
26
|
+
if self::INNER_TYPE_STR == "boolean"
|
27
|
+
new(false)
|
28
28
|
else
|
29
29
|
# big process
|
30
|
-
value =
|
31
|
-
|
30
|
+
value = Scale::Types.get(self::INNER_TYPE_STR).decode(scale_bytes)
|
31
|
+
new(value)
|
32
32
|
end
|
33
33
|
elsif byte == [2]
|
34
|
-
if self::INNER_TYPE_STR ==
|
35
|
-
|
34
|
+
if self::INNER_TYPE_STR == "boolean"
|
35
|
+
new(true)
|
36
36
|
else
|
37
37
|
raise "bad data"
|
38
38
|
end
|
@@ -42,7 +42,7 @@ module Scale
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def inner_type(type_str)
|
45
|
-
|
45
|
+
const_set(:INNER_TYPE_STR, type_str)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
@@ -52,26 +52,54 @@ module Scale
|
|
52
52
|
|
53
53
|
def encode
|
54
54
|
# TODO: add Null type
|
55
|
-
if
|
55
|
+
if value.nil?
|
56
56
|
"00"
|
57
57
|
else
|
58
|
-
return "02" if
|
59
|
-
return "01" if
|
60
|
-
"01" +
|
58
|
+
return "02" if value.class == TrueClass && value === true
|
59
|
+
return "01" if value.class == FalseClass && value === false
|
60
|
+
"01" + value.encode
|
61
61
|
end
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
+
module FixedWidthInt
|
66
|
+
include SingleValue
|
67
|
+
|
68
|
+
module ClassMethods
|
69
|
+
def decode(scale_bytes)
|
70
|
+
bit_length = to_s[15..].to_i
|
71
|
+
byte_length = bit_length / 8
|
72
|
+
bytes = scale_bytes.get_next_bytes byte_length
|
73
|
+
value = bytes.reverse.bytes_to_hex.to_i(16).to_signed(bit_length)
|
74
|
+
new(value)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.included(base)
|
79
|
+
base.extend(ClassMethods)
|
80
|
+
end
|
81
|
+
|
82
|
+
def encode
|
83
|
+
if value.class != ::Integer
|
84
|
+
raise "#{self.class}'s value must be integer"
|
85
|
+
end
|
86
|
+
bit_length = self.class.name[15..].to_i
|
87
|
+
hex = value.to_unsigned(bit_length).to_s(16).hex_to_bytes.reverse.bytes_to_hex
|
88
|
+
hex[2..]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
65
92
|
module FixedWidthUInt
|
66
93
|
include SingleValue
|
67
94
|
|
68
95
|
module ClassMethods
|
96
|
+
attr_accessor :byte_length
|
97
|
+
|
69
98
|
def decode(scale_bytes)
|
70
|
-
|
71
|
-
bytes = scale_bytes.get_next_bytes self::BYTES_LENGTH
|
99
|
+
bytes = scale_bytes.get_next_bytes self::BYTE_LENGTH
|
72
100
|
bytes_reversed = bytes.reverse
|
73
|
-
hex = bytes_reversed.reduce(
|
74
|
-
|
101
|
+
hex = bytes_reversed.reduce("0x") { |hex, byte| hex + byte.to_s(16).rjust(2, "0") }
|
102
|
+
new(hex.to_i(16))
|
75
103
|
end
|
76
104
|
end
|
77
105
|
|
@@ -80,7 +108,10 @@ module Scale
|
|
80
108
|
end
|
81
109
|
|
82
110
|
def encode
|
83
|
-
|
111
|
+
if value.class != ::Integer
|
112
|
+
raise "#{self.class}'s value must be integer"
|
113
|
+
end
|
114
|
+
bytes = value.to_s(16).rjust(self.class::BYTE_LENGTH * 2, "0").scan(/.{2}/).reverse.map {|hex| hex.to_i(16) }
|
84
115
|
bytes.bytes_to_hex[2..]
|
85
116
|
end
|
86
117
|
end
|
@@ -92,7 +123,7 @@ module Scale
|
|
92
123
|
module ClassMethods
|
93
124
|
def decode(scale_bytes)
|
94
125
|
item_values = self::ITEM_TYPE_STRS.map do |item_type_str|
|
95
|
-
|
126
|
+
Scale::Types.get(item_type_str).decode(scale_bytes)
|
96
127
|
end
|
97
128
|
|
98
129
|
value = {}
|
@@ -100,25 +131,25 @@ module Scale
|
|
100
131
|
value[attr] = val
|
101
132
|
end
|
102
133
|
|
103
|
-
result =
|
134
|
+
result = new(value)
|
104
135
|
value.each_pair do |attr, val|
|
105
136
|
result.send "#{attr}=", val
|
106
137
|
end
|
107
|
-
|
138
|
+
result
|
108
139
|
end
|
109
140
|
|
110
|
-
def items(
|
141
|
+
def items(items)
|
111
142
|
attr_names = []
|
112
143
|
attr_type_strs = []
|
113
144
|
|
114
145
|
items.each_pair do |attr_name, attr_type_str|
|
115
|
-
attr_names << attr_name
|
146
|
+
attr_names << attr_name.to_s.gsub("-", "")
|
116
147
|
attr_type_strs << attr_type_str
|
117
148
|
end
|
118
149
|
|
119
|
-
|
120
|
-
|
121
|
-
|
150
|
+
const_set(:ITEM_NAMES, attr_names)
|
151
|
+
const_set(:ITEM_TYPE_STRS, attr_type_strs)
|
152
|
+
attr_accessor *attr_names
|
122
153
|
end
|
123
154
|
end
|
124
155
|
|
@@ -127,8 +158,8 @@ module Scale
|
|
127
158
|
end
|
128
159
|
|
129
160
|
def encode
|
130
|
-
[].tap do |result|
|
131
|
-
|
161
|
+
[].tap do |result|
|
162
|
+
value.each_pair do |attr_name, attr_value|
|
132
163
|
result << attr_value.encode
|
133
164
|
end
|
134
165
|
end.join
|
@@ -137,17 +168,17 @@ module Scale
|
|
137
168
|
|
138
169
|
module Tuple
|
139
170
|
include SingleValue
|
140
|
-
|
171
|
+
|
141
172
|
module ClassMethods
|
142
173
|
def decode(scale_bytes)
|
143
174
|
values = self::TYPE_STRS.map do |type_str|
|
144
|
-
|
175
|
+
Scale::Types.get(type_str).decode(scale_bytes)
|
145
176
|
end
|
146
|
-
|
177
|
+
new(values)
|
147
178
|
end
|
148
179
|
|
149
180
|
def inner_types(*type_strs)
|
150
|
-
|
181
|
+
const_set(:TYPE_STRS, type_strs)
|
151
182
|
end
|
152
183
|
end
|
153
184
|
|
@@ -156,7 +187,7 @@ module Scale
|
|
156
187
|
end
|
157
188
|
|
158
189
|
def encode
|
159
|
-
|
190
|
+
value.map(&:encode).join
|
160
191
|
end
|
161
192
|
end
|
162
193
|
|
@@ -166,18 +197,17 @@ module Scale
|
|
166
197
|
module ClassMethods
|
167
198
|
def decode(scale_bytes)
|
168
199
|
index = scale_bytes.get_next_bytes(1)[0]
|
169
|
-
if
|
200
|
+
if const_defined? "ITEM_NAMES"
|
170
201
|
item_type_str = self::ITEM_TYPE_STRS[index]
|
171
202
|
raise "There is no such member with index #{index} for enum #{self}" if item_type_str.nil?
|
172
|
-
value =
|
173
|
-
return self.new(value)
|
203
|
+
value = Scale::Types.get(item_type_str).decode(scale_bytes)
|
174
204
|
else
|
175
205
|
value = self::VALUES[index]
|
176
|
-
return self.new(value)
|
177
206
|
end
|
207
|
+
new(value)
|
178
208
|
end
|
179
209
|
|
180
|
-
def items(
|
210
|
+
def items(items)
|
181
211
|
attr_names = []
|
182
212
|
attr_type_strs = []
|
183
213
|
|
@@ -186,12 +216,12 @@ module Scale
|
|
186
216
|
attr_type_strs << attr_type_str
|
187
217
|
end
|
188
218
|
|
189
|
-
|
190
|
-
|
219
|
+
const_set(:ITEM_NAMES, attr_names)
|
220
|
+
const_set(:ITEM_TYPE_STRS, attr_type_strs)
|
191
221
|
end
|
192
222
|
|
193
223
|
def values(*values)
|
194
|
-
|
224
|
+
const_set(:VALUES, values)
|
195
225
|
end
|
196
226
|
end
|
197
227
|
|
@@ -201,11 +231,11 @@ module Scale
|
|
201
231
|
|
202
232
|
def encode
|
203
233
|
if self.class.const_defined? "ITEM_NAMES"
|
204
|
-
value_type_str =
|
205
|
-
index = self
|
206
|
-
index +
|
234
|
+
value_type_str = value.class.to_s.split("::").last.to_s
|
235
|
+
index = self.class::ITEM_TYPE_STRS.index(value_type_str).to_s(16).rjust(2, "0")
|
236
|
+
index + value.encode
|
207
237
|
else
|
208
|
-
self
|
238
|
+
self.class::VALUES.index(value).to_s(16).rjust(2, "0")
|
209
239
|
end
|
210
240
|
end
|
211
241
|
end
|
@@ -214,18 +244,18 @@ module Scale
|
|
214
244
|
include SingleValue # value is an array
|
215
245
|
|
216
246
|
module ClassMethods
|
217
|
-
def decode(scale_bytes, raw=false)
|
247
|
+
def decode(scale_bytes, raw = false)
|
218
248
|
number = Scale::Types::Compact.decode(scale_bytes).value
|
219
249
|
items = []
|
220
250
|
number.times do
|
221
|
-
item =
|
251
|
+
item = Scale::Types.get(self::INNER_TYPE_STR).decode(scale_bytes)
|
222
252
|
items << item
|
223
253
|
end
|
224
|
-
raw ? items :
|
254
|
+
raw ? items : new(items)
|
225
255
|
end
|
226
256
|
|
227
257
|
def inner_type(type_str)
|
228
|
-
|
258
|
+
const_set(:INNER_TYPE_STR, type_str)
|
229
259
|
end
|
230
260
|
end
|
231
261
|
|
@@ -234,9 +264,9 @@ module Scale
|
|
234
264
|
end
|
235
265
|
|
236
266
|
def encode
|
237
|
-
number = Scale::Types::Compact.new(
|
267
|
+
number = Scale::Types::Compact.new(value.length).encode
|
238
268
|
[number].tap do |result|
|
239
|
-
|
269
|
+
value.each do |element|
|
240
270
|
result << element.encode
|
241
271
|
end
|
242
272
|
end.join
|
@@ -248,24 +278,24 @@ module Scale
|
|
248
278
|
|
249
279
|
module ClassMethods
|
250
280
|
def decode(scale_bytes)
|
251
|
-
value = "Scale::Types::U#{self::BYTES_LENGTH*8}".constantize.decode(scale_bytes).value
|
252
|
-
return
|
281
|
+
value = "Scale::Types::U#{self::BYTES_LENGTH * 8}".constantize.decode(scale_bytes).value
|
282
|
+
return new [] unless value || value <= 0
|
253
283
|
|
254
|
-
result = self::
|
255
|
-
|
284
|
+
result = self::ITEMS.select { |_, mask| value & mask > 0 }.keys
|
285
|
+
new result
|
256
286
|
end
|
257
287
|
|
258
|
-
#
|
288
|
+
# items is a hash:
|
259
289
|
# {
|
260
290
|
# "TransactionPayment" => 0b00000001,
|
261
291
|
# "Transfer" => 0b00000010,
|
262
292
|
# "Reserve" => 0b00000100,
|
263
293
|
# ...
|
264
294
|
# }
|
265
|
-
def
|
266
|
-
raise "byte length is wrong: #{bytes_length}"
|
267
|
-
|
268
|
-
|
295
|
+
def items(items, bytes_length = 1)
|
296
|
+
raise "byte length is wrong: #{bytes_length}" unless [1, 2, 4, 8, 16].include?(bytes_length)
|
297
|
+
const_set(:ITEMS, items)
|
298
|
+
const_set(:BYTES_LENGTH, bytes_length)
|
269
299
|
end
|
270
300
|
end
|
271
301
|
|
@@ -274,8 +304,8 @@ module Scale
|
|
274
304
|
end
|
275
305
|
|
276
306
|
def encode
|
277
|
-
value = self.class::
|
278
|
-
"Scale::Types::U#{self.class::BYTES_LENGTH*8}".constantize.new(value).encode
|
307
|
+
value = self.class::ITEMS.select { |key, _| self.value.include?(key) }.values.sum
|
308
|
+
"Scale::Types::U#{self.class::BYTES_LENGTH * 8}".constantize.new(value).encode
|
279
309
|
end
|
280
310
|
end
|
281
311
|
|
@@ -284,17 +314,16 @@ module Scale
|
|
284
314
|
|
285
315
|
module ClassMethods
|
286
316
|
def decode(scale_bytes)
|
287
|
-
|
288
|
-
length
|
289
|
-
|
290
|
-
length = length.to_i
|
317
|
+
byte_length = name[25..]
|
318
|
+
raise "length is wrong: #{byte_length}" unless %w[2 3 4 8 16 20 32 64].include?(byte_length)
|
319
|
+
byte_length = byte_length.to_i
|
291
320
|
|
292
|
-
bytes = scale_bytes.get_next_bytes(
|
321
|
+
bytes = scale_bytes.get_next_bytes(byte_length)
|
293
322
|
str = bytes.pack("C*").force_encoding("utf-8")
|
294
323
|
if str.valid_encoding?
|
295
|
-
|
324
|
+
new str
|
296
325
|
else
|
297
|
-
|
326
|
+
new bytes.bytes_to_hex
|
298
327
|
end
|
299
328
|
end
|
300
329
|
end
|
@@ -305,14 +334,14 @@ module Scale
|
|
305
334
|
|
306
335
|
def encode
|
307
336
|
class_name = self.class.to_s
|
308
|
-
length = class_name[
|
309
|
-
raise "length is wrong: #{length}"
|
337
|
+
length = class_name[25..]
|
338
|
+
raise "length is wrong: #{length}" unless %w[2 3 4 8 16 20 32 64].include?(length)
|
310
339
|
length = length.to_i
|
311
340
|
|
312
|
-
if
|
313
|
-
|
341
|
+
if value.start_with?("0x") && value.length == (length * 2 + 2)
|
342
|
+
value[2..]
|
314
343
|
else
|
315
|
-
bytes =
|
344
|
+
bytes = value.unpack("C*")
|
316
345
|
bytes.bytes_to_hex[2..]
|
317
346
|
end
|
318
347
|
end
|
data/lib/scale/block.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
module Scale
|
2
|
+
module Types
|
3
|
+
|
4
|
+
class Extrinsic
|
5
|
+
include SingleValue
|
6
|
+
# attr_accessor :address, :signature, :nonce, :era, :extrinsic_hash, :call_index, :params_raw, :params
|
7
|
+
|
8
|
+
def self.generate_hash(data)
|
9
|
+
Blake2b.hex data, Blake2b::Key.none, 32
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.decode(scale_bytes, metadata)
|
13
|
+
result = {}
|
14
|
+
|
15
|
+
extrinsic_length = Compact.decode(scale_bytes).value
|
16
|
+
# TODO: legacy version
|
17
|
+
|
18
|
+
version_info = scale_bytes.get_next_bytes(1).bytes_to_hex
|
19
|
+
contains_transaction = version_info.to_i(16) >= 80
|
20
|
+
|
21
|
+
if version_info == "0x01" || version_info == "0x81"
|
22
|
+
|
23
|
+
if contains_transaction
|
24
|
+
address = Scale::Types.get("Address").decode(scale_bytes)
|
25
|
+
result[:address] = address.value
|
26
|
+
result[:account_length] = address.account_length
|
27
|
+
result[:account_id] = address.account_id
|
28
|
+
result[:account_index] = address.account_index
|
29
|
+
result[:signature] = Scale::Types.get("Signature").decode(scale_bytes).value
|
30
|
+
result[:nonce] = Scale::Types.get("Compact").decode(scale_bytes).value
|
31
|
+
result[:era] = Scale::Types.get("Era").decode(scale_bytes).value
|
32
|
+
result[:extrinsic_hash] = generate_hash(scale_bytes.bytes)
|
33
|
+
end
|
34
|
+
result[:call_index] = scale_bytes.get_next_bytes(2).bytes_to_hex[2..]
|
35
|
+
|
36
|
+
elsif version_info == "0x02" || version_info == "0x82"
|
37
|
+
|
38
|
+
if contains_transaction
|
39
|
+
address = Scale::Types.get("Address").decode(scale_bytes)
|
40
|
+
result[:address] = address.value
|
41
|
+
result[:account_length] = address.account_length
|
42
|
+
result[:account_id] = address.account_id
|
43
|
+
result[:account_index] = address.account_index
|
44
|
+
result[:signature] = Scale::Types.get("Signature").decode(scale_bytes).value
|
45
|
+
result[:era] = Scale::Types.get("Era").decode(scale_bytes).value
|
46
|
+
result[:nonce] = Scale::Types.get("Compact").decode(scale_bytes).value
|
47
|
+
result[:tip] = Scale::Types.get("Compact").decode(scale_bytes).value
|
48
|
+
result[:extrinsic_hash] = generate_hash(scale_bytes.bytes)
|
49
|
+
end
|
50
|
+
result[:call_index] = scale_bytes.get_next_bytes(2).bytes_to_hex[2..]
|
51
|
+
|
52
|
+
elsif version_info == "0x03" || version_info == "0x83"
|
53
|
+
|
54
|
+
if contains_transaction
|
55
|
+
address = Scale::Types.get("Address").decode(scale_bytes)
|
56
|
+
result[:address] = address.value
|
57
|
+
result[:account_length] = address.account_length
|
58
|
+
result[:account_id] = address.account_id
|
59
|
+
result[:account_index] = address.account_index
|
60
|
+
result[:signature] = Scale::Types.get("Signature").decode(scale_bytes).value
|
61
|
+
result[:era] = Scale::Types.get("Era").decode(scale_bytes).value
|
62
|
+
result[:nonce] = Scale::Types.get("Compact").decode(scale_bytes).value
|
63
|
+
result[:tip] = Scale::Types.get("Compact").decode(scale_bytes).value
|
64
|
+
result[:extrinsic_hash] = generate_hash(scale_bytes.bytes)
|
65
|
+
end
|
66
|
+
result[:call_index] = scale_bytes.get_next_bytes(2).bytes_to_hex[2..]
|
67
|
+
|
68
|
+
elsif version_info == "0x04" || version_info == "0x84"
|
69
|
+
|
70
|
+
if contains_transaction
|
71
|
+
address = Scale::Types.get("Address").decode(scale_bytes)
|
72
|
+
result[:address] = address.value
|
73
|
+
result[:account_length] = address.account_length
|
74
|
+
result[:account_id] = address.account_id
|
75
|
+
result[:account_index] = address.account_index
|
76
|
+
result[:signature_version] = Scale::Types.get("U8").decode(scale_bytes).value
|
77
|
+
result[:signature] = Scale::Types.get("Signature").decode(scale_bytes).value
|
78
|
+
result[:era] = Scale::Types.get("Era").decode(scale_bytes).value
|
79
|
+
result[:nonce] = Scale::Types.get("Compact").decode(scale_bytes).value
|
80
|
+
result[:tip] = Scale::Types.get("Compact").decode(scale_bytes).value
|
81
|
+
result[:extrinsic_hash] = generate_hash(scale_bytes.bytes)
|
82
|
+
end
|
83
|
+
result[:call_index] = scale_bytes.get_next_bytes(2).bytes_to_hex[2..]
|
84
|
+
|
85
|
+
else
|
86
|
+
raise "Extrinsics version #{version_info} is not implemented"
|
87
|
+
end
|
88
|
+
|
89
|
+
if result[:call_index]
|
90
|
+
call_module, call = metadata.value.call_index[result[:call_index]]
|
91
|
+
|
92
|
+
result[:call_function] = call[:name].downcase
|
93
|
+
result[:call_module] = call_module[:name].downcase
|
94
|
+
|
95
|
+
# decode params
|
96
|
+
result[:params_raw] = scale_bytes.get_remaining_bytes.bytes_to_hex
|
97
|
+
result[:params] = call[:args].map do |arg|
|
98
|
+
type = Scale::Types.get(arg[:type])
|
99
|
+
arg_obj = type.decode(scale_bytes)
|
100
|
+
{name: arg[:name], type: type.name, value: arg_obj.value, value_raw: "0x#{arg_obj.encode}" }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
result[:extrinsic_length] = extrinsic_length
|
105
|
+
result[:version_info] = version_info
|
106
|
+
|
107
|
+
result
|
108
|
+
end
|
109
|
+
|
110
|
+
def encode
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|