scale_rb 0.5.0 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,8 +10,9 @@ module ScaleRb
10
10
  Primitive = Types::Strict::Symbol.enum(
11
11
  :I8, :U8, :I16, :U16, :I32, :U32, :I64, :U64, :I128, :U128, :I256, :U256, :Bool, :Str, :Char
12
12
  )
13
- Ti = Types::Strict::Integer.constrained(gteq: 0)
14
- U8 = Types::Strict::Integer.constrained(gteq: 0, lt: 256)
13
+ Ti = Types::Strict::Integer | Types::Strict::String
14
+ # U8 = Types::Strict::Integer.constrained(gteq: 0, lt: 256)
15
+ U8 = Types::Strict::Integer
15
16
  U8Array = Types::Strict::Array.of(U8)
16
17
  Hex = Types::Strict::String.constrained(format: /\A0x[0-9a-fA-F]+\z/)
17
18
 
@@ -23,9 +24,15 @@ module ScaleRb
23
24
  UnsignedInteger = Types::Strict::Integer.constrained(gteq: 0)
24
25
  TypedArray = ->(type) { Types::Array.of(type) }
25
26
 
27
+ class Param < Dry::Struct
28
+ attribute :name, Types::Strict::String
29
+ attribute? :type, Ti
30
+ end
31
+
26
32
  class Base < Dry::Struct
27
33
  attribute? :registry, Registry
28
34
  attribute? :path, Types::Strict::Array.of(Types::Strict::String)
35
+ attribute? :params, Types::Strict::Array.of(Param)
29
36
 
30
37
  def t(type_id)
31
38
  raise 'No registry' unless registry
@@ -1,3 +1,3 @@
1
1
  module ScaleRb
2
- VERSION = '0.5.0'
2
+ VERSION = '0.5.2'
3
3
  end
data/lib/scale_rb.rb CHANGED
@@ -21,16 +21,18 @@ require 'type_enforcer'
21
21
 
22
22
  require 'scale_rb/types'
23
23
  require 'scale_rb/portable_registry'
24
+ require 'scale_rb/old_registry'
24
25
  require 'scale_rb/codec'
25
26
 
26
27
  require 'scale_rb/metadata/metadata'
27
28
 
28
29
  require 'scale_rb/hasher'
29
30
  require 'scale_rb/storage_helper'
30
- require 'scale_rb/call_helper'
31
+ require 'scale_rb/extrinsic_helper'
31
32
 
32
33
  require 'address'
33
34
 
34
35
  # clients
36
+ require 'scale_rb/client/client_share'
35
37
  require 'scale_rb/client/http_client'
36
38
  require 'scale_rb/client/ws_client'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scale_rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aki Wu
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-10-13 00:00:00.000000000 Z
11
+ date: 2024-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base58
@@ -160,6 +160,7 @@ files:
160
160
  - bin/setup
161
161
  - examples/http_client_1.rb
162
162
  - examples/http_client_2.rb
163
+ - examples/http_client_3.rb
163
164
  - examples/ws_client_1.rb
164
165
  - examples/ws_client_2.rb
165
166
  - examples/ws_client_3.rb
@@ -170,13 +171,14 @@ files:
170
171
  - lib/custom_assign.rb
171
172
  - lib/scale_rb.rb
172
173
  - lib/scale_rb/call_helper.rb
173
- - lib/scale_rb/client/client_ext.rb
174
+ - lib/scale_rb/client/client_share.rb
174
175
  - lib/scale_rb/client/http_client.rb
175
176
  - lib/scale_rb/client/ws_client.rb
176
177
  - lib/scale_rb/codec.rb
177
178
  - lib/scale_rb/codec_utils.rb
178
179
  - lib/scale_rb/decode.rb
179
180
  - lib/scale_rb/encode.rb
181
+ - lib/scale_rb/extrinsic_helper.rb
180
182
  - lib/scale_rb/hasher.rb
181
183
  - lib/scale_rb/metadata/metadata.rb
182
184
  - lib/scale_rb/metadata/metadata_v10.rb
@@ -185,8 +187,7 @@ files:
185
187
  - lib/scale_rb/metadata/metadata_v13.rb
186
188
  - lib/scale_rb/metadata/metadata_v14.rb
187
189
  - lib/scale_rb/metadata/metadata_v9.rb
