scale.rb 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|