scale.rb 0.2.14 → 0.2.15

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.
data/Cargo.toml CHANGED
@@ -2,10 +2,17 @@
2
2
  name = "SCALE-testing-interface"
3
3
  version = "0.1.0"
4
4
  authors = ["Robert Hambrock <robert@web3.foundation>"]
5
+ edition = "2018"
5
6
 
6
7
  [dependencies]
7
- parity-scale-codec = { version = "1.2.0" }
8
+ parity-scale-codec = { version = "1.3.6" }
9
+ sp-core = { version = "2.0.0", git = "https://github.com/paritytech/substrate.git", features = ["full_crypto"]}
10
+ frame-support = { version = "2.0.0", git = "https://github.com/paritytech/substrate.git" }
8
11
 
9
12
  [lib]
10
13
  name = "scale_ffi"
11
- crate-type = ["dylib"]
14
+ crate-type = ["dylib"]
15
+
16
+ [[bin]]
17
+ name = "storage_key"
18
+ path = "src/storage_key.rs"
data/Gemfile.lock CHANGED
@@ -1,10 +1,11 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- scale.rb (0.2.14)
5
- activesupport (>= 4.0.0)
4
+ scale.rb (0.2.15)
5
+ activesupport (~> 6.0.0)
6
6
  json (~> 2.3.0)
7
- substrate_common.rb (~> 0.1.9)
7
+ kontena-websocket-client (~> 0.1.1)
8
+ substrate_common.rb (~> 0.1.10)
8
9
  thor (~> 0.19.0)
9
10
 
10
11
  GEM
@@ -19,14 +20,16 @@ GEM
19
20
  base58 (0.2.3)
20
21
  blake2b (0.10.0)
21
22
  coderay (1.1.2)
22
- concurrent-ruby (1.1.7)
23
+ concurrent-ruby (1.1.8)
23
24
  diff-lcs (1.3)
24
25
  ffi (1.12.2)
25
- i18n (1.8.5)
26
+ i18n (1.8.8)
26
27
  concurrent-ruby (~> 1.0)
27
28
  json (2.3.1)
29
+ kontena-websocket-client (0.1.1)
30
+ websocket-driver (~> 0.6.5)
28
31
  method_source (0.9.2)
29
- minitest (5.14.2)
32
+ minitest (5.14.3)
30
33
  pry (0.12.2)
31
34
  coderay (~> 1.1.0)
32
35
  method_source (~> 0.9.0)
@@ -44,16 +47,19 @@ GEM
44
47
  diff-lcs (>= 1.2.0, < 2.0)
45
48
  rspec-support (~> 3.9.0)
46
49
  rspec-support (3.9.0)
47
- substrate_common.rb (0.1.9)
50
+ substrate_common.rb (0.1.10)
48
51
  base58
49
52
  blake2b
50
53
  xxhash
51
54
  thor (0.19.4)
52
55
  thread_safe (0.3.6)
53
- tzinfo (1.2.8)
56
+ tzinfo (1.2.9)
54
57
  thread_safe (~> 0.1)
58
+ websocket-driver (0.6.5)
59
+ websocket-extensions (>= 0.1.0)
60
+ websocket-extensions (0.1.5)
55
61
  xxhash (0.4.0)
56
- zeitwerk (2.4.1)
62
+ zeitwerk (2.4.2)
57
63
 
58
64
  PLATFORMS
59
65
  ruby
data/exe/scale CHANGED
@@ -75,6 +75,15 @@ class ScaleCli < Thor
75
75
  type = Scale::Types.get(type_name)
76
76
  p "0x" + type.new(value.to_i).encode
77
77
  end
78
+
79
+ desc "check_read_proof ROOT PROOF STORAGE_KEY", "check read proof and output leaf's value"
80
+ def check_read_proof(root, proof, storage_key)
81
+ Scale::TypeRegistry.instance.load
82
+ proof = proof.split(",").map(&:strip)
83
+
84
+ value = Scale::Types::TrieNode::check(root, proof, storage_key)
85
+ p value
86
+ end
78
87
  end
