scale.rb 0.2.16 → 0.3.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Cargo.lock +8 -4
- data/Cargo.toml +2 -3
- data/Dockerfile +4 -1
- data/Gemfile.lock +43 -35
- data/README.md +44 -1
- data/Rakefile +6 -0
- data/exe/scale +39 -79
- data/lib/address.rb +3 -0
- data/lib/common.rb +163 -0
- data/lib/helper.rb +25 -8
- data/lib/metadata/metadata.rb +28 -18
- data/lib/metadata/metadata_v0.rb +24 -20
- data/lib/metadata/metadata_v1.rb +13 -9
- data/lib/metadata/metadata_v10.rb +2 -2
- data/lib/metadata/metadata_v11.rb +2 -2
- data/lib/metadata/metadata_v12.rb +9 -8
- data/lib/metadata/metadata_v13.rb +161 -0
- data/lib/metadata/metadata_v2.rb +2 -2
- data/lib/metadata/metadata_v3.rb +2 -2
- data/lib/metadata/metadata_v4.rb +21 -11
- data/lib/metadata/metadata_v5.rb +21 -11
- data/lib/metadata/metadata_v6.rb +9 -9
- data/lib/metadata/metadata_v7.rb +26 -15
- data/lib/metadata/metadata_v8.rb +9 -9
- data/lib/metadata/metadata_v9.rb +2 -2
- data/lib/scale.rb +41 -341
- data/lib/scale/base.rb +177 -95
- data/lib/scale/block.rb +17 -13
- data/lib/scale/trie.rb +1 -1
- data/lib/scale/types.rb +139 -40
- data/lib/scale/version.rb +1 -1
- data/lib/scale_bytes.rb +63 -0
- data/lib/substrate_client.rb +31 -17
- data/lib/type_builder.rb +279 -0
- data/lib/type_registry.rb +91 -0
- data/lib/type_registry/crab.json +676 -595
- data/lib/type_registry/darwinia.json +730 -554
- data/lib/type_registry/default.json +3 -2
- data/lib/type_registry/pangolin.json +771 -0
- data/scale.gemspec +7 -5
- data/scripts/mmr_root_to_sign.rb +10 -0
- data/src/lib.rs +80 -25
- metadata +59 -30
- 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/src/storage_key.rs +0 -41
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ce5a456e8313b36d61cbfbff272c86985a6dc240603b37d6e96bd1cc0f28a9b
|
4
|
+
data.tar.gz: fda311dc30d0f8b31c62d9332bf241bab5b5646b6919fcb3b41814126692f469
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2d9d0c5ccc5cdc2e34515af88a64164678ce6f18a128f3e935906a362979ff6be7e83c0ea9ab17350acb3fb91e67766dbc3bc247fc733dd4310c9efb3aaf6857
|
7
|
+
data.tar.gz: 9c0a9f424308e368dc886ad31f568b118fa5596d21b7d5cd9d79bbefcf41a8324c4d3f885f24334165cac769e33da988f2b1f03097a966f19003b7c027cd8ab3
|
data/.gitignore
CHANGED
data/Cargo.lock
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# This file is automatically @generated by Cargo.
|
2
2
|
# It is not intended for manual editing.
|
3
|
+
version = 3
|
4
|
+
|
3
5
|
[[package]]
|
4
6
|
name = "Inflector"
|
5
7
|
version = "0.11.4"
|
@@ -15,6 +17,8 @@ name = "SCALE-testing-interface"
|
|
15
17
|
version = "0.1.0"
|
16
18
|
dependencies = [
|
17
19
|
"frame-support",
|
20
|
+
"hex",
|
21
|
+
"libc",
|
18
22
|
"parity-scale-codec",
|
19
23
|
"sp-core",
|
20
24
|
]
|
@@ -642,9 +646,9 @@ dependencies = [
|
|
642
646
|
|
643
647
|
[[package]]
|
644
648
|
name = "hex"
|
645
|
-
version = "0.4.
|
649
|
+
version = "0.4.3"
|
646
650
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
647
|
-
checksum = "
|
651
|
+
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
648
652
|
|
649
653
|
[[package]]
|
650
654
|
name = "hmac"
|
@@ -744,9 +748,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|
744
748
|
|
745
749
|
[[package]]
|
746
750
|
name = "libc"
|
747
|
-
version = "0.2.
|
751
|
+
version = "0.2.94"
|
748
752
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
749
|
-
checksum = "
|
753
|
+
checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
|
750
754
|
|
751
755
|
[[package]]
|
752
756
|
name = "libsecp256k1"
|
data/Cargo.toml
CHANGED
@@ -8,11 +8,10 @@ edition = "2018"
|
|
8
8
|
parity-scale-codec = { version = "1.3.6" }
|
9
9
|
sp-core = { version = "2.0.0", git = "https://github.com/paritytech/substrate.git", features = ["full_crypto"]}
|
10
10
|
frame-support = { version = "2.0.0", git = "https://github.com/paritytech/substrate.git" }
|
11
|
+
libc = { version = "0.2.94" }
|
12
|
+
hex = { version = "0.4.3" }
|
11
13
|
|
12
14
|
[lib]
|
13
15
|
name = "scale_ffi"
|
14
16
|
crate-type = ["dylib"]
|
15
17
|
|
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,47 +1,55 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
scale.rb (0.
|
4
|
+
scale.rb (0.3.0)
|
5
|
+
base58
|
6
|
+
blake2b_rs (~> 0.1.2)
|
7
|
+
faye-websocket
|
5
8
|
json (~> 2.3.0)
|
6
|
-
|
7
|
-
|
8
|
-
thor (~> 0.19.0)
|
9
|
+
thor (~> 1.0)
|
10
|
+
xxhash
|
9
11
|
|
10
12
|
GEM
|
11
13
|
remote: https://rubygems.org/
|
12
14
|
specs:
|
13
15
|
base58 (0.2.3)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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.1)
|
23
|
+
eventmachine (>= 0.12.0)
|
24
|
+
websocket-driver (>= 0.5.1)
|
25
|
+
ffi (1.15.0)
|
18
26
|
json (2.3.1)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
rspec-
|
28
|
-
rspec-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
rspec-expectations (3.9.0)
|
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)
|
33
40
|
diff-lcs (>= 1.2.0, < 2.0)
|
34
|
-
rspec-support (~> 3.
|
35
|
-
rspec-mocks (3.
|
41
|
+
rspec-support (~> 3.10.0)
|
42
|
+
rspec-mocks (3.10.2)
|
36
43
|
diff-lcs (>= 1.2.0, < 2.0)
|
37
|
-
rspec-support (~> 3.
|
38
|
-
rspec-support (3.
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
thor (
|
44
|
-
|
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.5)
|
45
53
|
websocket-extensions (>= 0.1.0)
|
46
54
|
websocket-extensions (0.1.5)
|
47
55
|
xxhash (0.4.0)
|
@@ -50,12 +58,12 @@ PLATFORMS
|
|
50
58
|
ruby
|
51
59
|
|
52
60
|
DEPENDENCIES
|
53
|
-
bundler
|
54
|
-
ffi (~> 1.
|
61
|
+
bundler
|
62
|
+
ffi (~> 1.15.0)
|
55
63
|
pry
|
56
64
|
rake (~> 13.0)
|
57
65
|
rspec (~> 3.2)
|
58
66
|
scale.rb!
|
59
67
|
|
60
68
|
BUNDLED WITH
|
61
|
-
|
69
|
+
2.2.13
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|

|
2
2
|
|
3
|
+
**Warning: After v0.2.19, the develop branch will do a structure refactor and big optimization.**
|
4
|
+
|
3
5
|
# scale.rb
|
4
6
|
|
5
7
|
**Ruby SCALE Codec Library**
|
@@ -19,7 +21,7 @@ Because the feature of ruby 2.6 is used, the ruby version is required to be >= 2
|
|
19
21
|
Add this line to your application's Gemfile:
|
20
22
|
|
21
23
|
```ruby
|
22
|
-
gem 'scale.rb'
|
24
|
+
gem 'scale.rb', '0.2.19'
|
23
25
|
```
|
24
26
|
|
25
27
|
And then execute:
|
@@ -37,10 +39,22 @@ Or install it yourself as:
|
|
37
39
|
```ruby
|
38
40
|
require "scale"
|
39
41
|
|
42
|
+
Scale::TypeRegistry.instance.load # default
|
43
|
+
# Scale::TypeRegistry.instance.load spec_name: "pangolin"
|
44
|
+
# Scale::TypeRegistry.instance.load spec_name: "kusama"
|
45
|
+
|
46
|
+
# print hex changes if you set debug to true, default is false
|
47
|
+
Scale::Types.debug = true
|
48
|
+
|
40
49
|
# decode a compact integer
|
41
50
|
scale_bytes = Scale::Bytes.new("0x1501") # create scale_bytes object from scale encoded hex string
|
42
51
|
o = Scale::Types::Compact.decode(scale_bytes) # use scale type to decode scale_bytes object
|
43
52
|
p o.value # 69
|
53
|
+
|
54
|
+
#
|
55
|
+
type = Scale::Types::get("Vec<U8>")
|
56
|
+
o = type.decode(Scale::Bytes.new("0x080001"))
|
57
|
+
assert_eq o.value, [Scale::Types::U8.new(0), Scale::Types::U8.new(1)]
|
44
58
|
```
|
45
59
|
|
46
60
|
2. encode
|
@@ -48,8 +62,37 @@ p o.value # 69
|
|
48
62
|
```ruby
|
49
63
|
require "scale"
|
50
64
|
|
65
|
+
Scale::TypeRegistry.instance.load
|
66
|
+
|
51
67
|
o = Scale::Types::Compact.new(69)
|
52
68
|
p o.encode # "1501"
|
69
|
+
|
70
|
+
type = Scale::Types::get("Vec<U8>")
|
71
|
+
o = type.new([Scale::Types::U8.new(0), Scale::Types::U8.new(1)])
|
72
|
+
p o.encode # "080001"
|
73
|
+
```
|
74
|
+
|
75
|
+
3. client
|
76
|
+
```ruby
|
77
|
+
require "scale"
|
78
|
+
client = SubstrateClient.new "wss://rpc.darwinia.network"
|
79
|
+
|
80
|
+
v = Scale::Types.get("EthereumTransactionIndex")
|
81
|
+
.new(
|
82
|
+
[
|
83
|
+
Scale::Types::H256.new("0x803054c2beacabc36e15c3147bb87d8320a02e9b601be28820a622dedd1c7717"),
|
84
|
+
Scale::Types::U64.new(266)
|
85
|
+
]
|
86
|
+
)
|
87
|
+
|
88
|
+
storage = client.get_storage("EthereumBacking", "VerifiedProof", [v])
|
89
|
+
puts storage.to_human
|
90
|
+
|
91
|
+
# get the raw data
|
92
|
+
key = client.generate_storage_key("EthereumBacking", "VerifiedProof", [v])[0]
|
93
|
+
storage_raw = client.state_getStorageAt(key)
|
94
|
+
puts storage_raw
|
95
|
+
|
53
96
|
```
|
54
97
|
Please go to `spec` dir for more examples.
|
55
98
|
|
data/Rakefile
CHANGED
data/exe/scale
CHANGED
@@ -1,88 +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
|
-
|
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
43
|
|
79
|
-
|
80
|
-
|
81
|
-
Scale::TypeRegistry.instance.load
|
82
|
-
proof = proof.split(",").map(&:strip)
|
83
|
-
|
84
|
-
value = Scale::Types::TrieNode::check(root, proof, storage_key)
|
85
|
-
p value
|
44
|
+
types.uniq!
|
45
|
+
puts types
|
86
46
|
end
|
87
47
|
end
|
88
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
|