scale.rb 0.2.9 → 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.9)
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.7)
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.0)
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
@@ -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
@@ -9,6 +9,7 @@ require "singleton"
9
9
  require "scale/base"
10
10
  require "scale/types"
11
11
  require "scale/block"
12
+ require "scale/trie"
12
13
 
13
14
  require "metadata/metadata"
14
15
  require "metadata/metadata_v0"
@@ -25,13 +26,23 @@ require "metadata/metadata_v10"
25
26
  require "metadata/metadata_v11"
26
27
  require "metadata/metadata_v12"
27
28
 
29
+ require "substrate_client"
30
+ require "logger"
31
+ require "helper"
32
+ require 'kontena-websocket-client'
33
+
28
34
  module Scale
29
35
  class Error < StandardError; end
30
36
 
31
37
  class TypeRegistry
32
38
  include Singleton
33
- attr_reader :spec_name, :types, :versioning, :custom_types
34
- 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
35
46
  attr_accessor :metadata
36
47
 
37
48
  def load(spec_name: nil, custom_types: nil)
@@ -42,13 +53,18 @@ module Scale
42
53
 
43
54
  default_types, _, _ = load_chain_spec_types("default")
44
55
 
45
- 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
46
66
  @spec_name = "default"
47
67
  @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
68
  end
53
69
 
54
70
  self.custom_types = custom_types
@@ -62,7 +78,8 @@ module Scale
62
78
 
63
79
  if @spec_version && @versioning
64
80
  @versioning.each do |item|
65
- 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] )
66
83
  all_types.merge!(item["types"])
67
84
  end
68
85
  end
@@ -92,14 +109,11 @@ module Scale
92
109
  end
93
110
 
94
111
  def type_traverse(type, types)
112
+ type = rename(type) if type.class == ::String
95
113
  if types.has_key?(type) && types[type] != type
96
114
  type_traverse(types[type], types)
97
115
  else
98
- if type.class == ::String
99
- rename(type)
100
- else
101
- type
102
- end
116
+ type
103
117
  end
104
118
  end
105
119
  end
@@ -344,7 +358,7 @@ def rename(type)
344
358
  return "AccountData" if type == "AccountData<Balance>"
345
359
 
346
360
  if type =~ /\[U\d+; \d+\]/
347
- byte_length = type.scan(/\[U\d+; (\d+)\]/).first.first
361
+ byte_length = type.scan(/\[U\d+; (\d+)\]/).first.first.to_i
348
362
  return "VecU8Length#{byte_length}"
349
363
  end
350
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(