79
88
 
80
89
  ScaleCli.start(ARGV)
data/lib/helper.rb ADDED
@@ -0,0 +1,126 @@
1
+
2
+ class SubstrateClient::Helper
3
+ class << self
4
+ def generate_storage_key_from_metadata(metadata, module_name, storage_name, params = nil)
5
+ # find the storage item from metadata
6
+ metadata_modules = metadata.value.value[:metadata][:modules]
7
+ metadata_module = metadata_modules.detect { |mm| mm[:name] == module_name }
8
+ raise "Module '#{module_name}' not exist" unless metadata_module
9
+ storage_item = metadata_module[:storage][:items].detect { |item| item[:name] == storage_name }
10
+ raise "Storage item '#{storage_name}' not exist. \n#{metadata_module.inspect}" unless storage_item
11
+
12
+ if storage_item[:type][:Plain]
13
+ return_type = storage_item[:type][:Plain]
14
+ elsif map = storage_item[:type][:Map]
15
+ raise "Storage call of type \"Map\" requires 1 parameter" if params.nil? || params.length != 1
16
+
17
+ hasher = map[:hasher]
18
+ return_type = map[:value]
19
+ # TODO: decode to account id if param is address
20
+ # params[0] = decode(params[0]) if map[:key] == "AccountId"
21
+ type = Scale::Types.get(map[:key])
22
+ params[0] = type.new(params[0]).encode
23
+ elsif map = storage_item[:type][:DoubleMap]
24
+ raise "Storage call of type \"DoubleMapType\" requires 2 parameters" if params.nil? || params.length != 2
25
+
26
+ hasher = map[:hasher]
27
+ hasher2 = map[:key2Hasher]
28
+ return_type = map[:value]
29
+ params[0] = Scale::Types.get(map[:key1]).new(params[0]).encode
30
+ params[1] = Scale::Types.get(map[:key2]).new(params[1]).encode
31
+ else
32
+ raise NotImplementedError
33
+ end
34
+
35
+ storage_prefix = metadata_module[:storage][:prefix]
36
+ storage_key = generate_storage_key(
37
+ storage_prefix.nil? ? module_name : storage_prefix,
38
+ storage_name,
39
+ params,
40
+ hasher,
41
+ hasher2,
42
+ metadata.value.value[:metadata][:version]
43
+ )
44
+ [storage_key, return_type]
45
+ end
46
+
47
+ def generate_storage_key(module_name, storage_name, params = nil, hasher = nil, hasher2 = nil, metadata_version = nil)
48
+ metadata_version = 12 if metadata_version.nil?
49
+ if metadata_version and metadata_version >= 9
50
+ storage_key = Crypto.twox128(module_name) + Crypto.twox128(storage_name)
51
+
52
+ params&.each_with_index do |param, index|
53
+ if index == 0
54
+ param_hasher = hasher
55
+ elsif index == 1
56
+ param_hasher = hasher2
57
+ else
58
+ raise "Unexpected third parameter for storage call"
59
+ end
60
+
61
+ param_key = if param.class == String && param.start_with?("0x")
62
+ param.hex_to_bytes
63
+ else
64
+ param.encode().hex_to_bytes
65
+ end
66
+ param_hasher = "Twox128" if param_hasher.nil?
67
+ storage_key += Crypto.send(param_hasher.underscore, param_key)
68
+ end
69
+
70
+ "0x#{storage_key}"
71
+ else
72
+ # TODO: add test
73
+ storage_key = module_name + " " + storage_name
74
+
75
+ unless params.nil?
76
+ params = [params] if params.class != ::Array
77
+ params_key = params.join("")
78
+ hasher = "Twox128" if hasher.nil?
79
+ storage_key += params_key.hex_to_bytes.bytes_to_utf8
80
+ end
81
+
82
+ "0x#{Crypto.send( hasher.underscore, storage_key )}"
83
+ end
84
+ end
85
+
86
+ def compose_call_from_metadata(metadata, module_name, call_name, params)
87
+ call = metadata.get_module_call(module_name, call_name)
88
+
89
+ value = {
90
+ call_index: call[:lookup],
91
+ module_name: module_name,
92
+ call_name: call_name,
93
+ params: []
94
+ }
95
+
96
+ params.keys.each_with_index do |call_param_name, i|
97
+ param_value = params[call_param_name]
98
+ value[:params] << {
99
+ name: call_param_name.to_s,
100
+ type: call[:args][i][:type],
101
+ value: param_value
102
+ }
103
+ end
104
+
105
+ Scale::Types::Extrinsic.new(value).encode
106
+ end
107
+
108
+ def decode_block(block)
109
+ block["block"]["header"]["number"] = block["block"]["header"]["number"].to_i(16)
110
+
111
+ block["block"]["extrinsics"].each_with_index do |hex, i|
112
+ scale_bytes = Scale::Bytes.new(hex)
113
+ block["block"]["extrinsics"][i] = Scale::Types::Extrinsic.decode(scale_bytes).to_human
114
+ end
115
+
116
+ block['block']['header']["digest"]["logs"].each_with_index do |hex, i|
117
+ scale_bytes = Scale::Bytes.new(hex)
118
+ log = Scale::Types::LogDigest.decode(scale_bytes).to_human
119
+ block['block']['header']["digest"]["logs"][i] = log
120
+ end
121
+
122
+ block
123
+ end
124
+
125
+ end
126
+ end
@@ -35,6 +35,16 @@ module Scale
35
35
  end
