-
Notifications
You must be signed in to change notification settings - Fork 255
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Metadata V15: Generate Runtime APIs #918
Changes from 6 commits
8af6a40
dd89dd6
073aea9
3c2d78a
d2d29dc
a795b62
98360c3
04dc695
47d84bc
365e78d
9302fa2
dd48979
bc2cf2a
f52b92b
9da2bf3
7f3931a
4663300
334f7fb
15ddaaa
78fafe6
561c16d
d7141ec
d7652e5
21741d8
bff5b7c
2546520
c1c8fd4
0f8a86d
d1229e7
16474c7
67d63b3
82548ce
9f7d26e
1b60e89
ae35fa7
df8e3b2
ce2d6d6
8cfdbe3
26688d3
57790d6
a58fbdc
fc5a952
e355c14
320f260
5754c09
719a004
c8b3fee
cd9d1e6
df24528
ff6efca
7bd91ff
b597b5d
ee9e679
834e3ad
3866c6b
69f5322
014b758
334ee4c
dc3433c
f74cf75
2d8e68d
4273fb7
ff64caa
b6f5f7b
9e02da4
0e17af5
b336ff3
4138b6a
05ebbe0
bd665d1
9c92ade
f16525d
e632b66
9bf0f66
0655df8
f29c048
a032374
0ea32fc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,9 +16,11 @@ use std::time::Duration; | |
/// The metadata version that is fetched from the node. | ||
#[derive(Default)] | ||
pub enum MetadataVersion { | ||
/// Version 14. | ||
/// Latest stable version of the metadata. | ||
#[default] | ||
V14, | ||
Latest, | ||
/// Fetch a specified version of the metadata. | ||
Version(u32), | ||
/// Latest unstable version of the metadata. | ||
Unstable, | ||
} | ||
|
@@ -75,48 +77,122 @@ pub async fn fetch_metadata_hex( | |
Ok(hex_data) | ||
} | ||
|
||
async fn fetch_latest_stable(client: impl ClientT) -> Result<Vec<u8>, FetchMetadataError> { | ||
// Fetch latest stable metadata of a node via `Metadata_metadata`. | ||
let raw: String = client | ||
.request("state_call", rpc_params!["Metadata_metadata", "0x"]) | ||
.await?; | ||
let raw_bytes = hex::decode(raw.trim_start_matches("0x"))?; | ||
let bytes: frame_metadata::OpaqueMetadata = Decode::decode(&mut &raw_bytes[..])?; | ||
Ok(bytes.0) | ||
} | ||
|
||
/// Execute runtime API call and return the specified runtime metadata version. | ||
async fn fetch_metadata( | ||
client: impl ClientT, | ||
version: MetadataVersion, | ||
) -> Result<Vec<u8>, FetchMetadataError> { | ||
const UNSTABLE_METADATA_VERSION: u32 = u32::MAX; | ||
const LATEST_STABLE_VERSION: u32 = 14; | ||
|
||
// Note: `Metadata_metadata_versions` may not be present on all nodes. | ||
// Once every node supports the new RPC methods, we can simplify the code a bit. | ||
let supported: Option<Vec<u32>> = client | ||
.request( | ||
"state_call", | ||
rpc_params!["Metadata_metadata_versions", "0x"], | ||
) | ||
.await | ||
.ok() | ||
.map(|raw: String| { | ||
let raw_bytes = hex::decode(raw.trim_start_matches("0x"))?; | ||
let versions: Vec<u32> = Decode::decode(&mut &raw_bytes[..])?; | ||
Ok::<Vec<u32>, FetchMetadataError>(versions) | ||
}) | ||
.transpose()?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The code here seems a bit complex after another look, I'll take a note to go back and do a plain-old match to make it easier to follow:
I believe we should be safe here, I'll be a bit more explicit with a simple match and such :D |
||
|
||
// Ensure the user requested a valid version if done implicitly. | ||
if let (Some(supported_versions), MetadataVersion::Version(request_version)) = | ||
(&supported, &version) | ||
{ | ||
if !supported_versions.is_empty() | ||
&& !supported_versions | ||
.iter() | ||
.any(|value| value == request_version) | ||
{ | ||
return Err(FetchMetadataError::Other(format!( | ||
"Metadata version {} not supported", | ||
request_version | ||
)))?; | ||
} | ||
} | ||
|
||
let mut is_latest = false; | ||
let version_num = match version { | ||
MetadataVersion::V14 => 14, | ||
MetadataVersion::Latest => { | ||
// If he have a valid supported version, find the latest stable version number. | ||
let version_num = if let Some(supported_versions) = &supported { | ||
supported_versions | ||
.iter() | ||
.fold(None, |max, value| match (max, value) { | ||
(None, value) => Some(value), | ||
(Some(old_max), value) => { | ||
if value != &UNSTABLE_METADATA_VERSION && value > old_max { | ||
Some(value) | ||
} else { | ||
Some(old_max) | ||
} | ||
} | ||
}) | ||
} else { | ||
// List not exposed by node. | ||
None | ||
}; | ||
|
||
if let Some(version_num) = version_num { | ||
// Use the latest stable from the provided list. | ||
is_latest = true; | ||
*version_num | ||
} else { | ||
// List is empty or the node does not expose the list of supported versions. | ||
return fetch_latest_stable(client).await; | ||
} | ||
} | ||
MetadataVersion::Version(version) => version, | ||
MetadataVersion::Unstable => UNSTABLE_METADATA_VERSION, | ||
}; | ||
|
||
// Fetch the latest stable version with `Metadata_metadata` API. | ||
if version_num == LATEST_STABLE_VERSION { | ||
let raw: String = client | ||
.request("state_call", rpc_params!["Metadata_metadata", "0x"]) | ||
.await?; | ||
let raw_bytes = hex::decode(raw.trim_start_matches("0x"))?; | ||
let bytes: frame_metadata::OpaqueMetadata = Decode::decode(&mut &raw_bytes[..])?; | ||
return Ok(bytes.0); | ||
} | ||
|
||
// Other versions (including unstable) are fetched with `Metadata_metadata_at_version`. | ||
let bytes = version_num.encode(); | ||
let version: String = format!("0x{}", hex::encode(&bytes)); | ||
|
||
let raw: String = client | ||
let result: Result<String, _> = client | ||
.request( | ||
"state_call", | ||
rpc_params!["Metadata_metadata_at_version", &version], | ||
) | ||
.await?; | ||
.await; | ||
|
||
let raw_bytes = hex::decode(raw.trim_start_matches("0x"))?; | ||
match result { | ||
Ok(raw) => { | ||
let raw_bytes = hex::decode(raw.trim_start_matches("0x"))?; | ||
|
||
let opaque: Option<frame_metadata::OpaqueMetadata> = Decode::decode(&mut &raw_bytes[..])?; | ||
let bytes = opaque.ok_or(FetchMetadataError::Other( | ||
"Metadata version not found".into(), | ||
))?; | ||
let opaque: Option<frame_metadata::OpaqueMetadata> = | ||
Decode::decode(&mut &raw_bytes[..])?; | ||
let bytes = opaque.ok_or(FetchMetadataError::Other( | ||
"Metadata version not found".into(), | ||
))?; | ||
|
||
Ok(bytes.0) | ||
Ok(bytes.0) | ||
} | ||
Err(err) => { | ||
// Try to fetch the latest with `Metadata_metadata`. | ||
if is_latest { | ||
fetch_latest_stable(client).await | ||
} else { | ||
Err(err.into()) | ||
} | ||
} | ||
} | ||
} | ||
|
||
async fn fetch_metadata_ws( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: maybe just manually have an
into_codegen_metadata_version(metadata_version: Option<MetadataVersion>) -> CodegenMetadataVersion
so we don't have to hardcode the 14 here (I'm trying to get away from assuming anything about what the node has in terms of metadata versions :))?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or clap has
default_value = <str>
which we could use so thatMetadataVersion
could have aLatest
variant and clap will default to using that. (maybe we can just useCodegenMetadataVersion
directly in that case?)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense! Have ended up using just the
CodegenMetadataVersion
here :D Thanks!