scale.rb 0.2.14 → 0.2.15

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