scale.rb 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 455155ae80fa2688bd42bf2dfdf5d0206e53ff8a645d2f8b0936bb7657fad3a9
4
- data.tar.gz: 60c09397cb38825bfd9e67cfb52a770578e7b9d6b43d6e1db6acecc9af9dac78
3
+ metadata.gz: 1557cc1ad637937b0301af472bd99efae047d222dee854b4de014a3f4f58f5e9
4
+ data.tar.gz: 9d0cf93b3cd088ffb663332ff1de2b4cef0b5895c2eedb381a90de7e8be4b270
5
5
  SHA512:
6
- metadata.gz: 2a71f2efdfbe7e376bc07c47ad35b9d1768f8b2c97c6047ae16b36ca583fbe75d23937f6e6342c624701bff2fa7f8b2a3118d9d9e5fd3db33571d9133e590713
7
- data.tar.gz: 4c165871d267f740ec0f980a3fb88b5a56c0c83d3163b0268279597eec96c7e33a454ad29f9f1f5e4e0cd9e513425aabea148df7b0eee0e3a5191c358a935a90
6
+ metadata.gz: b2cb860a69f16ae7115474edd8f178f6b712a5ce5f146f21e8e30918b6b52d83f40380a60a84d576d832856c37f1813ec031750b45bebb1c3defa2e93de99677
7
+ data.tar.gz: c896365be27dcdf74590afe05e8543a80fa22f2585040f7fcf2ac185584368c26fae3f6ecc7b36a9a190624f5c2a1268f925634e405f52b34092a2b08e418260
data/.DS_Store CHANGED
Binary file
data/.gitignore CHANGED
@@ -8,3 +8,4 @@
8
8
  /tmp/
9
9
  /.rakeTasks
10
10
  /.idea
11
+ /target
@@ -0,0 +1,44 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ [[package]]
4
+ name = "SCALE-testing-interface"
5
+ version = "0.1.0"
6
+ dependencies = [
7
+ "parity-scale-codec",
8
+ ]
9
+
10
+ [[package]]
11
+ name = "arrayvec"
12
+ version = "0.5.1"
13
+ source = "registry+https://github.com/rust-lang/crates.io-index"
14
+ checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
15
+
16
+ [[package]]
17
+ name = "bitvec"
18
+ version = "0.15.2"
19
+ source = "registry+https://github.com/rust-lang/crates.io-index"
20
+ checksum = "a993f74b4c99c1908d156b8d2e0fb6277736b0ecbd833982fd1241d39b2766a6"
21
+
22
+ [[package]]
23
+ name = "byte-slice-cast"
24
+ version = "0.3.5"
25
+ source = "registry+https://github.com/rust-lang/crates.io-index"
26
+ checksum = "b0a5e3906bcbf133e33c1d4d95afc664ad37fbdb9f6568d8043e7ea8c27d93d3"
27
+
28
+ [[package]]
29
+ name = "parity-scale-codec"
30
+ version = "1.2.0"
31
+ source = "registry+https://github.com/rust-lang/crates.io-index"
32
+ checksum = "f509c5e67ca0605ee17dcd3f91ef41cadd685c75a298fb6261b781a5acb3f910"
33
+ dependencies = [
34
+ "arrayvec",
35
+ "bitvec",
36
+ "byte-slice-cast",
37
+ "serde",
38
+ ]
39
+
40
+ [[package]]
41
+ name = "serde"
42
+ version = "1.0.104"
43
+ source = "registry+https://github.com/rust-lang/crates.io-index"
44
+ checksum = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
@@ -0,0 +1,11 @@
1
+ [package]
2
+ name = "SCALE-testing-interface"
3
+ version = "0.1.0"
4
+ authors = ["Robert Hambrock <robert@web3.foundation>"]
5
+
6
+ [dependencies]
7
+ parity-scale-codec = { version = "1.2.0" }
8
+
9
+ [lib]
10
+ name = "scale_ffi"
11
+ crate-type = ["dylib"]
data/Dockerfile CHANGED
@@ -13,6 +13,7 @@ COPY . .
13
13
  RUN gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.org/ && \
14
14
  gem install bundler:1.17.3 && \
15
15
  bundle config mirror.https://rubygems.org https://gems.ruby-china.com && \
16
- bundle install
16
+ bundle install && \
17
+ rake install:local
17
18
 
18
19
  CMD ["sh"]
data/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
- git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
3
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  # Specify your gem's dependencies in scale.gemspec
6
6
  gemspec