36
36
  end
37
37
  end
38
+
39
+ def get_module_storage(module_name, storage_name)
40
+ the_module = get_module(module_name)
41
+ if the_module[:storage].class == Array
42
+ storages = the_module[:storage]
43
+ else
44
+ storages = the_module[:storage][:items]
45
+ end
46
+ storages.find {|storage| storage[:name] == storage_name}
47
+ end
38
48
  end
39
49
 
40
50
  class MetadataModule
@@ -68,6 +78,10 @@ module Scale
68
78
 
69
79
  MetadataModule.new(result)
70
80
  end
81
+
82
+ def get_storage(storage_name)
83
+ self.value[:storage].find { |storage| storage[:name].downcase == storage_name.downcase }
84
+ end
71
85
  end
72
86
 
73
87
  class MetadataModuleStorage
data/lib/scale.rb CHANGED
@@ -26,13 +26,23 @@ require "metadata/metadata_v10"
26
26
  require "metadata/metadata_v11"
27
27
  require "metadata/metadata_v12"
28
28
 
29
+ require "substrate_client"
30
+ require "logger"
31
+ require "helper"
32
+ require 'kontena-websocket-client'
33
+
29
34
  module Scale
30
35
  class Error < StandardError; end
31
36
 
32
37
  class TypeRegistry
33
38
  include Singleton
34
- attr_reader :spec_name, :types, :versioning, :custom_types
35
- attr_accessor :spec_version
39
+
40
+ # init by load, and will not change
41
+ attr_reader :spec_name, :types
42
+ attr_reader :versioning, :custom_types # optional
43
+
44
+ # will change by different spec version
45
+ attr_accessor :spec_version # optional
36
46
  attr_accessor :metadata
37
47
 
38
48
  def load(spec_name: nil, custom_types: nil)
@@ -43,13 +53,18 @@ module Scale
43
53
 
44
54
  default_types, _, _ = load_chain_spec_types("default")
45
55
 
