scale.rb 0.2.12 → 0.2.17

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.
@@ -26,21 +26,19 @@ module Scale
26
26
  call_module_index = 0
27
27
  event_module_index = 0
28
28
 
29
- modules.map(&:value).each do |m|
29
+ modules.map(&:value).each_with_index do |m, module_index|
30
30
  if m[:calls]
31
31
  m[:calls].each_with_index do |call, index|
32
- call[:lookup] = "%02x%02x" % [call_module_index, index]
32
+ call[:lookup] = "%02x%02x" % [module_index, index]
33
33
  result.call_index[call[:lookup]] = [m, call]
34
34
  end
35
- call_module_index += 1
36
35
  end
37
36
 
38
37
  if m[:events]
39
38
  m[:events].each_with_index do |event, index|
40
- event[:lookup] = "%02x%02x" % [event_module_index, index]
39
+ event[:lookup] = "%02x%02x" % [module_index, index]
41
40
  result.event_index[event[:lookup]] = [m, event]
42
41
  end
43
- event_module_index += 1
44
42
  end
45
43
  end
46
44
 
data/lib/scale.rb CHANGED
@@ -1,14 +1,14 @@
1
1
  require "scale/version"
2
2
 
3
- require "substrate_common"
3
+ require "common"
4
+
4
5
  require "json"
5
- require "active_support"
6
- require "active_support/core_ext/string"
7
6
  require "singleton"
8
7
 
9
8
  require "scale/base"
10
9
  require "scale/types"
11
10
  require "scale/block"
11
+ require "scale/trie"
12
12
 
13
13
  require "metadata/metadata"
14
14
  require "metadata/metadata_v0"
@@ -25,13 +25,40 @@ require "metadata/metadata_v10"
25
25
  require "metadata/metadata_v11"
26
26
  require "metadata/metadata_v12"
27
27
 
28
+ require "substrate_client"
29
+ require "logger"
30
+ require "helper"
31
+
32
+ class String
33
+ def upcase_first
34
+ self.sub(/\S/, &:upcase)
35
+ end
36
+
37
+ def camelize2
38
+ self.split('_').collect(&:upcase_first).join
39
+ end
40
+
41
+ def underscore2
42
+ self.gsub(/::/, '/').
43
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
44
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
45
+ tr("-", "_").
46
+ downcase
47
+ end
48
+ end
49
+
28
50
  module Scale
29
51
  class Error < StandardError; end
30
52
 
31
53
  class TypeRegistry
32
54
  include Singleton
33
- attr_reader :spec_name, :types, :versioning, :custom_types
34
- attr_accessor :spec_version
55
+
56
+ # init by load, and will not change
57
+ attr_reader :spec_name, :types
58
+ attr_reader :versioning, :custom_types # optional
59
+
60
+ # will change by different spec version
61
+ attr_accessor :spec_version # optional
35
62
  attr_accessor :metadata
36
63
 
37
64
  def load(spec_name: nil, custom_types: nil)
@@ -42,13 +69,18 @@ module Scale
42
69
 
43
70
  default_types, _, _ = load_chain_spec_types("default")
44
71
 
45
- if spec_name.nil? || spec_name == "default"
72
+ if spec_name
73
+ begin
74
+ @spec_name = spec_name
75
+ spec_types, @versioning, @spec_version = load_chain_spec_types(spec_name)
76
+ @types = default_types.merge(spec_types)
77
+ rescue => ex
78
+ puts "There is no types json file named #{spec_name}"
79
+ @types = default_types
80
+ end
81
+ else
46
82
  @spec_name = "default"
47
83
  @types = default_types
48
- else
49
- @spec_name = spec_name
50
- spec_types, @versioning, @spec_version = load_chain_spec_types(spec_name)
51
- @types = default_types.merge(spec_types)
52
84
  end
53
85
 
54
86
  self.custom_types = custom_types
@@ -62,7 +94,8 @@ module Scale
62
94
 
63
95
  if @spec_version && @versioning
64
96
  @versioning.each do |item|
65
- if @spec_version >= item["runtime_range"][0] && @spec_version <= (item["runtime_range"][1] || 1073741823)
97
+ if @spec_version >= item["runtime_range"][0] &&
98
+ ( item["runtime_range"][1].nil? || @spec_version <= item["runtime_range"][1] )
66
99
  all_types.merge!(item["types"])
67
100
  end
68
101
  end
@@ -175,7 +208,7 @@ module Scale
175
208
  types.each do |name, body|
