scale_rb 0.4.1 → 0.5.0

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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/devcontainer.json +21 -0
  3. data/Dockerfile +16 -0
  4. data/Gemfile +4 -4
  5. data/README.md +19 -6
  6. data/bin/console +0 -0
  7. data/bin/setup +0 -0
  8. data/examples/http_client_1.rb +0 -2
  9. data/examples/http_client_2.rb +0 -2
  10. data/examples/ws_client_1.rb +0 -2
  11. data/examples/ws_client_3.rb +1 -3
  12. data/examples/ws_client_4.rb +0 -2
  13. data/exe/metadata +9 -11
  14. data/lib/address.rb +1 -1
  15. data/lib/custom_assign.rb +92 -0
  16. data/lib/scale_rb/call_helper.rb +42 -0
  17. data/lib/{client → scale_rb/client}/client_ext.rb +12 -13
  18. data/lib/{client → scale_rb/client}/http_client.rb +3 -5
  19. data/lib/{client → scale_rb/client}/ws_client.rb +13 -20
  20. data/lib/scale_rb/codec.rb +25 -0
  21. data/lib/scale_rb/codec_utils.rb +128 -0
  22. data/lib/scale_rb/decode.rb +164 -0
  23. data/lib/scale_rb/encode.rb +150 -0
  24. data/lib/{hasher.rb → scale_rb/hasher.rb} +10 -8
  25. data/lib/scale_rb/metadata/metadata.rb +114 -0
  26. data/lib/{metadata → scale_rb/metadata}/metadata_v10.rb +0 -17
  27. data/lib/{metadata → scale_rb/metadata}/metadata_v11.rb +0 -17
  28. data/lib/{metadata → scale_rb/metadata}/metadata_v12.rb +0 -17
  29. data/lib/{metadata → scale_rb/metadata}/metadata_v13.rb +0 -17
  30. data/lib/{metadata → scale_rb/metadata}/metadata_v14.rb +18 -18
  31. data/lib/{metadata → scale_rb/metadata}/metadata_v9.rb +0 -17
  32. data/lib/scale_rb/metadata/registry.rb +263 -0
  33. data/lib/scale_rb/metadata/type_exp.rb +286 -0
  34. data/lib/scale_rb/portable_registry.rb +133 -0
  35. data/lib/{storage_helper.rb → scale_rb/storage_helper.rb} +16 -4
  36. data/lib/scale_rb/types.rb +233 -0
  37. data/lib/scale_rb/utils.rb +125 -0
  38. data/lib/scale_rb/version.rb +1 -1
  39. data/lib/scale_rb.rb +22 -30
  40. data/lib/type_enforcer.rb +170 -0
  41. data/scale_rb.gemspec +5 -0
  42. metadata +71 -19
  43. data/lib/codec.rb +0 -450
  44. data/lib/metadata/metadata.rb +0 -137
  45. data/lib/monkey_patching.rb +0 -115
  46. data/lib/portable_codec.rb +0 -285
  47. data/lib/registry.rb +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 15825760ac8babb0cfa263f8cdaf72c8cdad02cc24c5c7816d1ff6febf6db8de
4
- data.tar.gz: a93953348decaf1fb7f220a9e0929e84e7ba4ee3ae7c53562c2064cea6a4d892
3
+ metadata.gz: cb19be98106d9f8331a9be9812f6252c23d6913cbd98cedcae34bf1a464e7b90
4
+ data.tar.gz: cff1e034d85f130ed7d149628647f020adb9ffc532d9646bceda054007d6bf14
5
5
  SHA512:
6
- metadata.gz: 6abb7a322f18aa546886081a03775824b02a988389572ab58c4ecbf58fa130c1391fb46d5ef8355e61752d0add3690085758f9b7a2e27ab4080ba57630eb5406
7
- data.tar.gz: '0377164249cb083560b6f8b5eb70f510413b4c620d7a51675da23d23cb4038c33e8e54040135b4a70ff9faeba0b1afba001408172e46cbc19f72c636e3a6a256'
6
+ metadata.gz: de658214901aa13071c6b8d0c1aa94c8db0b2cee3c6c1df3207eb0881399c12215ce6c05a7d89c7da115e279a60fbe4688710e5f3fba827d5bd729afb7275e59
7
+ data.tar.gz: 999f5311c1a66933281798c40bbb3b7956e528b3164c264f2a7694fa48c142683e49ff47a185c1e174501b2e8c3b083d2bd513d1e6c37cffff9002d9186908e4
@@ -0,0 +1,21 @@
1
+ // For format details, see https://aka.ms/devcontainer.json. For config options, see the
2
+ // README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-dockerfile
3
+ {
4
+ "name": "scale_rb",
5
+ "build": {
6
+ // Sets the run context to one level up instead of the .devcontainer folder.
7
+ "context": "..",
8
+ // Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename.
9
+ "dockerfile": "../Dockerfile"
10
+ }
11
+ // Features to add to the dev container. More info: https://containers.dev/features.
12
+ // "features": {},
13
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
14
+ // "forwardPorts": [],
15
+ // Uncomment the next line to run commands after the container is created.
16
+ // "postCreateCommand": "cat /etc/os-release",
17
+ // Configure tool-specific properties.
18
+ // "customizations": {},
19
+ // Uncomment to connect as an existing user other than the container default. More info: https://aka.ms/dev-containers-non-root.
20
+ // "remoteUser": "devcontainer"
21
+ }
data/Dockerfile ADDED
@@ -0,0 +1,16 @@
1
+ FROM ruby:3.1
2
+
3
+ # Dependencies
4
+ RUN apt-get update -qq && apt-get install -y build-essential
5
+ RUN curl https://sh.rustup.rs -sSf | bash -s -- -y
6
+ ENV PATH="/root/.cargo/bin:${PATH}"
7
+
8
+ # Set the working directory
9
+ WORKDIR /scale_rb
10
+ COPY . /scale_rb
11
+
12
+ # Intall gems
13
+ RUN bundle install
14
+
15
+ # default command is to run a shell
16
+ CMD ["bash"]
data/Gemfile CHANGED
@@ -1,8 +1,8 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in scale_rb.gemspec
4
4
  gemspec
5
5
 
6
- gem "rake", "~> 12.0"
7
- gem "rspec", "~> 3.0"
8
- gem 'rubocop', group: 'development', require: false
6
+ gem 'rake', '~> 12.0'
7
+ gem 'rspec', '~> 3.0'
8
+ gem 'rubocop', group: 'development', require: false
data/README.md CHANGED
@@ -1,13 +1,11 @@
1
1
  # ScaleRb
2
2
 
3
- It is still under heavy development. Use the latest version.
4
-
5
3
  ## Installation
6
4
 
7
5
  Add this line to your application's Gemfile:
8
6
 
9
7
  ```ruby
10
- gem 'scale_rb', '~> 0.4.0'
8
+ gem "scale_rb"
11
9
  ```
12
10
 
13
11
  And then execute:
@@ -29,15 +27,30 @@ bundle exec ruby examples/http_client_1.rb
29
27
 
30
28
  ## Development
31
29
 