46
- if spec_name.nil? || spec_name == "default"
56
+ if spec_name
57
+ begin
58
+ @spec_name = spec_name
59
+ spec_types, @versioning, @spec_version = load_chain_spec_types(spec_name)
60
+ @types = default_types.merge(spec_types)
61
+ rescue => ex
62
+ puts "There is no types json file named #{spec_name}"
63
+ @types = default_types
64
+ end
65
+ else
47
66
  @spec_name = "default"
48
67
  @types = default_types
49
- else
50
- @spec_name = spec_name
51
- spec_types, @versioning, @spec_version = load_chain_spec_types(spec_name)
52
- @types = default_types.merge(spec_types)
53
68
  end
54
69
 
55
70
  self.custom_types = custom_types
@@ -63,7 +78,8 @@ module Scale
63
78
 
64
79
  if @spec_version && @versioning
65
80
  @versioning.each do |item|
66
- if @spec_version >= item["runtime_range"][0] && @spec_version <= (item["runtime_range"][1] || 1073741823)
81
+ if @spec_version >= item["runtime_range"][0] &&
82
+ ( item["runtime_range"][1].nil? || @spec_version <= item["runtime_range"][1] )
67
83
  all_types.merge!(item["types"])
68
84
  end
69
85
  end
@@ -342,7 +358,7 @@ def rename(type)
342
358
  return "AccountData" if type == "AccountData<Balance>"
343
359
 
344
360
  if type =~ /\[U\d+; \d+\]/
345
- byte_length = type.scan(/\[U\d+; (\d+)\]/).first.first
361
+ byte_length = type.scan(/\[U\d+; (\d+)\]/).first.first.to_i
346
362
  return "VecU8Length#{byte_length}"
347
363
  end
348
364
 
data/lib/scale/base.rb CHANGED
@@ -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
@@ -175,18 +161,18 @@ module Scale
175
161
  end
176
162
  end
177
163
 
178
- # log
179
- class Other < Bytes; end
180
-
181
164
  class AuthoritiesChange
182
165
  include Vec
183
166
  inner_type "AccountId"
184
167
  end
185
168
 
186
- class ConsensusEngineId < VecU8Length4; end
169
+ class GenericConsensusEngineId < VecU8Length4; end
187
170
 
188
171
  class ChangesTrieRoot < Bytes; end
189
172
 
173
+ # log
174
+ class Other < Bytes; end
175
+
190
176
  class SealV0
191
177
  include Struct
192
178
  items(
data/lib/scale/types.rb CHANGED
@@ -570,34 +570,52 @@ module Scale
570
570
 
571
571
  class VecU8Length2
572
572
  include VecU8FixedLength
573
+ BYTE_LENGTH = 2
573
574
  end
574
575
 
575
576
  class VecU8Length3
576
577
  include VecU8FixedLength
578
+ BYTE_LENGTH = 3
577
579
  end
578
580
 
579
581
  class VecU8Length4
580
582
  include VecU8FixedLength
583
+ BYTE_LENGTH = 4
581
584
  end
582
585
 
583
586
  class VecU8Length8
584
587
  include VecU8FixedLength
588
+ BYTE_LENGTH = 8
585
589
  end
586
590
 
587
591
  class VecU8Length16
588
592
  include VecU8FixedLength
593
+ BYTE_LENGTH = 16
589
594
  end
590
595
 
591
596
  class VecU8Length20
592
597
  include VecU8FixedLength
598
+ BYTE_LENGTH = 20
593
599
  end
594
600
 
595
601
  class VecU8Length32
596
602
  include VecU8FixedLength
603
+ BYTE_LENGTH = 32
597
604
  end
598
605
 
599
606
  class VecU8Length64
600
607
  include VecU8FixedLength
608
+ BYTE_LENGTH = 64
609
+ end
610
+
611
+ class VecU8Length128
612
+ include VecU8FixedLength
613
+ BYTE_LENGTH = 128
614
+ end
615
+
616
+ class VecU8Length256
617
+ include VecU8FixedLength
618
+ BYTE_LENGTH = 256
601
619
  end
602
620
 
603
621
  class BalanceLock