176
209
  if body.class == String
177
210
  target_type = "Scale::Types::#{body}"
178
- klass = Class.new(target_type.constantize) do
211
+ klass = Class.new(target_type.constantize2) do
179
212
  end
180
213
  elsif body.class == Hash
181
214
  if body["type"] == "struct"
@@ -244,7 +277,7 @@ module Scale
244
277
  include Scale::Types.type_of(type_str)
245
278
  inner_type inner_type_str
246
279
  end
247
- name = "#{type_str}_Of_#{inner_type_str.camelize}_#{klass.object_id}"
280
+ name = "#{type_str}<#{inner_type_str.camelize2}>_#{klass.object_id}"
248
281
  Scale::Types.const_set fix(name), klass
249
282
  else
250
283
  raise "#{type_str} not support inner type: #{type_string}"
@@ -266,7 +299,7 @@ module Scale
266
299
  include Scale::Types::Tuple
267
300
  inner_types *type_strs
268
301
  end
269
- name = "Tuple_Of_#{type_strs.map(&:camelize).join("_")}_#{klass.object_id}"
302
+ name = "Tuple_Of_#{type_strs.map(&:camelize2).join("_")}_#{klass.object_id}"
270
303
  Scale::Types.const_set fix(name), klass
271
304
  else
272
305
  if type_string == "Enum"
@@ -279,7 +312,7 @@ module Scale
279
312
  values(*values)
280
313
  end
281
314
  end
282
- name = values.class == ::Hash ? values.values.map(&:camelize).join("_") : values.map(&:camelize).join("_")
315
+ name = values.class == ::Hash ? values.values.map(&:camelize2).join("_") : values.map(&:camelize2).join("_")
283
316
  name = "Enum_Of_#{name}_#{klass.object_id}"
284
317
  Scale::Types.const_set fix(name), klass
285
318
  elsif type_string == "Struct"
@@ -287,19 +320,19 @@ module Scale
287
320
  include Scale::Types::Struct
288
321
  items values
289
322
  end
290
- name = "Struct_Of_#{values.values.map(&:camelize).join("_")}_#{klass.object_id}"
323
+ name = "Struct_Of_#{values.values.map(&:camelize2).join("_")}_#{klass.object_id}"
291
324
  Scale::Types.const_set fix(name), klass
292
325
  elsif type_string == "Set"
293
326
  klass = Class.new do
294
327
  include Scale::Types::Set
295
328
  items values, 1
296
329
  end
297
- name = "Set_Of_#{values.keys.map(&:camelize).join("_")}_#{klass.object_id}"
330
+ name = "Set_Of_#{values.keys.map(&:camelize2).join("_")}_#{klass.object_id}"
298
331
  Scale::Types.const_set fix(name), klass
299
332
  else
300
333
  type_name = (type_string.start_with?("Scale::Types::") ? type_string : "Scale::Types::#{type_string}")
301
334
  begin
302
- type_name.constantize
335
+ type_name.constantize2
303
336
  rescue NameError => e
304
337
  puts "#{type_string} is not defined"
305
338
  end
@@ -341,7 +374,7 @@ def rename(type)
341
374
  return "AccountData" if type == "AccountData<Balance>"
342
375
 
343
376
  if type =~ /\[U\d+; \d+\]/
344
- byte_length = type.scan(/\[U\d+; (\d+)\]/).first.first
377
+ byte_length = type.scan(/\[U\d+; (\d+)\]/).first.first.to_i
345
378
  return "VecU8Length#{byte_length}"
346
379
  end
347
380
 
data/lib/scale/base.rb CHANGED
@@ -313,7 +313,7 @@ module Scale
313
313
 
314
314
  module ClassMethods
315
315
  def decode(scale_bytes)
316
- value = "Scale::Types::U#{self::BYTE_LENGTH * 8}".constantize.decode(scale_bytes).value
316
+ value = "Scale::Types::U#{self::BYTE_LENGTH * 8}".constantize2.decode(scale_bytes).value
317
317
  return new [] unless value || value <= 0
318
318
 
319
319
  result = self::ITEMS.select { |_, mask| value & mask > 0 }.keys
@@ -340,7 +340,7 @@ module Scale
340
340
 
341
341
  def encode
342
342
  value = self.class::ITEMS.select { |key, _| self.value.include?(key) }.values.sum
343
- "Scale::Types::U#{self.class::BYTE_LENGTH * 8}".constantize.new(value).encode
343
+ "Scale::Types::U#{self.class::BYTE_LENGTH * 8}".constantize2.new(value).encode
344
344
  end
