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