@@ -1,17 +1,32 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- scale.rb (0.1.0)
5
- substrate_common.rb (~> 0.1.3)
4
+ scale.rb (0.2.0)
5
+ activesupport (>= 4.0.0)
6
+ json (~> 2.3.0)
7
+ substrate_common.rb (~> 0.1.8)
8
+ thor (~> 0.20.3)
6
9
 
7
10
  GEM
8
11
  remote: https://rubygems.org/
9
12
  specs:
13
+ activesupport (6.0.2.2)
14
+ concurrent-ruby (~> 1.0, >= 1.0.2)
15
+ i18n (>= 0.7, < 2)
16
+ minitest (~> 5.1)
17
+ tzinfo (~> 1.1)
18
+ zeitwerk (~> 2.2)
10
19
  base58 (0.2.3)
11
20
  blake2b (0.10.0)
12
21
  coderay (1.1.2)
22
+ concurrent-ruby (1.1.6)
13
23
  diff-lcs (1.3)
24
+ ffi (1.12.2)
25
+ i18n (1.8.2)
26
+ concurrent-ruby (~> 1.0)
27
+ json (2.3.0)
14
28
  method_source (0.9.2)
29
+ minitest (5.14.0)
15
30
  pry (0.12.2)
16
31
  coderay (~> 1.1.0)
17
32
  method_source (~> 0.9.0)
@@ -29,17 +44,23 @@ GEM
29
44
  diff-lcs (>= 1.2.0, < 2.0)
30
45
  rspec-support (~> 3.9.0)
31
46
  rspec-support (3.9.0)
32
- substrate_common.rb (0.1.3)
47
+ substrate_common.rb (0.1.8)
33
48
  base58
34
49
  blake2b
35
50
  xxhash
51
+ thor (0.20.3)
52
+ thread_safe (0.3.6)
53
+ tzinfo (1.2.7)
54
+ thread_safe (~> 0.1)
36
55
  xxhash (0.4.0)
56
+ zeitwerk (2.3.0)
37
57
 
38
58
  PLATFORMS
39
59
  ruby
40
60
 
41
61
  DEPENDENCIES
42
62
  bundler (~> 1.17)
63
+ ffi (~> 1.12)
43
64
  pry
44
65
  rake (~> 13.0)
45
66
  rspec (~> 3.2)
@@ -0,0 +1,13 @@
1
+ ifeq ($(shell uname),Darwin)
2
+ EXT := dylib
3
+ else
4
+ EXT := so
5
+ endif
6
+
7
+ all: target/debug/libscale_ffi.$(EXT)
8
+
9
+ target/debug/libscale_ffi.$(EXT): src/lib.rs Cargo.toml
10
+ cargo build
11
+
12
+ clean:
13
+ rm -rf target
data/README.md CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  # scale.rb
4
4
 
5
- **Ruby SCALE Codec Library and Substrate Json-rpc Api Client.**
5
+ **Ruby SCALE Codec Library**
6
6
 
7
7
  SCALE is a lightweight, efficient, binary serialization and deserialization codec used by substrate. Most of the input and output data of the substrate API are encoded in SCALE data format.
8
8
 
9
- This is a SCALE codec library and substrate json-rpc api client implemented in ruby language for general use. It contains the implementation of low-level data formats, various substrate types, metadata support and json-rpc client.
9
+ This is a SCALE codec library implemented in ruby language for general use. It contains the implementation of low-level data formats, various substrate types, metadata support.
10
10
 
11
11
  This work is the prerequisite of our subsequent series of projects. We hope to familiarize and quickly access Polkadot and Substrate through ruby. We plan to develop the back end of our applications in ruby language, and then interact with nodes or synchronize data through this library.
12
12
 