345
345
  end
346
346
 
@@ -349,9 +349,8 @@ module Scale
349
349
 
350
350
  module ClassMethods
351
351
  def decode(scale_bytes)
352
- byte_length = name[25..]
353
- raise "length is wrong: #{byte_length}" unless %w[2 3 4 8 16 20 32 64].include?(byte_length)
354
- byte_length = byte_length.to_i
352
+ byte_length = self::BYTE_LENGTH
353
+ raise "#{self.name} byte length is wrong: #{byte_length}" unless %w[2 3 4 8 16 20 32 64 128 256].include?(byte_length.to_s)
355
354
 
356
355
  bytes = scale_bytes.get_next_bytes(byte_length)
357
356
  str = bytes.pack("C*").force_encoding("utf-8")
@@ -368,12 +367,10 @@ module Scale
368
367
  end
369
368
 
370
369
  def encode
371
- class_name = self.class.to_s
372
- length = class_name[25..]
373
- raise "length is wrong: #{length}" unless %w[2 3 4 8 16 20 32 64].include?(length)
374
- length = length.to_i
370
+ byte_length = self.class::BYTE_LENGTH
371
+ raise "#{self.class.name}'s byte length is wrong: #{byte_length}" unless %w[2 3 4 8 16 20 32 64 128 256].include?(byte_length.to_s)
375
372
 
376
- if value.start_with?("0x") && value.length == (length * 2 + 2)
373
+ if value.start_with?("0x") && value.length == (byte_length * 2 + 2)
377
374
  value[2..]
378
375
  else
379
376
  bytes = value.unpack("C*")
data/lib/scale/block.rb CHANGED
@@ -10,7 +10,7 @@ module Scale
10
10
  end
11
11
 
12
12
  def self.decode(scale_bytes)
13
- metadata = Scale::TypeRegistry.instance.metadata
13
+ metadata = Scale::TypeRegistry.instance.metadata.value
14
14
  result = {}
15
15
 
16
16
  extrinsic_length = Compact.decode(scale_bytes).value
@@ -24,9 +24,6 @@ module Scale
24
24
  if contains_transaction
25
25
  address = Scale::Types.get("Address").decode(scale_bytes)
26
26
  result[:address] = address.value
27
- result[:account_length] = address.account_length
28
- result[:account_id] = address.account_id
29
- result[:account_index] = address.account_index
30
27
  result[:signature] = Scale::Types.get("Signature").decode(scale_bytes).value
31
28
  result[:nonce] = Scale::Types.get("Compact").decode(scale_bytes).value
32
29
  result[:era] = Scale::Types.get("Era").decode(scale_bytes).value
@@ -39,9 +36,6 @@ module Scale
39
36
  if contains_transaction
40
37
  address = Scale::Types.get("Address").decode(scale_bytes)
41
38
  result[:address] = address.value
42
- result[:account_length] = address.account_length
43
- result[:account_id] = address.account_id
44
- result[:account_index] = address.account_index
45
39
  result[:signature] = Scale::Types.get("Signature").decode(scale_bytes).value
46
40
  result[:era] = Scale::Types.get("Era").decode(scale_bytes).value
47
41
  result[:nonce] = Scale::Types.get("Compact").decode(scale_bytes).value
@@ -55,9 +49,6 @@ module Scale
55
49
  if contains_transaction
56
50
  address = Scale::Types.get("Address").decode(scale_bytes)
57
51
  result[:address] = address.value
58
- result[:account_length] = address.account_length
59
- result[:account_id] = address.account_id
60
- result[:account_index] = address.account_index
61
52
  result[:signature] = Scale::Types.get("Signature").decode(scale_bytes).value
62
53
  result[:era] = Scale::Types.get("Era").decode(scale_bytes).value
63
54
  result[:nonce] = Scale::Types.get("Compact").decode(scale_bytes).value
@@ -69,16 +60,11 @@ module Scale
69
60
  elsif version_info == "0x04" || version_info == "0x84"
70
61
 
71
62
  if contains_transaction
