scale.rb 0.2.12 → 0.2.17

Sign up to get free protection for your applications and to get access to all the features.
@@ -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