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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Cargo.lock +2007 -11
- data/Cargo.toml +9 -2
- data/Gemfile.lock +25 -28
- data/README.md +1 -1
- data/lib/address.rb +3 -0
- data/lib/common.rb +163 -0
- data/lib/helper.rb +128 -0
- data/lib/metadata/metadata.rb +15 -1
- data/lib/metadata/metadata_v12.rb +3 -5
- data/lib/scale.rb +52 -19
- data/lib/scale/base.rb +7 -10
- data/lib/scale/block.rb +18 -28
- data/lib/scale/trie.rb +171 -0
- data/lib/scale/types.rb +18 -0
- data/lib/scale/version.rb +1 -1
- data/lib/substrate_client.rb +170 -0
- data/lib/type_registry/crab.json +929 -0
- data/lib/type_registry/darwinia.json +701 -136
- data/scale.gemspec +6 -5
- data/scripts/block_events.rb +2 -3
- data/src/lib.rs +42 -1
- data/src/storage_key.rs +41 -0
- metadata +48 -30
- data/.DS_Store +0 -0
- data/exe/scale +0 -80
@@ -26,21 +26,19 @@ module Scale
|
|
26
26
|
call_module_index = 0
|
27
27
|
event_module_index = 0
|
28
28
|
|
29
|
-
modules.map(&:value).
|
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" % [
|
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" % [
|
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 "
|
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
|
-
|
34
|
-
|
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
|
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] &&
|
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.
|
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}
|
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(&:
|
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(&:
|
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(&:
|
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(&:
|
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.
|
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}".
|
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}".
|
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 =
|
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
|
-
|
372
|
-
length
|
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 == (
|
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[:
|
74
|
-
result[:
|
75
|
-
result[:
|
76
|
-
result[:
|
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
|
-
|
159
|
-
event = metadata.event_index[
|
160
|
-
|
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
|
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
|