72
- address = Scale::Types.get("Address").decode(scale_bytes)
73
- result[:address] = address.value
74
- result[:account_length] = address.account_length
75
- result[:account_id] = address.account_id
76
- result[:account_index] = address.account_index
77
- result[:signature_version] = Scale::Types.get("U8").decode(scale_bytes).value
78
- result[:signature] = Scale::Types.get("Signature").decode(scale_bytes).value
79
- result[:era] = Scale::Types.get("Era").decode(scale_bytes).value
80
- result[:nonce] = Scale::Types.get("Compact").decode(scale_bytes).value
81
- result[:tip] = Scale::Types.get("Compact").decode(scale_bytes).value
63
+ result[:address] = Scale::Types.get("Address").decode(scale_bytes).value
64
+ result[:signature] = scale::types.get("MultiSignature").decode(scale_bytes).value
65
+ result[:era] = scale::types.get("era").decode(scale_bytes).value
66
+ result[:nonce] = scale::types.get("compact").decode(scale_bytes).value
67
+ result[:tip] = scale::types.get("compact").decode(scale_bytes).value
82
68
  result[:extrinsic_hash] = generate_hash(scale_bytes.bytes)
83
69
  end
84
70
  result[:call_index] = scale_bytes.get_next_bytes(2).bytes_to_hex[2..]
@@ -146,7 +132,7 @@ module Scale
146
132
  include SingleValue
147
133
 
148
134
  def self.decode(scale_bytes)
149
- metadata = Scale::TypeRegistry.instance.metadata
135
+ metadata = Scale::TypeRegistry.instance.metadata.value
150
136
 
151
137
  result = {}
152
138
  phase = scale_bytes.get_next_bytes(1).first
@@ -155,9 +141,13 @@ module Scale
155
141
  result[:extrinsic_idx] = U32.decode(scale_bytes).value
156
142
  end
157
143
 
158
- type = scale_bytes.get_next_bytes(2).bytes_to_hex[2..]
159
- event = metadata.event_index[type][1]
160
- # mod = metadata.event_index[type][0]
144
+ index = scale_bytes.get_next_bytes(2).bytes_to_hex[2..]
145
+ event = metadata.event_index[index][1]
146
+ the_module = metadata.event_index[index][0]
147
+
148
+ result[:event_index] = index
149
+ result[:event_metadata] = event
150
+ result[:module_metadata] = the_module
161
151
 
162
152
  result[:params] = []
163
153
  event[:args].each do |arg_type|
@@ -175,18 +165,18 @@ module Scale
175
165
  end
176
166
  end
177
167
 
178
- # log
179
- class Other < Bytes; end
180
-
181
168
  class AuthoritiesChange
182
169
  include Vec
183
170
  inner_type "AccountId"
184
171
  end
185
172
 
186
- class ConsensusEngineId < VecU8Length4; end
173
+ class GenericConsensusEngineId < VecU8Length4; end
187
174
 
188
175
  class ChangesTrieRoot < Bytes; end
189
176
 
177
+ # log
178
+ class Other < Bytes; end
179
+
190
180
  class SealV0
191
181
  include Struct
