scale.rb 0.2.14 → 0.2.19
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Cargo.lock +2007 -11
- data/Cargo.toml +9 -2
- data/Dockerfile +4 -1
- data/Gemfile.lock +45 -46
- data/README.md +28 -1
- data/exe/scale +39 -70
- data/lib/address.rb +3 -0
- data/lib/common.rb +163 -0
- data/lib/helper.rb +128 -0
- data/lib/metadata/metadata.rb +15 -1
- data/lib/scale.rb +105 -33
- data/lib/scale/base.rb +52 -13
- data/lib/scale/block.rb +17 -27
- data/lib/scale/types.rb +71 -4
- data/lib/scale/version.rb +1 -1
- data/lib/substrate_client.rb +170 -0
- data/lib/type_registry/{crab-28.json → crab.json} +474 -126
- data/lib/type_registry/darwinia.json +701 -136
- data/lib/type_registry/default.json +2 -2
- data/lib/type_registry/pangolin.json +332 -0
- data/scale.gemspec +7 -5
- data/scripts/block_events.rb +2 -3
- data/src/lib.rs +42 -1
- data/src/storage_key.rs +41 -0
- metadata +52 -26
- data/.DS_Store +0 -0
- data/lib/type_registry/darwinia-8.json +0 -662
- data/lib/type_registry/edgeware.json +0 -124
- data/lib/type_registry/joystream.json +0 -49
- data/lib/type_registry/kulupu.json +0 -15
- data/lib/type_registry/plasm.json +0 -89
- data/lib/type_registry/robonomics.json +0 -39
- data/lib/type_registry/westend.json +0 -63
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.
|
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/Dockerfile
CHANGED
@@ -15,7 +15,10 @@ RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && \
|
|
15
15
|
export RUSTFLAGS='-C target-feature=-crt-static' && \
|
16
16
|
make
|
17
17
|
|
18
|
-
|
18
|
+
ENV RUSTFLAGS='-C target-feature=-crt-static'
|
19
|
+
ENV PATH=/root/.cargo/bin:$PATH
|
20
|
+
|
21
|
+
RUN gem install bundler:2.2.13 && \
|
19
22
|
bundle install && \
|
20
23
|
rake install:local
|
21
24
|
|
data/Gemfile.lock
CHANGED
@@ -1,70 +1,69 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
scale.rb (0.2.
|
5
|
-
|
4
|
+
scale.rb (0.2.19)
|
5
|
+
base58
|
6
|
+
blake2b_rs (~> 0.1.2)
|
7
|
+
faye-websocket
|
6
8
|
json (~> 2.3.0)
|
7
|
-
|
8
|
-
|
9
|
+
thor (~> 1.0)
|
10
|
+
xxhash
|
9
11
|
|
10
12
|
GEM
|
11
13
|
remote: https://rubygems.org/
|
12
14
|
specs:
|
13
|
-
activesupport (6.0.3.4)
|
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, >= 2.2.2)
|
19
15
|
base58 (0.2.3)
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
16
|
+
blake2b_rs (0.1.2)
|
17
|
+
ffi (= 1.15.0)
|
18
|
+
thermite (~> 0)
|
19
|
+
coderay (1.1.3)
|
20
|
+
diff-lcs (1.4.4)
|
21
|
+
eventmachine (1.2.7)
|
22
|
+
faye-websocket (0.11.0)
|
23
|
+
eventmachine (>= 0.12.0)
|
24
|
+
websocket-driver (>= 0.5.1)
|
25
|
+
ffi (1.15.0)
|
27
26
|
json (2.3.1)
|
28
|
-
method_source (0.
|
29
|
-
|
30
|
-
pry (0.
|
31
|
-
coderay (~> 1.1
|
32
|
-
method_source (~>
|
33
|
-
rake (13.0.
|
34
|
-
rspec (3.
|
35
|
-
rspec-core (~> 3.
|
36
|
-
rspec-expectations (~> 3.
|
37
|
-
rspec-mocks (~> 3.
|
38
|
-
rspec-core (3.
|
39
|
-
rspec-support (~> 3.
|
40
|
-
rspec-expectations (3.
|
27
|
+
method_source (1.0.0)
|
28
|
+
minitar (0.9)
|
29
|
+
pry (0.14.0)
|
30
|
+
coderay (~> 1.1)
|
31
|
+
method_source (~> 1.0)
|
32
|
+
rake (13.0.3)
|
33
|
+
rspec (3.10.0)
|
34
|
+
rspec-core (~> 3.10.0)
|
35
|
+
rspec-expectations (~> 3.10.0)
|
36
|
+
rspec-mocks (~> 3.10.0)
|
37
|
+
rspec-core (3.10.1)
|
38
|
+
rspec-support (~> 3.10.0)
|
39
|
+
rspec-expectations (3.10.1)
|
41
40
|
diff-lcs (>= 1.2.0, < 2.0)
|
42
|
-
rspec-support (~> 3.
|
43
|
-
rspec-mocks (3.
|
41
|
+
rspec-support (~> 3.10.0)
|
42
|
+
rspec-mocks (3.10.2)
|
44
43
|
diff-lcs (>= 1.2.0, < 2.0)
|
45
|
-
rspec-support (~> 3.
|
46
|
-
rspec-support (3.
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
thor (
|
52
|
-
|
53
|
-
|
54
|
-
|
44
|
+
rspec-support (~> 3.10.0)
|
45
|
+
rspec-support (3.10.2)
|
46
|
+
thermite (0.13.0)
|
47
|
+
minitar (~> 0.5)
|
48
|
+
rake (>= 10)
|
49
|
+
tomlrb (~> 1.2)
|
50
|
+
thor (1.1.0)
|
51
|
+
tomlrb (1.3.0)
|
52
|
+
websocket-driver (0.7.3)
|
53
|
+
websocket-extensions (>= 0.1.0)
|
54
|
+
websocket-extensions (0.1.5)
|
55
55
|
xxhash (0.4.0)
|
56
|
-
zeitwerk (2.4.1)
|
57
56
|
|
58
57
|
PLATFORMS
|
59
58
|
ruby
|
60
59
|
|
61
60
|
DEPENDENCIES
|
62
|
-
bundler
|
63
|
-
ffi (~> 1.
|
61
|
+
bundler
|
62
|
+
ffi (~> 1.15.0)
|
64
63
|
pry
|
65
64
|
rake (~> 13.0)
|
66
65
|
rspec (~> 3.2)
|
67
66
|
scale.rb!
|
68
67
|
|
69
68
|
BUNDLED WITH
|
70
|
-
|
69
|
+
2.2.13
|
data/README.md
CHANGED
@@ -19,7 +19,7 @@ Because the feature of ruby 2.6 is used, the ruby version is required to be >= 2
|
|
19
19
|
Add this line to your application's Gemfile:
|
20
20
|
|
21
21
|
```ruby
|
22
|
-
gem 'scale.rb'
|
22
|
+
gem 'scale.rb', '0.2.19'
|
23
23
|
```
|
24
24
|
|
25
25
|
And then execute:
|
@@ -37,10 +37,22 @@ Or install it yourself as:
|
|
37
37
|
```ruby
|
38
38
|
require "scale"
|
39
39
|
|
40
|
+
Scale::TypeRegistry.instance.load # default
|
41
|
+
# Scale::TypeRegistry.instance.load spec_name: "pangolin"
|
42
|
+
# Scale::TypeRegistry.instance.load spec_name: "kusama"
|
43
|
+
|
44
|
+
# print hex changes if you set debug to true, default is false
|
45
|
+
Scale::Types.debug = true
|
46
|
+
|
40
47
|
# decode a compact integer
|
41
48
|
scale_bytes = Scale::Bytes.new("0x1501") # create scale_bytes object from scale encoded hex string
|
42
49
|
o = Scale::Types::Compact.decode(scale_bytes) # use scale type to decode scale_bytes object
|
43
50
|
p o.value # 69
|
51
|
+
|
52
|
+
#
|
53
|
+
type = Scale::Types::get("Vec<U8>")
|
54
|
+
o = type.decode(Scale::Bytes.new("0x080001"))
|
55
|
+
assert_eq o.value, [Scale::Types::U8.new(0), Scale::Types::U8.new(1)]
|
44
56
|
```
|
45
57
|
|
46
58
|
2. encode
|
@@ -48,8 +60,23 @@ p o.value # 69
|
|
48
60
|
```ruby
|
49
61
|
require "scale"
|
50
62
|
|
63
|
+
Scale::TypeRegistry.instance.load
|
64
|
+
|
51
65
|
o = Scale::Types::Compact.new(69)
|
52
66
|
p o.encode # "1501"
|
67
|
+
|
68
|
+
type = Scale::Types::get("Vec<U8>")
|
69
|
+
o = type.new([Scale::Types::U8.new(0), Scale::Types::U8.new(1)])
|
70
|
+
p o.encode # "080001"
|
71
|
+
```
|
72
|
+
|
73
|
+
3. client
|
74
|
+
```ruby
|
75
|
+
require "scale"
|
76
|
+
|
77
|
+
client = SubstrateClient.new "wss://pangolin-rpc.darwinia.network"
|
78
|
+
client.get_storage("EthereumRelay", "ConfirmedHeaderParcels", [0])
|
79
|
+
|
53
80
|
```
|
54
81
|
Please go to `spec` dir for more examples.
|
55
82
|
|
data/exe/scale
CHANGED
@@ -1,79 +1,48 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "thor"
|
4
|
+
require "scale"
|
5
5
|
|
6
6
|
class ScaleCli < Thor
|
7
|
-
desc "
|
8
|
-
def
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
desc "list-types WS_ENDPOINT ", "list all types in metadata"
|
8
|
+
def list_types(ws)
|
9
|
+
client = SubstrateClient.new ws
|
10
|
+
metadata = client.get_metadata.value.to_human.to_json
|
11
|
+
metadata = JSON.parse(metadata)
|
12
|
+
|
13
|
+
types = []
|
14
|
+
metadata["metadata"]["modules"].each do |m|
|
15
|
+
if m["storage"]
|
16
|
+
m["storage"]["items"].each do |storage|
|
17
|
+
type = storage["type"]
|
18
|
+
if type["Plain"]
|
19
|
+
types << type["Plain"].gsub("\n ", "").gsub("\n", "")
|
20
|
+
elsif type["Map"]
|
21
|
+
types << type["Map"]["key"].gsub("\n", "")
|
22
|
+
types << type["Map"]["value"].gsub("\n", "")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
if m["calls"]
|
28
|
+
m["calls"].each do |call|
|
29
|
+
call["args"].each do |arg|
|
30
|
+
types << arg["type"].gsub("\n", "")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
if m["events"]
|
36
|
+
m["events"].each do |event|
|
37
|
+
event["args"].each do |arg|
|
38
|
+
types << arg.gsub("\n", "")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
12
42
|
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
43
|
|
68
|
-
|
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
|
44
|
+
types.uniq!
|
45
|
+
puts types
|
77
46
|
end
|
78
47
|
end
|
79
48
|
|
data/lib/address.rb
ADDED
data/lib/common.rb
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
require 'xxhash'
|
2
|
+
require 'blake2b'
|
3
|
+
require 'base58'
|
4
|
+
|
5
|
+
class Array
|
6
|
+
def bytes_to_hex
|
7
|
+
raise "Not a byte array" unless self.is_byte_array?
|
8
|
+
'0x' + self.map { |b| b.to_s(16).rjust(2, '0') }.join
|
9
|
+
end
|
10
|
+
|
11
|
+
def bytes_to_bin
|
12
|
+
raise "Not a byte array" unless self.is_byte_array?
|
13
|
+
'0b' + self.map { |b| b.to_s(2).rjust(8, '0') }.join
|
14
|
+
end
|
15
|
+
|
16
|
+
def bytes_to_bin
|
17
|
+
raise "Not a byte array" unless self.is_byte_array?
|
18
|
+
self.map { |b| b.to_s(2).rjust(8, '0') }
|
19
|
+
end
|
20
|
+
|
21
|
+
def bytes_to_utf8
|
22
|
+
raise "Not a byte array" unless self.is_byte_array?
|
23
|
+
self.pack('C*').force_encoding('utf-8')
|
24
|
+
end
|
25
|
+
|
26
|
+
def is_byte_array?
|
27
|
+
self.all? {|e| e >= 0 and e <= 255 }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class String
|
32
|
+
def constantize2
|
33
|
+
Object.const_get(self)
|
34
|
+
end
|
35
|
+
|
36
|
+
def hex_to_bytes
|
37
|
+
data = self.start_with?('0x') ? self[2..] : self
|
38
|
+
raise "Not valid hex string" if data.length % 2 != 0
|
39
|
+
data.scan(/../).map(&:hex)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module Crypto
|
44
|
+
def self.identity(bytes)
|
45
|
+
bytes.bytes_to_hex[2..]
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.twox64(data)
|
49
|
+
result = XXhash.xxh64 data, 0
|
50
|
+
bytes = result.to_s(16).rjust(16, '0').hex_to_bytes.reverse
|
51
|
+
bytes.bytes_to_hex[2..]
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.twox128(data)
|
55
|
+
bytes = []
|
56
|
+
2.times do |i|
|
57
|
+
result = XXhash.xxh64 data, i
|
58
|
+
bytes = bytes + result.to_s(16).rjust(16, '0').hex_to_bytes.reverse
|
59
|
+
end
|
60
|
+
bytes.bytes_to_hex[2..]
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.twox64_concat(bytes)
|
64
|
+
data = bytes.bytes_to_utf8
|
65
|
+
twox64(data) + bytes.bytes_to_hex[2..]
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.blake2_128(bytes)
|
69
|
+
Blake2b.hex bytes, 16
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.blake2_256(bytes)
|
73
|
+
Blake2b.hex bytes, 32
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.blake2_128_concat(bytes)
|
77
|
+
blake2_128(bytes) + bytes.bytes_to_hex[2..]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class Address
|
82
|
+
SS58_PREFIX = 'SS58PRE'
|
83
|
+
|
84
|
+
TYPES = [
|
85
|
+
# Polkadot Live (SS58, AccountId)
|
86
|
+
0, 1,
|
87
|
+
# Polkadot Canary (SS58, AccountId)
|
88
|
+
2, 3,
|
89
|
+
# Kulupu (SS58, Reserved)
|
90
|
+
16, 17,
|
91
|
+
# Darwinia Live
|
92
|
+
18,
|
93
|
+
# Dothereum (SS58, AccountId)
|
94
|
+
20, 21,
|
95
|
+
# Generic Substrate wildcard (SS58, AccountId)
|
96
|
+
42, 43,
|
97
|
+
|
98
|
+
# Schnorr/Ristretto 25519 ("S/R 25519") key
|
99
|
+
48,
|
100
|
+
# Edwards Ed25519 key
|
101
|
+
49,
|
102
|
+
# ECDSA SECP256k1 key
|
103
|
+
50,
|
104
|
+
|
105
|
+
# Reserved for future address format extensions.
|
106
|
+
*64..255
|
107
|
+
]
|
108
|
+
|
109
|
+
class << self
|
110
|
+
|
111
|
+
def array_to_hex_string(arr)
|
112
|
+
body = arr.map { |i| i.to_s(16).rjust(2, '0') }.join
|
113
|
+
"0x#{body}"
|
114
|
+
end
|
115
|
+
|
116
|
+
def decode(address, addr_type = 42, ignore_checksum = true)
|
117
|
+
decoded = Base58.base58_to_binary(address, :bitcoin)
|
118
|
+
is_pubkey = decoded.size == 35
|
119
|
+
|
120
|
+
size = decoded.size - ( is_pubkey ? 2 : 1 )
|
121
|
+
|
122
|
+
prefix = decoded[0, 1].unpack("C*").first
|
123
|
+
|
124
|
+
raise "Invalid address type" unless TYPES.include?(addr_type)
|
125
|
+
|
126
|
+
hash_bytes = make_hash(decoded[0, size])
|
127
|
+
if is_pubkey
|
128
|
+
is_valid_checksum = decoded[-2].unpack("C*").first == hash_bytes[0] && decoded[-1].unpack("C*").first == hash_bytes[1]
|
129
|
+
else
|
130
|
+
is_valid_checksum = decoded[-1].unpack("C*").first == hash_bytes[0]
|
131
|
+
end
|
132
|
+
|
133
|
+
raise "Invalid decoded address checksum" unless is_valid_checksum && ignore_checksum
|
134
|
+
|
135
|
+
decoded[1...size].unpack("H*").first
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
def encode(pubkey, addr_type = 42)
|
140
|
+
pubkey = pubkey[2..-1] if pubkey =~ /^0x/i
|
141
|
+
key = [pubkey].pack("H*")
|
142
|
+
|
143
|
+
u8_array = key.bytes
|
144
|
+
|
145
|
+
u8_array.unshift(addr_type)
|
146
|
+
|
147
|
+
bytes = make_hash(u8_array.pack("C*"))
|
148
|
+
|
149
|
+
checksum = bytes[0, key.size == 32 ? 2 : 1]
|
150
|
+
|
151
|
+
u8_array.push(*checksum)
|
152
|
+
|
153
|
+
input = u8_array.pack("C*")
|
154
|
+
|
155
|
+
Base58.binary_to_base58(input, :bitcoin)
|
156
|
+
end
|
157
|
+
|
158
|
+
def make_hash(body)
|
159
|
+
Blake2b.bytes("#{SS58_PREFIX}#{body}", Blake2b::Key.none, 64)
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
end
|