32
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+ ### Run devcontainer
31
+
32
+ Open the project in vscode, then in the command palette, type `Reopen in Container` to open the project in a devcontainer.
33
+
34
+ ![image](https://github.com/user-attachments/assets/39af785c-5570-46df-9e6e-bf816e7f7b68)
35
+
33
36
 
34
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
37
+ After the devcontainer is opened, you can run the following commands:
38
+
39
+ 1. Tests:
40
+
41
+ ```bash
42
+ bundle exec rspec
43
+ ```
44
+
45
+ 2. Examples:
46
+ ```bash
47
+ bundle exec ruby examples/http_client_1.rb
48
+ ```
35
49
 
36
50
  ## Contributing
37
51
 
38
52
  Bug reports and pull requests are welcome on GitHub at https://github.com/wuminzhe/scale_rb. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/wuminzhe/scale_rb/blob/master/CODE_OF_CONDUCT.md).
39
53
 
40
-
41
54
  ## License
42
55
 
43
56
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/bin/console CHANGED
File without changes
data/bin/setup CHANGED
File without changes
@@ -1,8 +1,6 @@
1
1
 
2
2
  require 'scale_rb'
3
3
 
4
- ScaleRb.logger.level = Logger::DEBUG
5
-
6
4
  client = ScaleRb::HttpClient.new('https://polkadot-rpc.dwellir.com')
7
5
  block_hash = client.chain_getBlockHash(21585684)
8
6
  runtime_version = client.state_getRuntimeVersion(block_hash)
@@ -14,7 +14,5 @@ def fetch_some_storages(client, block_number)
14
14
  puts "Time taken: #{end_time - start_time} seconds"
15
15
  end
16
16
 
17
- ScaleRb.logger.level = Logger::DEBUG
18
-
19
17
  client = ScaleRb::HttpClient.new('https://polkadot-rpc.dwellir.com')
20
18
  fetch_some_storages(client, 21711742)
@@ -1,7 +1,5 @@
1
1
  require 'scale_rb'
2
2
 
3
- ScaleRb.logger.level = Logger::DEBUG
4
-
5
3
  ScaleRb::WsClient.start('wss://polkadot-rpc.dwellir.com') do |client|
6
4
  block_hash = client.chain_getBlockHash(21585684)
7
5
  runtime_version = client.state_getRuntimeVersion(block_hash)
@@ -1,7 +1,5 @@
1
1
  require 'scale_rb'
2
2
 
3
- # ScaleRb.logger.level = Logger::DEBUG
4
-
5
3
  # Unsubscribe after receiving 4 new heads
6
4
  ScaleRb::WsClient.start('wss://polkadot-rpc.dwellir.com') do |client|
7
5
  count = 0
@@ -15,7 +13,7 @@ ScaleRb::WsClient.start('wss://polkadot-rpc.dwellir.com') do |client|
15
13
  puts "Received new head at height: #{block_number}, block hash: #{block_hash}"
16
14
  else
17
15
  unsub_result = client.chain_unsubscribeNewHead(subscription_id)
18
- puts "Unsubscribe result: #{unsub_result}"
16
+ puts "Unsubscribe #{subscription_id} #{unsub_result === true ? 'succeeded' : 'failed'}"
19
17
  end
20
18
  end
21
19
 
@@ -14,8 +14,6 @@ def fetch_some_storages(client, block_number)
14
14
  puts "Time taken: #{end_time - start_time} seconds"
15
15
  end
16
16
 
17
- ScaleRb.logger.level = Logger::DEBUG
18
-
19
17
  ScaleRb::WsClient.start('wss://polkadot-rpc.dwellir.com') do |client|
20
18
  fetch_some_storages(client, 21711742)
21
19
  end
data/exe/metadata CHANGED
@@ -5,13 +5,9 @@ require 'scale_rb'
5
5
  require 'json'
6
6
  require 'optparse'
7
7
 
8
- def print_metadata(url, at = nil)
9
- puts JSON.pretty_generate(ScaleRb::HttpClient.get_metadata(url, at))
10
- end
11
-
12
- # ./bin/metadata http://g2.dev.darwinia.network:2234 -b 0x23ebddd6519aaf1b7fc916c3709af13d7a4010943fb53038406581171000a58e
13
- # ./bin/metadata https://rpc.darwinia.network -b 10511703
14
- # ./bin/metadata https://pangoro-rpc.darwinia.network
8
+ # ./exe/metadata https://polkadot-rpc.dwellir.com -b 0xfc2d86c5a2cc92b7770dcc14e74116912c9f848000b5f4ceca6fe1475588692c
9
+ # ./exe/metadata https://polkadot-rpc.dwellir.com -b 22931689
10
+ # ./exe/metadata https://polkadot-rpc.dwellir.com
15
11
  @options = {}
16
12
  parser = OptionParser.new do |opts|
17
13
  opts.banner = 'Usage: metadata [url] [options]'
@@ -26,16 +22,18 @@ else
26
22
  parser.parse!
27
23
  url = ARGV[0]
28
24
 
25
+ client = ScaleRb::HttpClient.new(url)
26
+
27
+ block_hash = nil
29
28
  if @options[:block]
30
29
  if @options[:block].length == 66
31
30
  block_hash = @options[:block]
32
31
  else
33
32
  block_number = @options[:block].to_i
34
- block_hash = ScaleRb::HttpClient.chain_getBlockHash url, block_number
33
+ block_hash = client.chain_getBlockHash(block_number)
35
34
  end
36
- else
37
- block_hash = ScaleRb::HttpClient.chain_getBlockHash url
38
35
  end
39
36
 
40
- print_metadata url, block_hash
37
+ metadata = client.get_metadata(block_hash)
38
+ puts JSON.pretty_generate(metadata)
41
39
  end
data/lib/address.rb CHANGED
@@ -79,7 +79,7 @@ module ScaleRb
79
79
  end
80
80
 
81
81
  input_bytes = ss58_format_bytes.bytes + pubkey_bytes
82
- checksum = Blake2b.hex(SS58_PREFIX.bytes + input_bytes, 64)._to_bytes
82
+ checksum = Utils.hex_to_u8a(Blake2b.hex(SS58_PREFIX.bytes + input_bytes, 64))
83
83
 
84
84
  Base58.binary_to_base58((input_bytes + checksum[0...checksum_length]).pack('C*'), :bitcoin)
85
85
  end
@@ -0,0 +1,92 @@
1
+ def custom_assign(positional_params, keyword_params, args, kwargs = {}, defaults = {})
2
+ assigned = {}
3
+
4
+ # Handle positional arguments (with optional defaults)
5
+ raise ArgumentError, 'Too many positional arguments' if args.length > positional_params.length
6
+
7
+ positional_params.each_with_index do |param, index|
8
+ if args[index]
9
+ assigned[param] = args[index] # Assign from args if available
10
+ elsif args.length == positional_params.length
11
+ assigned[param] = nil
12
+ elsif defaults.key?(param)
13
+ assigned[param] = defaults[param] # Assign default if no argument is provided
14
+ else
15
+ raise ArgumentError, "Missing required positional argument: #{param}"
16
+ end
17
+ end
18
+
19
+ # Handle keyword arguments (with optional defaults)
20
+ kwargs.each_key do |key|
21
+ raise ArgumentError, "Unknown keyword argument: #{key}" unless keyword_params.include?(key)
22
+ end
23
+
24
+ keyword_params.each do |key|
25
+ if kwargs.key?(key)
26
+ assigned[key] = kwargs[key] # Assign from kwargs if available
27
+ elsif defaults.key?(key)
28
+ assigned[key] = defaults[key] # Assign default if not provided
29
+ else
30
+ raise ArgumentError, "Missing required keyword argument: #{key}"
31
+ end
32
+ end
33
+
34
+ # assert_equal(positional_params.length + keyword_params.length, assigned.length)
35
+ assigned
36
+ end
37
+
38
+ def get_method_params(method)
39
+ params = method.parameters
40
+
41
+ positional_params = []
42
+ keyword_params = []
43
+
44
+ params.each do |type, name|
45
+ case type
46
+ when :req, :opt # Required, optional positional arguments
47
+ positional_params << name
48
+ when :key, :keyreq # Keyword arguments
49
+ keyword_params << name
50
+ end
51
+ end
52
+
53
+ [positional_params, keyword_params]
54
+ end
55
+
56
+ def assert_equal(expected, actual)
57
+ raise "Expected #{expected}, but got #{actual}" unless expected === actual
58
+ end
59
+
60
+ def build_assigned_params(method, defaults, args, kwargs)
61
+ positional_params, keyword_params = get_method_params(method)
62
+ custom_assign(positional_params, keyword_params, args, kwargs, defaults)
63
+ end
64
+
65
+ # def my_method(a, b = 2, c:, d: 4); end
66
+
67
+ # defaults = { b: 2, d: 4 }
68
+
69
+ # # my_method(5, c: 3)
70
+ # p build_assigned_params(:my_method, defaults, 5, c: 3)
71
+ # # => {:a=>5, :b=>2, :c=>3, :d=>4}
72
+
73
+ # # my_method(5, 6, c: 3)
74
+ # p build_assigned_params(:my_method, defaults, 5, 6, c: 3)
75
+ # # => {:a=>5, :b=>6, :c=>3, :d=>4}
76
+
77
+ # # my_method(5, 6, c: 3, d: 10)
78
+ # p build_assigned_params(:my_method, defaults, 5, 6, c: 3, d: 10)
79
+ # # => {:a=>5, :b=>6, :c=>3, :d=>10}
80
+
81
+ # # my_method(5, 6, c: 3, d: 10, e: 11)
82
+ # begin
83
+ # build_assigned_params(:my_method, defaults, 5, 6, c: 3, d: 10, e: 11)
84
+ # rescue ArgumentError => e
85
+ # puts e.message # => "Unknown keyword argument: e"
86
+ # end
87
+
88
+ # begin
89
+ # build_assigned_params(:my_method, defaults, 5, 6, 7, c: 3, d: 10)
90
+ # rescue ArgumentError => e
91
+ # puts e.message # => "Too many positional arguments"
92
+ # end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ScaleRb
4
+ module CallHelper
5
+ # callbytes's structure is: pallet_index + call_index + argsbytes
6
+ #
7
+ # callbytes examples:
8
+ # "0x0901"._to_bytes
9
+ # "0x05000a1287977578f888bdc1c7627781af1cc000e6ab1300004c31b8d9a798"._to_bytes
10
+ def self.decode_call(callbytes, metadata)
11
+ pallet_index = callbytes[0]
12
+ pallet = Metadata.get_module_by_index(pallet_index, metadata)
13
+
14
+ # Remove the pallet_index
15
+ # The callbytes we used below should not contain the pallet index.
16
+ # This is because the pallet index is not part of the call type.
17
+ # Its structure is: call_index + call_args
18
+ callbytes_without_pallet_index = callbytes[1..]
19
+ calls_type_id = pallet._get(:calls, :type)
20
+ decoded = Codec.decode(
21
+ calls_type_id,
22
+ callbytes_without_pallet_index,
23
+ Metadata.build_registry(metadata)
24
+ )&.first
25
+
26
+ {
27
+ pallet_name: pallet._get(:name),
28
+ call_name: decoded.is_a?(::Hash) ? decoded.keys.first.to_s : decoded.to_s,
29
+ call: decoded
30
+ }
31
+ end
32
+
33
+ # call examples:
34
+ # {:pallet_name=>"Deposit", :call_name=>"claim", :call=>:claim]}
35
+ # {:pallet_name=>"Balances", :call_name=>"transfer", :call=>{:transfer=>{:dest=>[10, 18, 135, 151, 117, 120, 248, 136, 189, 193, 199, 98, 119, 129, 175, 28, 192, 0, 230, 171], :value=>11000000000000000000}}]}
36
+ def self.encode_call(call, metadata)
37
+ calls_type_id = Metadata.get_calls_type_id(call[:pallet_name], metadata)
38
+ pallet_index = Metadata.get_module(call[:pallet_name], metadata)._get(:index)
39
+ [pallet_index] + Codec.encode(calls_type_id, call[:call], Metadata.build_registry(metadata))
40
+ end
41
+ end
42
+ end
@@ -1,12 +1,11 @@
1
1
  module ScaleRb
2
-
3
2
  # This module is used to add extra methods to both the ScaleRb::WsClient ScaleRb::HttpClient
4
3
  module ClientExt
5
4
  # get decoded metadata at block_hash
6
5
  def get_metadata(block_hash = nil)
7
6
  block_hash ||= chain_getHead
8
7
  metadata_hex = state_getMetadata(block_hash)
9
- ScaleRb::Metadata.decode_metadata(metadata_hex.strip._to_bytes)
8
+ Metadata.decode_metadata(metadata_hex)
10
9
  end
11
10
 
12
11
  # Get decoded storage at block_hash
@@ -39,8 +38,8 @@ module ScaleRb
39
38
  item[:changes].map do |change|
40
39
  storage_key = change[0]
41
40
  data = change[1] || default
42
- storage = data.nil? ? nil : PortableCodec.decode(type_id, data._to_bytes, registry)[0]
43
- { storage_key: storage_key, storage: storage }
41
+ storage = data.nil? ? nil : Codec.decode(type_id, Utils.hex_to_u8a(data), registry)[0]
42
+ { storage_key:, storage: }
44
43
  end
45
44
  end.flatten
46
45
  end
@@ -83,7 +82,7 @@ module ScaleRb
83
82
  # 'System',
84
83
  # 'Account',
85
84
  # key = {
86
- # value: [['0x724d50824542b56f422588421643c4a162b90b5416ef063f2266a1eae6651641'._to_bytes]], # [AccountId]
85
+ # value: [[Utils.hex_to_u8a('0x724d50824542b56f422588421643c4a162b90b5416ef063f2266a1eae6651641')]], # [AccountId]
87
86
  # type: 0,
88
87
  # hashers: ['Blake2128Concat']
89
88
  # },
@@ -101,7 +100,7 @@ module ScaleRb
101
100
  if key
102
101
  if key[:value].nil? || key[:value].empty?
103
102
  # map, but no key's value provided. get all storages under the partial storage key
104
- partial_storage_key = StorageHelper.encode_storage_key(pallet_name, item_name)._to_hex
103
+ partial_storage_key = Utils.u8a_to_hex(StorageHelper.encode_storage_key(pallet_name, item_name))
105
104
  get_storages_by_partial_key(
106
105
  block_hash,
107
106
  partial_storage_key,
@@ -111,7 +110,8 @@ module ScaleRb
111
110
  )
112
111
  elsif key[:value].length != key[:hashers].length
113
112
  # map with multi parts, but not have all values
114
- partial_storage_key = StorageHelper.encode_storage_key(pallet_name, item_name, key, registry)._to_hex
113
+ partial_storage_key = Utils.u8a_to_hex(StorageHelper.encode_storage_key(pallet_name, item_name, key,
114
+ registry))
115
115
  get_storages_by_partial_key(
116
116
  block_hash,
117
117
  partial_storage_key,
@@ -120,12 +120,12 @@ module ScaleRb
120
120
  registry
121
121
  )
122
122
  else
123
- storage_key = StorageHelper.encode_storage_key(pallet_name, item_name, key, registry)._to_hex
123
+ storage_key = Utils.u8a_to_hex(StorageHelper.encode_storage_key(pallet_name, item_name, key, registry))
124
124
  data = state_getStorage(storage_key, block_hash)
125
125
  StorageHelper.decode_storage(data, value[:type], value[:modifier] == 'Optional', value[:fallback], registry)
126
126
  end
127
127
  else
128
- storage_key = StorageHelper.encode_storage_key(pallet_name, item_name)._to_hex
128
+ storage_key = Utils.u8a_to_hex(StorageHelper.encode_storage_key(pallet_name, item_name))
129
129
  data = state_getStorage(storage_key, block_hash)
130
130
  StorageHelper.decode_storage(data, value[:type], value[:modifier] == 'Optional', value[:fallback], registry)
131
131
  end
@@ -152,12 +152,12 @@ module ScaleRb
152
152
  if plain
153
153
  [
154
154
  nil,
155
- { type: plain, modifier: modifier, fallback: fallback }
155
+ { type: plain, modifier:, fallback: }
156
156
  ]
157
157
  elsif map
158
158
  [
159
159
  { value: params, type: map._get(:key), hashers: map._get(:hashers) },
160
- { type: map._get(:value), modifier: modifier, fallback: fallback }
160
+ { type: map._get(:value), modifier:, fallback: }
161
161
  ]
162
162
  else
163
163
  raise 'NoSuchStorageType'
@@ -175,11 +175,10 @@ module ScaleRb
175
175
  if key.is_a?(Integer)
176
176
  key.to_i
177
177
  elsif key.is_a?(String) && key.start_with?('0x')
178
- key._to_bytes
178
+ Utils.hex_to_u8a(key)
179
179
  else
180
180
  key
181
181
  end
182
182
  end
183
-
184
183
  end
185
184
  end
@@ -30,8 +30,8 @@ module ScaleRb
30
30
  http.use_ssl = @uri.scheme == 'https'
31
31
 
32
32
  request = Net::HTTP::Post.new(@uri, 'Content-Type' => 'application/json')
33
- request.body = { jsonrpc: '2.0', method: method, params: params, id: Time.now.to_i }.to_json
34
- ScaleRb.logger.debug "Request: #{request.body}"
33
+ request.body = { jsonrpc: '2.0', method:, params:, id: Time.now.to_i }.to_json
34
+ ScaleRb.logger.debug "—→ #{request.body}"
35
35
 
36
36
  # https://docs.ruby-lang.org/en/master/Net/HTTPResponse.html
37
37
  response = http.request(request)
@@ -39,7 +39,7 @@ module ScaleRb
39
39
 
40
40
  # parse response, make key symbol
41
41
  body = JSON.parse(response.body, symbolize_names: true)
42
- ScaleRb.logger.debug "Response: #{body}"
42
+ ScaleRb.logger.debug "←— #{body}"
43
43
  raise body[:error] if body[:error]
44
44
 
45
45
  body[:result]
@@ -50,8 +50,6 @@ module ScaleRb
50
50
  end
51
51
 
52
52
  def method_missing(method, *args)
53
- # ScaleRb.logger.debug "#{method}(#{args.join(', ')})"
54
-
55
53
  request(method.to_s, args)
56
54
  end
57
55
  end
@@ -6,7 +6,6 @@ require_relative 'client_ext'
6
6
 
7
7
  module ScaleRb
8
8
  class WsClient
9
-
10
9
  class << self
11
10
  # @param [string] url
12
11
  def start(url)
@@ -22,14 +21,14 @@ module ScaleRb
22
21
  data = parse_message(message)
23
22
  next if data.nil?
24
23
 
25
- ScaleRb.logger.debug "Response: #{data}"
24
+ ScaleRb.logger.debug "←— #{data}"
26
25
  Async do
27
26
  client.handle_response(data)
28
27
  end
29
28
  end
30
29
  end
31
30
 
32
- client.supported_methods = client.rpc_methods()[:methods]
31
+ client.supported_methods = client.rpc_methods[:methods]
33
32
  yield client
34
33
 
35
34
  recv_task.wait
@@ -37,7 +36,6 @@ module ScaleRb
37
36
  recv_task&.stop
38
37
  end
39
38
  end
40
-
41
39
  end
42
40
 
43
41
  private
@@ -45,11 +43,10 @@ module ScaleRb
45
43
  def parse_message(message)
46
44
  message.parse
47
45
  rescue StandardError => e
48
- ScaleRb.logger.error "Error while parsing message: #{e.inspect}, message: #{message}"
46
+ Console::Event::Failure.for(e).emit(self, 'Parse message failed!')
49
47
  nil
50
48
  end
51
49
  end
52
-
53
50
  end
54
51
  end
55
52
 
@@ -71,7 +68,6 @@ module ScaleRb
71
68
 
72
69
  def method_missing(method, *args)
73
70
  method = method.to_s
74
- # ScaleRb.logger.debug "#{method}(#{args.join(', ')})"
75
71
 
76
72
  # why not check 'rpc_methods', because there is no @supported_methods when initializing
77
73
  if method != 'rpc_methods' && !@supported_methods.include?(method)
@@ -103,9 +99,9 @@ module ScaleRb
103
99
  def unsubscribe(method, subscription_id)
104
100
  return unless method.include?('unsubscribe')
105
101
 
106
- if @subscription_handler.unsubscribe(subscription_id)
107
- request(method, [subscription_id])
108
- end
102
+ return unless @subscription_handler.unsubscribe(subscription_id)
103
+
104
+ request(method, [subscription_id])
109
105
  end
110
106
 
111
107
  def handle_response(response)
@@ -117,16 +113,14 @@ module ScaleRb
117
113
  ScaleRb.logger.info "Received an unknown response: #{response}"
118
114
  end
119
115
  rescue StandardError => e
120
- ScaleRb.logger.error "Error while handling response: #{e.inspect}"
121
- ScaleRb.logger.debug e.backtrace.join("\n")
116
+ Console::Event::Failure.for(e).emit(self, 'Handle response failed!')
122
117
  end
123
118
 
124
119
  def read_message
125
120
  loop do
126
121
  return @connection.read
127
122
  rescue StandardError => e
128
- ScaleRb.logger.error "Error while read message from connection: #{e.inspect}"
129
- ScaleRb.logger.debug e.backtrace.join("\n")
123
+ Console::Event::Failure.for(e).emit(self, 'Read message from connection failed!')
130
124
  sleep 1
131
125
  retry
132
126
  end
@@ -141,8 +135,8 @@ module ScaleRb
141
135
  response_future.resolve(response[:result])
142
136
  })