192
182
  items(
data/lib/scale/trie.rb ADDED
@@ -0,0 +1,171 @@
1
+ module Scale
2
+ module Types
3
+
4
+ class TrieNode
5
+ include SingleValue
6
+ EMPTY = 0
7
+ NIBBLE_PER_BYTE = 2
8
+ BITMAP_LENGTH = 2
9
+ NIBBLE_LENGTH = 16
10
+ NIBBLE_SIZE_BOUND = 65535
11
+
12
+ def self.decode(scale_bytes)
13
+ hash = "0x#{Crypto::blake2_256(scale_bytes.bytes)}"
14
+ first = scale_bytes.get_next_bytes(1).first
15
+ if first == EMPTY
16
+ TrieNode.new({})
17
+ else
18
+ v = first & (0b11 << 6)
19
+ decode_size = -> {
20
+ result = first & 255 >> 2
21
+ return result if result < 63
22
+ result -= 1
23
+ while result <= NIBBLE_SIZE_BOUND
24
+ n = scale_bytes.get_next_bytes(1).first
25
+ return (result + n + 1) if n < 255
26
+ result += 255
27
+ end
28
+ return NIBBLE_SIZE_BOUND
29
+ }
30
+
31
+ if v == 0b01 << 6 # leaf
32
+ nibble_count = decode_size.call
33
+ # if nibble_count is odd, the half of first byte of partial is 0
34
+ padding = (nibble_count % NIBBLE_PER_BYTE) != 0
35
+ first_byte_of_partial = scale_bytes.bytes[scale_bytes.offset]
36
+ if padding && (first_byte_of_partial & 0xf0) != 0
37
+ raise "bad format"
38
+ end
39
+
40
+ ### partial decoding
41
+ partial_bytes = scale_bytes.get_next_bytes((nibble_count + (NIBBLE_PER_BYTE - 1)) / NIBBLE_PER_BYTE)
42
+
43
+ ### value
44
+ count = Compact.decode(scale_bytes).value
45
+ value_bytes = scale_bytes.get_next_bytes(count)
46
+
47
+ return TrieNode.new({
48
+ hash: hash,
49
+ node_type: "leaf",
50
+ partial: {
51
+ hex: partial_bytes.bytes_to_hex,
52
+ padding: padding
53
+ },
54
+ value: value_bytes.bytes_to_hex
55
+ })
56
+ elsif v == 0b10 << 6 || v == 0b11 << 6 # branch without mask || branch with mask
57
+ nibble_count = decode_size.call
58
+
59
+ ### check that the padding is valid (if any)
60
+ # if nibble_count is odd, the half of first byte of partial is 0
61
+ padding = nibble_count % NIBBLE_PER_BYTE != 0
62
+ first_byte_of_partial = scale_bytes.bytes[scale_bytes.offset]
63
+ if padding && (first_byte_of_partial & 0xf0) != 0
64
+ raise "bad format"
65
+ end
66
+
67
+ ### partial decoding
68
+ partial_bytes = scale_bytes.get_next_bytes((nibble_count + (NIBBLE_PER_BYTE - 1)) / NIBBLE_PER_BYTE)
69
+
70
+ ### value decoding
71
+ if v == 0b11 << 6 # has value
72
+ count = Compact.decode(scale_bytes).value
73
+ value_bytes = scale_bytes.get_next_bytes(count)
74
+ end
75
+
76
+ ### children decoding
77
+ children = []
78
+ bitmap = U16.decode(scale_bytes).value
79
+ NIBBLE_LENGTH.times do |i|
80
+ has_child = (bitmap & (1 << i)) != 0
81
+ children[i] = nil
82
+ if has_child
83
+ count = Compact.decode(scale_bytes).value
84
+ if count == 32
85
+ h = H256.decode(scale_bytes).value
86
+ children[i] = h
87
+ else
88
+ inline = scale_bytes.get_next_bytes count
89
+ children[i] = inline.bytes_to_hex
90
+ end
91
+ end
92
+ end
93
+ # debug
94
+ # children.each_with_index do |child, i|
95
+ # if child.nil?
96
+ # puts "#{i}: NULL"
97
+ # else
98
+ # puts "#{i}: #{child}"
99
+ # end
100
+ # end
101
+
102
+ result = TrieNode.new({
103
+ hash: hash,
104
+ node_type: "branch",
105
+ partial: {
106
+ hex: partial_bytes.bytes_to_hex,
107
+ padding: padding
108
+ },
109
+ children: children
110
+ })
111
+
112
+ result[:value] = value_bytes.bytes_to_hex if value_bytes
113
+
114
+ return result
115
+ else
116
+ puts "Not support"
117
+ end
118
+
119
+ end
120
+ end
121
+
122
+ def self.check(root, proof, key)
123
+ key = Key.new(key)
124
+
125
+ nodes = proof.map {|node_data|
126
+ node = TrieNode::decode(Scale::Bytes.new(node_data)).value
127
+ [node[:hash], node]
128
+ }.to_h
129
+
130
+ self.do_check(root, nodes, key)
131
+ end
132
+
133
+ private
134
+ def self.do_check(hash, nodes, key)
135
+ if node = nodes[hash]
136
+ if node[:children]
137
+ position = key.next_nibble(node[:partial][:hex], node[:partial][:padding]).to_i(16)
138
+ child = node[:children][position]
139
+ return self.do_check(child, nodes, key)
140
+ else
141
+ return node[:value]
142
+ end
143
+ else
144
+ raise "Fail"
145
+ end
146
+ end
147
+ end
148
+
149
+ end
150
+ end
151
+
152
+ class Key
153
+ def initialize(value)
154
+ @value = value[2..] if value.start_with?("0x")
155
+ @offset = 0
156
+ end
157
+
158
+ def next_nibble(partial, padding)
159
+ partial = partial[2..] if partial.start_with?("0x")
160
+ partial = partial[1..] if padding
161
+
162
+ new_offset = @offset + partial.length
163
+ if partial == @value[@offset...new_offset]
164
+ nibble = @value[new_offset]
165
+ @offset = new_offset + 1
166
+ return nibble
167
+ else
168
+ raise "Fail"
169
+ end
170
+ end
171
+ end