@@ -53,40 +53,33 @@ p o.encode # "1501"
53
53
  ```
54
54
  Please go to `spec` dir for more examples.
55
55
 
56
- ## Types supported
57
-
58
- scale.rb now support types:
59
-
60
- - [x] Compact
61
- - [x] Bool
62
- - [x] U8, U16, U32, U64, U128
63
- - [x] Enum
64
- - [x] Option
65
- - [x] Struct
66
- - [x] Tuple
67
- - [x] Vec
68
- - [x] Set
69
- - [x] Bytes
70
- - [x] Hex
71
- - [x] String
72
- - [x] H160, H256, H512
73
- - [x] AccountId
74
- - [x] Balance
75
- - [x] BalanceOf
76
- - [x] BlockNumber
77
- - [x] AccountIndex
78
- - [x] Era
56
+ ## Command line tools
57
+
58
+ After install scale.rb gem, there is a command named `scale` available. You can use it directly in your terminal.
59
+
60
+ ```bash
61
+ > scale
62
+ Commands:
63
+ scale decode TYPE_NAME HEX SPEC_NAME SPEC_VERSION # decode HEX string using TYPE_NAME
64
+ scale help [COMMAND] # Describe available commands or one specific command
65
+ scale specs # list all chain specs
66
+ scale type TYPE_NAME SPEC_NAME SPEC_VERSION # show type's ruby class
67
+ scale types SPEC_NAME SPEC_VERSION # list all types implemented for chain
68
+ ```
69
+
70
+ examples in `exec/scale`
79
71
 
80
72
  ## Running tests
81
73
 
82
74
  1. Download or clone the code to local, and enter the code root directory
83
- 2. Run all tests
75
+ 2. If rust is installed on your system (for instance, `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh`), call `make` to build the FFI library
76
+ 3. Run all tests
84
77
 
85
78
  ```
86
79
  rspec
87
80
  ```
88
81
 
89
- 2. Run low level format tests
82
+ To run only low level format tests, call
90
83
 
91
84
  ```
92
85
  rspec spec/low_level_spec.rb
@@ -119,7 +112,7 @@ rspec spec/low_level_spec.rb
119
112
  19 examples, 0 failures
120
113
  ```
121
114
 
122
- 4. Or type `./bin/console` to enter the ruby interactive environment and run any decode or encode code
115
+ 4. Or, type `./bin/console` to enter the ruby interactive environment and run any decode or encode code
123
116
 
124
117
  ```shell
125
118
  /usr/src/app # ./bin/console
@@ -133,6 +126,17 @@ rspec spec/low_level_spec.rb
133
126
  [4] pry(main)>