188
- - lib/scale_rb/metadata/registry.rb
189
- - lib/scale_rb/metadata/type_exp.rb
190
+ - lib/scale_rb/old_registry.rb
190
191
  - lib/scale_rb/portable_registry.rb
191
192
  - lib/scale_rb/storage_helper.rb
192
193
  - lib/scale_rb/types.rb
@@ -216,7 +217,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
216
217
  - !ruby/object:Gem::Version
217
218
  version: '0'
218
219
  requirements: []
219
- rubygems_version: 3.5.16
220
+ rubygems_version: 3.5.21
220
221
  signing_key:
221
222
  specification_version: 4
222
223
  summary: A Ruby SCALE Codec Library, and, Substrate RPC Client
@@ -1,263 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative './type_exp'
4
- require_relative '../types'
5
-
6
- # rubocop:disable all
7
- module ScaleRb
8
- module Metadata
9
- class Registry
10
- include Types
11
-
12
- # Map name to index of type in `types` array
13
- # % lookup :: String -> Integer
14
- attr_reader :lookup
15
-
16
- # % keys :: Integer -> String
17
- attr_reader :keys
18
-
19
- # % types :: Array<PortableType>
20
- attr_reader :types
21
-
22
- attr_reader :old_types
23
-
24
- # % initialize :: Hash<Symbol, Any> -> void
25
- def initialize(old_types)
26
- @old_types = old_types
27
- @lookup = {}
28
- @keys = {}
29
- @types = []
30
-
31
- build()
32
- end
33
-
34
- def build()
35
- @old_types.keys.each do |name|
36
- use(name.to_s)
37
- end
38
- end
39
-
40
- def [](index)
41
- @types[index]
42
- end
43
-
44
- def inspect
45
- "registry(#{@types.length} types)"
46
- end
47
-
48
- def to_s
49
- @types.map.with_index do |type, index|
50
- "#{@keys[index]} => #{type.to_s}"
51
- end.join("\n")
52
- end
53
-
54
- # % use :: String -> Integer
55
- def use(old_type_exp)
56
- raise "Empty old_type_exp: #{old_type_exp}" if old_type_exp.nil? || old_type_exp.strip == ''
57
-
58
- ast_type = TypeExp.parse(old_type_exp)
59
- raise "No AST type for #{old_type_exp}" if ast_type.nil?
60
-
61
- key = ast_type.to_s
62
- ti = lookup[key]
63
- return ti if ti
64
-
65
- ti = @types.length
66
- @types[ti] = "Placeholder"
67
- @lookup[key] = ti
68
- @keys[ti] = key
69
- @types[ti] = build_portable_type(ast_type)
70
- ti
71
- end
72
-
73
- # % build_portable_type :: NamedType | ArrayType | TupleType -> PortableType
74
- # __ :build_portable_type, { ast_type: TypedArray[TypeExp::ArrayType | TypeExp::TupleType | TypeExp::NamedType] } => PortableType
75
- def build_portable_type(ast_type)
76
- case ast_type
77
- when TypeExp::ArrayType
78
- ArrayType.new(use(ast_type.item), ast_type.len, registry: self)
79
- when TypeExp::TupleType
80
- TupleType.new(ast_type.params.map { |param| use(param) })
81
- when TypeExp::NamedType
82
- build_portable_type_from_named_type(ast_type)
83
- else
84
- raise "Unknown type: #{ast_type.class}"
85
- end
86
- end
87
-
88
- # % build_portable_type_from_named_type :: NamedType -> PortableType
89
- def build_portable_type_from_named_type(named_type)
90
- name = named_type.name
91
- params = named_type.params
92
-
93
- definition = @old_types[name.to_sym]
94
- return build_from_definition(name, definition) if definition
95
-
96
- primitive = as_primitive(name)
97
- return primitive if primitive
98
-
99
- case name
100
- when 'Vec'
101
- item_index = use(params[0].to_s)
102
- SequenceType.new(type: item_index, registry: self)
103
- when 'Option'
104
- item_index = use(params[0].to_s)
105
- VariantType.option(item_index, self)
106
- when 'Result'
107
- ok_index = use(params[0].to_s)
108
- err_index = use(params[1].to_s)
109
- VariantType.result(ok_index, err_index, self)
110
- when 'Compact'
111
- # item_index = use(params[0].to_s)
112
- # CompactType.new(type: item_index, registry: self)
113
- CompactType.new
114
- when 'Null'
115
- UnitType.new
116
- else
117
- raise "Unknown type: #{name}"
118
- end
119
- end
120
-
121
- # % as_primitive :: String -> PrimitiveType | nil
122
- def as_primitive(name)
123
- case name.downcase
124
- when /^i\d+$/
125
- PrimitiveType.new(primitive: "I#{name[1..]}".to_sym)
126
- when /^u\d+$/
127
- PrimitiveType.new(primitive: "U#{name[1..]}".to_sym)
128
- when /^bool$/
129
- PrimitiveType.new(primitive: :Bool)
130
- when /^str$/, /^text$/
131
- PrimitiveType.new(primitive: :Str)
132
- else
133
- nil
134
- end
135
- end
136
-
137
- # % build_from_definition :: String -> OldTypeDefinition -> PortableType | TypeAlias
138
- #
139
- # type OldTypeDefinition = String | OldEnumDefinition | OldStructDefinition
140
- # type OldEnumDefinition = {
141
- # _enum: String[] | Hash<Symbol, Any>,
142
- # }
143
- # type OldStructDefinition = {
144
- # _struct: Hash<Symbol, Any>
145
- # }
146
- def build_from_definition(name, definition) # rubocop:disable Metrics/MethodLength
147
- case definition
148
- when String
149
- # TypeAlias.new(name, use(definition))
150
- alias_type_id = use(definition)
151
- # p "alias_type_id: #{alias_type_id}"
152
- types[alias_type_id]
153
- when Hash
154
- if definition[:_enum]
155
- _build_portable_type_from_enum_definition(definition)
156
- elsif definition[:_set]
157
- raise 'Sets are not supported'
158
- else
159
- _build_portable_type_from_struct_definition(definition)
160
- end
161
- end
162
- end
163
-
164
- private
165
-
166
- def _indexed_enum?(definition)
167
- definition[:_enum].is_a?(::Hash) && definition[:_enum].values.all? { |value| value.is_a?(::Integer) }
168
- end
169
-
170
- # % _build_portable_type_from_enum_definition :: Hash<Symbol, Any> -> VariantType
171
- def _build_portable_type_from_enum_definition(definition)
172
- variants =
173
- if definition[:_enum].is_a?(::Array)
174
- # Simple array enum:
175
- # {
176
- # _enum: ['A', 'B', 'C']
177
- # }
178
- definition[:_enum].map.with_index do |variant_name, index|
179
- SimpleVariant.new(name: variant_name.to_sym, index:)
180
- end
181
- elsif definition[:_enum].is_a?(::Hash)
182
- if _indexed_enum?(definition)
183
- # Indexed enum:
184
- # {
185
- # _enum: {
186
- # Variant1: 0,
187
- # Variant2: 1,
188
- # Variant3: 2
189
- # }
190
- # }
191
- definition[:_enum].map do |variant_name, index|
192
- SimpleVariant.new(name: variant_name, index:)
193
- end
194
- else
195
- # Mixed enum:
196
- # {
197
- # _enum: {
198
- # A: 'u32',
199
- # B: {a: 'u32', b: 'u32'},
200
- # C: null,
201
- # D: ['u32', 'u32']
202
- # }
203
- # }
204
- definition[:_enum].map.with_index do |(variant_name, variant_def), index|
205
- case variant_def
206
- when ::String
207
- TupleVariant.new(
208
- name: variant_name,
209
- index:,
210
- tuple: TupleType.new(
211
- tuple: [use(variant_def)],
212
- registry: self
213
- ),
214
- )
215
- when ::Array
216
- TupleVariant.new(
217
- name: variant_name,
218
- index:,
219
- tuple: TupleType.new(
220
- tuple: variant_def.map { |field_type| use(field_type) },
221
- registry: self
222
- )
223
- )
224
- when ::Hash
225
- StructVariant.new(
226
- name: variant_name,
227
- index:,
228
- struct: StructType.new(
229
- fields: variant_def.map do |field_name, field_type|
230
- Field.new(name: field_name.to_s, type: use(field_type))
231
- end,
232
- registry: self
233
- )
234
- )
235
- else
236
- raise "Unknown variant type for #{variant_name}: #{variant_def.class}"
237
- end
238
- end
239
- end
240
- end
241
- VariantType.new(variants:, registry: self)
242
- end
243
-
244
- # % _build_portable_type_from_struct_definition :: Hash<Symbol, Any> -> StructType
245
- def _build_portable_type_from_struct_definition(definition)
246
- fields = definition.map do |field_name, field_type|
247
- Field.new(name: field_name.to_s, type: use(field_type))
248
- end
249
- StructType.new(fields:, registry: self)
250
- end
251
- end
252
- end
253
- end
254
-
255
- # require_relative '../../metadata/metadata'
256
-
257
- # begin
258
- # registry = ScaleRb::Metadata::Registry.new ScaleRb::Metadata::TYPES
259
- # puts registry
260
- # rescue StandardError => e
261
- # puts e.message
262
- # puts e.backtrace.join("\n")
263
- # end
@@ -1,286 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ScaleRb
4
- module Metadata
5
- module TypeExp
6
- class Tokenizer
7
- attr_reader :tokens, :index
8
-
9
- # % tokenize :: String -> [String]
10
- def initialize(type_exp)
11
- @tokens = tokenize(type_exp)
12
- @index = 0
13
- end
14
-
15
- # % next_token :: -> String
16
- def next_token
17
- token = @tokens[@index]
18
- @index += 1
19
- token
20
- end
21
-
22
- # % peek_token :: -> String
23
- def peek_token
24
- @tokens[@index]
25
- end
26
-
27
- # % eof? :: -> Bool
28
- def eof?
29
- @index >= @tokens.length
30
- end
31
-
32
- private
33
-
34
- def tokenize(type_exp)
35
- tokens = []
36
- current_token = ''
37
-
38
- type_exp.each_char do |char|
39
- case char
40
- when /[a-zA-Z0-9_]/
41
- current_token += char
42
- when ':', '<', '>', '(', ')', '[', ']', ',', ';', '&', "'"
43
- tokens << current_token unless current_token.empty?
44
- if char == ':' && tokens.last == ':'
45
- tokens[-1] = '::'
46
- else
47
- tokens << char
48
- end
49
- current_token = ''
50
- when /\s/
51
- tokens << current_token unless current_token.empty?
52
- current_token = ''
53
- else
54
- raise abort
55
- end
56
- end
57
-
58
- tokens << current_token unless current_token.empty?
59
- tokens
60
- end
61
- end
62
-
63
- class NamedType
64
- attr_reader :name, :params
65
-
66
- def initialize(name, params)
67
- @name = name
68
- @params = params
69
- end
70
-
71
- def to_s
72
- params.empty? ? name : "#{name}<#{params.map(&:to_s).join(', ')}>"
73
- end
74
- end
75
-
76
- class ArrayType
77
- attr_reader :item, :len
78
-
79
- def initialize(item, len)
80
- @item = item
81
- @len = len
82
- end
83
-
84
- def to_s
85
- "[#{item}; #{len}]"
86
- end
87
- end
88
-
89
- class TupleType
90
- attr_reader :params
91
-
92
- def initialize(params)
93
- @params = params
94
- end
95
-
96
- def to_s
97
- "(#{params.map(&:to_s).join(', ')})"
98
- end
99
- end
100
-
101
- # % print :: NamedType | ArrayType | TupleType -> String
102
- def self.print(type)
103
- type.to_s
104
- end
105
-
106
- # % parse :: String -> NamedType | ArrayType | TupleType
107
- def self.parse(type_exp)
108
- TypeExpParser.new(type_exp).parse
109
- end
110
-
111
- class TypeExpParser
112
- def initialize(type_exp)
113
- @type_exp = type_exp
114
- @tokenizer = Tokenizer.new(type_exp)
115
- @current_token = @tokenizer.next_token
116
- end
117
-
118
- def parse
119
- build_type
120
- end
121
-
122
- private
123
-
124
- # Consume and return the current token, or nil if it doesn't equal the expected token.
125
- def expect(token)
126
- return unless @current_token == token
127
-
128
- current_token = @current_token
129
- @current_token = @tokenizer.next_token
130
- current_token
131
- end
132
-
133
- def expect!(token)
134
- expect(token) || raise("Expected #{token}, got #{@current_token}")
135
- end
136
-
137
- # Consume and return the current token if it matches the expected regex pattern.
138
- def expect_regex(pattern)
139
- return unless pattern.match?(@current_token)
140
-
141
- current_token = @current_token
142
- @current_token = @tokenizer.next_token
143
- current_token
144
- end
145
-
146
- def expect_regex!(pattern)
147
- expect_regex(pattern) || raise("Expected current token matching #{pattern.inspect}, got #{@current_token}")
148
- end
149
-
150
- # Consume and return a natural number (integer) if the current token matches.
151
- def expect_nat
152
- expect_regex(/^\d+$/)&.to_i
153
- end
154
-
155
- def expect_nat!
156
- expect_nat || raise("Expected natural number, got #{@current_token}")
157
- end
158
-
159
- def expect_name
160
- expect_regex(/^[a-zA-Z]\w*$/)
161
- end
162
-
163
- def expect_name!
164
- expect_name || raise("Expected name, got #{@current_token}")
165
- end
166
-
167
- def list(sep, &block)
168
- result = []
169
- item = block.call
170
- return result if item.nil?
171
-
172
- result << item
173
- while expect(sep)
174
- item = block.call
175
- break if item.nil? # (A, B,)
176
-
177
- result << item
178
- end
179
- result
180
- end
181
-
182
- def build_tuple_type
183
- return nil unless expect('(')
184
-
185
- params = list(',') { build_type }
186
- expect!(')')
187
-
188
- TupleType.new(params)
189
- end
190
-
191
- # [u8; 16; H128]
192
- # [u8; 16]
193
- def build_array_type
194
- return nil unless expect('[')
195
-
196
- item = build_type
197
- raise "Expected array item, got #{@current_token}" if item.nil?
198
-
199
- expect!(';')
200
- len = expect_nat!
201
-
202
- # [u8; 16; H128]
203
- if expect(';')
204
- expect_name! # Just consume the name
205
- end
206
-
207
- expect!(']')
208
- ArrayType.new(item, len)
209
- end
210
-
211
- def build_named_type
212
- name = nil
213
- trait = nil
214
- item = nil
215
-
216
- if expect('<')
217
- # Handle trait syntax: <T::Trait as OtherTrait>::Type
218
- # name trait item
219
- # '<T::InherentOfflineReport as InherentOfflineReport>::Inherent' -> 'InherentOfflineReport'
220
- # '<T::Balance as HasCompact>' -> 'Compact<Balance>'
221
- # '<T as Trait<I>>::Proposal' -> 'Proposal'
222
- name = build_named_type.name
223
- expect!('as')
224
- trait = build_named_type.name
225
- expect!('>')
226
- else
227
- name = expect_name
228
- return if name.nil?
229
- end
230
-
231
- # Consume the :: and get the next name
232
- item = expect_name while expect('::')
233
-
234
- # Handle special cases
235
- # From subsquid's code. But where are these coming from?
236
- if name == 'InherentOfflineReport' && name == trait && item == 'Inherent'
237
- # Do nothing
238
- elsif name == 'exec' && item == 'StorageKey'
239
- name = 'ContractStorageKey'
240
- elsif name == 'Lookup' && item == 'Source'
241
- name = 'LookupSource'
242
- elsif name == 'Lookup' && item == 'Target'
243
- name = 'LookupTarget'
244
- elsif item
245
- # '<T::Balance as HasCompact>::Item' will raise error
246
- raise "Expected item, got #{item}" if trait == 'HasCompact'
247
-
248
- name = item
249
- elsif trait == 'HasCompact' # '<T::Balance as HasCompact>'
250
- return NamedType.new('Compact', [NamedType.new(name, [])])
251
- end
252
-
253
- NamedType.new(name, type_parameters)
254
- end
255
-
256
- def type_parameters
257
- if expect('<')
258
- params = list(',') { expect_nat || build_type }
259
- expect!('>')
260
- else
261
- params = []
262
- end
263
-
264
- params
265
- end
266
-
267
- # &[u8]
268
- # &'static [u8]
269
- def build_pointer_bytes
270
- return nil unless expect('&') # &
271
-
272
- expect("'") && expect!('static')
273
- expect!('[')
274
- expect!('u8')
275
- expect!(']')
276
- NamedType.new('Vec', [NamedType.new('u8', [])])
277
- end
278
-
279
- # % build_type :: TupleType | ArrayType | NamedType
280
- def build_type
281
- build_tuple_type || build_array_type || build_named_type || build_pointer_bytes
282
- end
283
- end
284
- end
285
- end
286
- end