143
137
 
144
- request = { jsonrpc: '2.0', id: @request_id, method: method, params: params }
145
- ScaleRb.logger.debug "Request: #{request}"
138
+ request = { jsonrpc: '2.0', id: @request_id, method:, params: }
139
+ ScaleRb.logger.debug "—→ #{request}"
146
140
  @connection.write(request.to_json)
147
141
 
148
142
  @request_id += 1
@@ -189,10 +183,9 @@ module ScaleRb
189
183
  subscription_id = notification.dig(:params, :subscription)
190
184
  return if subscription_id.nil?
191
185
 
192
- if @callbacks.key?(subscription_id)
193
- @callbacks[subscription_id].call(notification)
194
- end
186
+ return unless @callbacks.key?(subscription_id)
187
+
188
+ @callbacks[subscription_id].call(notification)
195
189
  end
196
190
  end
197
-
198
191
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'decode'
4
+ require_relative 'encode'
5
+
6
+ module ScaleRb
7
+ module Codec
8
+ class Error < StandardError; end
9
+ class TypeNotFound < Error; end
10
+ class TypeNotImplemented < Error; end
11
+ class CompositeInvalidValue < Error; end
12
+ class ArrayLengthNotEqual < Error; end
13
+ class VariantItemNotFound < Error; end
14
+ class VariantIndexOutOfRange < Error; end
15
+ class VariantInvalidValue < Error; end
16
+ class VariantFieldsLengthNotMatch < Error; end
17
+ class LengthNotEqualErr < Error; end
18
+ class NotEnoughBytesError < Error; end
19
+ class Unreachable < Error; end
20
+ class InvalidBytesError < Error; end
21
+
22
+ extend Decode
23
+ extend Encode
24
+ end
25
+ end