1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#[macro_use]
extern crate serde;
#[macro_use]
extern crate parity_scale_codec;
use self::version::*;
use parity_scale_codec::{Decode, Error as ScaleError};
use serde_json::Error as SerdeJsonError;
type Result<T> = std::result::Result<T, Error>;
mod version;
pub struct ExtrinsicInfo<'a> {
pub module_id: usize,
pub dispatch_id: usize,
pub module_name: &'a str,
pub extrinsic_name: &'a str,
pub args: Vec<(&'a str, &'a str)>,
pub documentation: Vec<&'a str>,
}
pub trait ModuleMetadataExt {
fn modules_extrinsics<'a>(&'a self) -> Vec<ExtrinsicInfo<'a>>;
fn find_module_extrinsic<'a>(
&'a self,
method: &str,
extrinsic: &str,
) -> Result<Option<ExtrinsicInfo<'a>>>;
}
#[derive(Debug)]
pub enum Error {
ParseJsonRpcMetadata(SerdeJsonError),
ParseHexMetadata(hex::FromHexError),
ParseRawMetadata(ScaleError),
InvalidMetadataVersion,
}
#[derive(Debug, Clone, Deserialize)]
pub struct JsonRpcResponse {
pub jsonrpc: String,
pub result: String,
}
pub fn parse_jsonrpc_metadata<T: AsRef<[u8]>>(json: T) -> Result<MetadataVersion> {
let resp = serde_json::from_slice::<JsonRpcResponse>(json.as_ref())
.map_err(|err| Error::ParseJsonRpcMetadata(err))?;
parse_hex_metadata(resp.result.as_bytes())
}
pub fn parse_hex_metadata<T: AsRef<[u8]>>(hex: T) -> Result<MetadataVersion> {
let hex = hex.as_ref();
let slice = if hex.starts_with(b"0x") {
hex[2..].as_ref()
} else {
hex
};
parse_raw_metadata(hex::decode(slice).map_err(|err| Error::ParseHexMetadata(err))?)
}
pub fn parse_raw_metadata<T: AsRef<[u8]>>(raw: T) -> Result<MetadataVersion> {
let raw = raw.as_ref();
let mut slice = if raw.starts_with(b"meta") {
raw[4..].as_ref()
} else {
raw
};
MetadataVersion::decode(&mut slice).map_err(|err| Error::ParseRawMetadata(err))
}
#[derive(Debug, Clone, PartialEq, Encode, Decode)]
pub enum MetadataVersion {
V0,
V1,
V2,
V3,
V4,
V5,
V6,
V7,
V8,
V9,
V10,
V11,
V12,
V13(MetadataV13),
}
impl MetadataVersion {
pub fn into_latest(self) -> Result<MetadataV13> {
match self {
MetadataVersion::V13(data) => Ok(data),
_ => Err(Error::InvalidMetadataVersion),
}
}
pub fn version_number(&self) -> usize {
use MetadataVersion::*;
match self {
V0 => 0,
V1 => 1,
V2 => 2,
V3 => 3,
V4 => 4,
V5 => 5,
V6 => 6,
V7 => 7,
V8 => 8,
V9 => 9,
V10 => 10,
V11 => 11,
V12 => 12,
V13(_) => 13,
}
}
pub fn into_inner(self) -> impl ModuleMetadataExt {
match self {
MetadataVersion::V13(m) => m,
_ => panic!(),
}
}
}
#[test]
fn parse_file() {
use std::fs::read_to_string;
let content = read_to_string("dumps/metadata_polkadot_9050.json").unwrap();
let res = parse_jsonrpc_metadata(content).unwrap();
let data = match res {
MetadataVersion::V13(data) => data,
_ => panic!(),
};
for m in data.modules {
println!("> {}", m.name);
m.calls.map(|calls| {
for c in calls {
println!(" > {}", c.name);
for arg in c.arguments {
println!(" > {}: {}", arg.name, arg.ty);
}
}
});
}
}