5
5
//! Fetch metadata from a URL.
6
6
7
7
use crate :: Error ;
8
- use codec:: { Decode , Encode } ;
8
+ use codec:: { Decode , Encode } ;
9
9
use jsonrpsee:: {
10
10
core:: client:: ClientT , http_client:: HttpClientBuilder , rpc_params, ws_client:: WsClientBuilder ,
11
11
} ;
@@ -44,19 +44,19 @@ impl std::str::FromStr for MetadataVersion {
44
44
}
45
45
46
46
/// Returns the metadata bytes from the provided URL.
47
- pub async fn from_url ( url : Url , version : MetadataVersion ) -> Result < Vec < u8 > , Error > {
47
+ pub async fn from_url ( url : Url , version : MetadataVersion , at_block_hash : Option < & str > ) -> Result < Vec < u8 > , Error > {
48
48
let bytes = match url. scheme ( ) {
49
- "http" | "https" => fetch_metadata_http ( url, version) . await ,
50
- "ws" | "wss" => fetch_metadata_ws ( url, version) . await ,
49
+ "http" | "https" => fetch_metadata_http ( url, version, at_block_hash ) . await ,
50
+ "ws" | "wss" => fetch_metadata_ws ( url, version, at_block_hash ) . await ,
51
51
invalid_scheme => Err ( Error :: InvalidScheme ( invalid_scheme. to_owned ( ) ) ) ,
52
52
} ?;
53
53
54
54
Ok ( bytes)
55
55
}
56
56
57
57
/// Returns the metadata bytes from the provided URL, blocking the current thread.
58
- pub fn from_url_blocking ( url : Url , version : MetadataVersion ) -> Result < Vec < u8 > , Error > {
59
- tokio_block_on ( from_url ( url, version) )
58
+ pub fn from_url_blocking ( url : Url , version : MetadataVersion , at_block_hash : Option < & str > ) -> Result < Vec < u8 > , Error > {
59
+ tokio_block_on ( from_url ( url, version, at_block_hash ) )
60
60
}
61
61
62
62
// Block on some tokio runtime for sync contexts
@@ -68,34 +68,40 @@ fn tokio_block_on<T, Fut: std::future::Future<Output = T>>(fut: Fut) -> T {
68
68
. block_on ( fut)
69
69
}
70
70
71
- async fn fetch_metadata_ws ( url : Url , version : MetadataVersion ) -> Result < Vec < u8 > , Error > {
71
+ async fn fetch_metadata_ws ( url : Url , version : MetadataVersion , at_block_hash : Option < & str > ) -> Result < Vec < u8 > , Error > {
72
72
let client = WsClientBuilder :: default ( )
73
73
. request_timeout ( std:: time:: Duration :: from_secs ( 180 ) )
74
74
. max_buffer_capacity_per_subscription ( 4096 )
75
75
. build ( url)
76
76
. await ?;
77
77
78
- fetch_metadata ( client, version) . await
78
+ fetch_metadata ( client, version, at_block_hash ) . await
79
79
}
80
80
81
- async fn fetch_metadata_http ( url : Url , version : MetadataVersion ) -> Result < Vec < u8 > , Error > {
81
+ async fn fetch_metadata_http ( url : Url , version : MetadataVersion , at_block_hash : Option < & str > ) -> Result < Vec < u8 > , Error > {
82
82
let client = HttpClientBuilder :: default ( )
83
83
. request_timeout ( std:: time:: Duration :: from_secs ( 180 ) )
84
84
. build ( url) ?;
85
85
86
- fetch_metadata ( client, version) . await
86
+ fetch_metadata ( client, version, at_block_hash ) . await
87
87
}
88
88
89
89
/// The innermost call to fetch metadata:
90
- async fn fetch_metadata ( client : impl ClientT , version : MetadataVersion ) -> Result < Vec < u8 > , Error > {
90
+ async fn fetch_metadata ( client : impl ClientT , version : MetadataVersion , at_block_hash : Option < & str > ) -> Result < Vec < u8 > , Error > {
91
91
const UNSTABLE_METADATA_VERSION : u32 = u32:: MAX ;
92
92
93
+ // Ensure always 0x prefix.
94
+ let at_block_hash = at_block_hash
95
+ . map ( |hash| format ! ( "0x{}" , hash. strip_prefix( "0x" ) . unwrap_or( hash) ) ) ;
96
+ let at_block_hash = at_block_hash. as_deref ( ) ;
97
+
93
98
// Fetch available metadata versions. If error, revert to legacy metadata code.
94
99
async fn fetch_available_versions (
95
100
client : & impl ClientT ,
101
+ at_block_hash : Option < & str > ,
96
102
) -> Result < Vec < u32 > , Error > {
97
103
let res: String = client
98
- . request ( "state_call" , rpc_params ! [ "Metadata_metadata_versions" , "0x" ] )
104
+ . request ( "state_call" , rpc_params ! [ "Metadata_metadata_versions" , "0x" , at_block_hash ] )
99
105
. await ?;
100
106
let raw_bytes = hex:: decode ( res. trim_start_matches ( "0x" ) ) ?;
101
107
Decode :: decode ( & mut & raw_bytes[ ..] ) . map_err ( Into :: into)
@@ -106,6 +112,7 @@ async fn fetch_metadata(client: impl ClientT, version: MetadataVersion) -> Resul
106
112
client : & impl ClientT ,
107
113
version : MetadataVersion ,
108
114
supported_versions : Vec < u32 > ,
115
+ at_block_hash : Option < & str > ,
109
116
) -> Result < Vec < u8 > , Error > {
110
117
// Return the version the user wants if it's supported:
111
118
let version = match version {
@@ -141,7 +148,7 @@ async fn fetch_metadata(client: impl ClientT, version: MetadataVersion) -> Resul
141
148
let metadata_string: String = client
142
149
. request (
143
150
"state_call" ,
144
- rpc_params ! [ "Metadata_metadata_at_version" , & version] ,
151
+ rpc_params ! [ "Metadata_metadata_at_version" , & version, at_block_hash ] ,
145
152
)
146
153
. await ?;
147
154
// Decode the metadata.
@@ -159,10 +166,11 @@ async fn fetch_metadata(client: impl ClientT, version: MetadataVersion) -> Resul
159
166
// Fetch metadata using the "old" state_call interface
160
167
async fn fetch_inner_legacy (
161
168
client : & impl ClientT ,
169
+ at_block_hash : Option < & str > ,
162
170
) -> Result < Vec < u8 > , Error > {
163
171
// Fetch the metadata.
164
172
let metadata_string: String = client
165
- . request ( "state_call" , rpc_params ! [ "Metadata_metadata" , "0x" ] )
173
+ . request ( "state_call" , rpc_params ! [ "Metadata_metadata" , "0x" , at_block_hash ] )
166
174
. await ?;
167
175
168
176
// Decode the metadata.
@@ -171,16 +179,16 @@ async fn fetch_metadata(client: impl ClientT, version: MetadataVersion) -> Resul
171
179
Ok ( metadata. 0 )
172
180
}
173
181
174
- match fetch_available_versions ( & client) . await {
182
+ match fetch_available_versions ( & client, at_block_hash ) . await {
175
183
Ok ( supported_versions) => {
176
- fetch_inner ( & client, version, supported_versions) . await
184
+ fetch_inner ( & client, version, supported_versions, at_block_hash ) . await
177
185
} ,
178
186
Err ( e) => {
179
187
// The "new" interface failed. if the user is asking for V14 or the "latest"
180
188
// metadata then try the legacy interface instead. Else, just return the
181
189
// reason for failure.
182
190
if matches ! ( version, MetadataVersion :: Version ( 14 ) | MetadataVersion :: Latest ) {
183
- fetch_inner_legacy ( & client) . await
191
+ fetch_inner_legacy ( & client, at_block_hash ) . await
184
192
} else {
185
193
Err ( e)
186
194
}
0 commit comments