134
127
  ```
135
128
 
129
+ 5. Or, run command line tool:
130
+
131
+ ```shell
132
+ /usr/src/app # scale types kusama
133
+ HeadData => Scale::Types::HeadData
134
+ Conviction => Scale::Types::Conviction
135
+ EraRewards => Scale::Types::EraRewards
136
+ ...
137
+
138
+ Count: 303
139
+ ```
136
140
 
137
141
  ## Development
138
142
 
data/Rakefile CHANGED
@@ -1,2 +1,2 @@
1
- require "bundler/gem_tasks"
2
- task :default => :spec
1
+ require 'bundler/gem_tasks'
2
+ task default: :spec
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "bundler/setup"
4
- require "scale"
3
+ require 'bundler/setup'
4
+ require 'scale'
5
5
 
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.
8
8
 
9
9
  # (If you use this, don't forget to add pry to your Gemfile!)
10
- require "pry"
10
+ require 'pry'
11
11
  Pry.start
12
12
 
13
13
  # require "irb"
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'scale'
4
+ require 'thor'
5
+
6
+ class ScaleCli < Thor
7
+ desc "specs", "list all chain specs"
8
+ def specs
9
+ path = File.join File.expand_path('../..', __FILE__), "lib", "type_registry", "*.json"
10
+ specs = Dir[path].map do |file|
11
+ File.basename file, ".json"
12
+ end
13
+ puts specs.join(", ")
14
+ end
15
+
16
+ # exmaples:
17
+ #
18
+ # scale types darwinia
19
+ # =>
20
+ # ProposalCategory => Scale::Types::ProposalCategory
21
+ # VoteStage => Scale::Types::VoteStage
22
+ # TallyType => Scale::Types::TallyType
23
+ # ...
24
+ #
25
+ # Count: 279
26
+ desc "types SPEC_NAME SPEC_VERSION", "list all types implemented for chain"
27
+ def types(spec_name = "default", spec_version = nil)
28
+ Scale::TypeRegistry.instance.load(spec_name, spec_version)
29
+ Scale::Types.list.each_pair do |type_name, type|
30
+ puts "#{green(type_name)} => #{yellow(type.to_s)}"
31
+ end
32
+
33
+ puts "\nCount: #{Scale::Types.list.length}"
34
+ end
35
+
36
+ # exmaples:
37
+ #
38
+ # scale type Compact
39
+ # => Scale::Types::Compact
40
+ #
41
+ # scale type SessionKeysPolkadot kusama
42
+ # => nil
43
+ #
44
+ # scale type SessionKeysPolkadot kusama 1054
45
+ # => Scale::Types::Struct_Of_AccountId_AccountId_AccountId_AccountId_AccountId_70247479160460
46
+ #
47
+ # scale type "UnappliedSlash<AccountId, BalanceOf>"
48
+ # => Scale::Types::Struct_Of_AccountId_AccountId_Vec˂UnappliedSlashOther˃_Vec˂AccountId˃_Balance_70145184872260
49
+ #
50
+ desc "type TYPE_NAME SPEC_NAME SPEC_VERSION", "show type's ruby class"
51
+ def type(type_name, spec_name = "default", spec_version = nil)
52
+ Scale::TypeRegistry.instance.load(spec_name, spec_version)
53
+ p Scale::Types.get(type_name)
54
+ end
55
+
56
+ # exmaples:
57
+ #
58
+ # scale decode Compact 0x0300000040
59
+ # => #<Scale::Types::Compact:0x00007fc86b9d1198 @value=1073741824>
60
+ desc "decode TYPE_NAME HEX SPEC_NAME SPEC_VERSION", "decode HEX string using TYPE_NAME"
61
+ def decode(type_name, hex, spec_name = "default", spec_version = nil)
62
+ Scale::TypeRegistry.instance.load(spec_name, spec_version)
63
+ type = Scale::Types.get(type_name)
64
+ scale_bytes = Scale::Bytes.new(hex)
65
+ p type.decode(scale_bytes)
66
+ end
67
+
68
+ # exmaples:
69
+ #
70
+ # scale encode SessionIndex 2818
71
+ # => #<Scale::Types::Compact:0x00007fc86b9d1198 @value=1073741824>
72
+ desc "encode TYPE_NAME VALUE SPEC_NAME SPEC_VERSION", "encode value"
73
+ def encode(type_name, value, spec_name = "default", spec_version = nil)
74
+ Scale::TypeRegistry.instance.load(spec_name, spec_version)
75
+ type = Scale::Types.get(type_name)
76
+ p "0x" + type.new(value.to_i).encode
77
+ end
78
+ end
79
+
80
+ ScaleCli.start(ARGV)
@@ -1,27 +1,34 @@
1
1
  module Scale
2
2
  module Types
3
-
4
3
  class Metadata
5
4
  include SingleValue
5
+ attr_accessor :version
6
6
  def self.decode(scale_bytes)
7
7
  bytes = scale_bytes.get_next_bytes(4)
8
8
  if bytes.bytes_to_utf8 == 'meta'
9
- metadata_v_name = type_of("Enum", enum_values: [
10
- "Scale::Types::MetadataV0",
11
- "Scale::Types::MetadataV1",
12
- "Scale::Types::MetadataV2",
13
- "Scale::Types::MetadataV3",
14
- "Scale::Types::MetadataV4",
15
- "Scale::Types::MetadataV5",
16
- "Scale::Types::MetadataV6",
17
- "Scale::Types::MetadataV7",
18
- "Scale::Types::MetadataV8",
19
- "Scale::Types::MetadataV9",
20
- "Scale::Types::MetadataV10"
21
- ]).decode(scale_bytes).value
22
-
23
- Metadata.new(metadata_v_name.constantize.decode(scale_bytes).value)
9
+ metadata_version = Scale::Types.type_of('Enum', [
10
+ 'MetadataV0',
11
+ 'MetadataV1',
12
+ 'MetadataV2',
13
+ 'MetadataV3',
14
+ 'MetadataV4',
15
+ 'MetadataV5',
16
+ 'MetadataV6',
17
+ 'MetadataV7',
18
+ 'MetadataV8',
19
+ 'MetadataV9',
20
+ 'MetadataV10',
21
+ 'MetadataV11'
22
+ ]).decode(scale_bytes).value
23
+ metadata = Metadata.new "Scale::Types::#{metadata_version}".constantize.decode(scale_bytes)
24
+ metadata.version = metadata_version[9..].to_i
25
+ else
26
+ scale_bytes.reset_offset
27
+ metadata_v0 = Scale::Types::MetadataV0.decode(scale_bytes)
28
+ metadata = Metadata.new metadata_v0
29
+ metadata.version = 0
24
30
  end
31
+ metadata
25
32
  end
26
33
  end
27
34
 
@@ -38,19 +45,19 @@ module Scale
38
45
 
39
46
  has_storage = Bool.decode(scale_bytes).value
40
47
  if has_storage
41
- storages = type_of("Vec<MetadataModuleStorage>").decode(scale_bytes).value
48
+ storages = Scale::Types.type_of('Vec<MetadataModuleStorage>').decode(scale_bytes).value
42
49
  result[:storage] = storages.map(&:value)
43
50
  end
44
51
 
45
52
  has_calls = Bool.decode(scale_bytes).value
46
53
  if has_calls
47
- calls = type_of("Vec<MetadataModuleCall>").decode(scale_bytes).value
54
+ calls = Scale::Types.type_of('Vec<MetadataModuleCall>').decode(scale_bytes).value
48
55
  result[:calls] = calls.map(&:value)
49
56
  end
50
57
 
51
58
  has_events = Bool.decode(scale_bytes).value
52
59
  if has_events
53
- events = type_of("Vec<MetadataModuleEvent>").decode(scale_bytes).value
60
+ events = Scale::Types.type_of('Vec<MetadataModuleEvent>').decode(scale_bytes).value
54
61
  result[:events] = events.map(&:value)
55
62
  end
56
63
 
@@ -61,29 +68,28 @@ module Scale
61
68
  class MetadataModuleStorage
62
69
  include SingleValue
63
70
  def self.decode(scale_bytes)
64
-
65
71
  result = {
66
72
  name: String.decode(scale_bytes).value,
67
- modifier: type_of("Enum", enum_values: ["Optional", "Default"]).decode(scale_bytes).value
73
+ modifier: Scale::Types.type_of('Enum', %w[Optional Default]).decode(scale_bytes).value
68
74
  }
69
75
 
70
76
  is_key_value = Bool.decode(scale_bytes).value
71
- if is_key_value
72
- result[:type] = {
73
- Map: {
74
- key: adjust(String.decode(scale_bytes).value),
75
- value: adjust(String.decode(scale_bytes).value),
76
- linked: Bool.decode(scale_bytes).value
77
- }
78
- }
79
- else
80
- result[:type] = {
81
- Plain: adjust(String.decode(scale_bytes).value)
82
- }
83
- end
77
+ result[:type] = if is_key_value
78
+ {
79
+ Map: {
80
+ key: adjust(String.decode(scale_bytes).value),
81
+ value: adjust(String.decode(scale_bytes).value),
82
+ linked: Bool.decode(scale_bytes).value
83
+ }
84
+ }
85
+ else
86
+ {
87
+ Plain: adjust(String.decode(scale_bytes).value)
88
+ }
89
+ end
84
90
 
85
91
  result[:fallback] = Hex.decode(scale_bytes).value
86
- result[:documentation] = type_of("Vec<String>").decode(scale_bytes).value.map(&:value)
92
+ result[:documentation] = Scale::Types.type_of('Vec<String>').decode(scale_bytes).value.map(&:value)
87
93
 
88
94
  MetadataModuleStorage.new(result)
89
95
  end
@@ -94,8 +100,8 @@ module Scale
94
100
  def self.decode(scale_bytes)
95
101
  result = {}
96
102
  result[:name] = String.decode(scale_bytes).value
97
- result[:args] = type_of("Vec<MetadataModuleCallArgument>").decode(scale_bytes).value.map(&:value)
98
- result[:documentation] = type_of("Vec<String>").decode(scale_bytes).value.map(&:value)
103
+ result[:args] = Scale::Types.type_of('Vec<MetadataModuleCallArgument>').decode(scale_bytes).value.map(&:value)
104
+ result[:documentation] = Scale::Types.type_of('Vec<String>').decode(scale_bytes).value.map(&:value)
99
105
  MetadataModuleCall.new(result)
100
106
  end
101
107
  end
@@ -116,12 +122,11 @@ module Scale
116
122
  def self.decode(scale_bytes)
117
123
  result = {}
118
124
  result[:name] = String.decode(scale_bytes).value
119
- result[:args] = type_of("Vec<String>").decode(scale_bytes).value.map(&:value)
120
- result[:documentation] = type_of("Vec<String>").decode(scale_bytes).value.map(&:value)
125
+ result[:args] = Scale::Types.type_of('Vec<String>').decode(scale_bytes).value.map(&:value)
126
+ result[:documentation] = Scale::Types.type_of('Vec<String>').decode(scale_bytes).value.map(&:value)
121
127
 
122
128
  MetadataModuleEvent.new(result)
123
129
  end
124
130
  end
125
-
126
131
  end
127
132
  end