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.
- 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
|