Skip to content

Commit c3d5de4

Browse files
bkchractions-user
authored andcommitted
Fix runtime api impl detection by construct runtime (paritytech#6665)
Construct runtime uses autoref-based specialization to fetch the metadata about the implemented runtime apis. This is done to not fail to compile when there are no runtime apis implemented. However, there was an issue with detecting runtime apis when they were implemented in a different file. The problem is solved by moving the trait implemented by `impl_runtime_apis!` to the metadata ir crate. Closes: paritytech#6659 --------- Co-authored-by: GitHub Action <[email protected]>
1 parent ec3b1f1 commit c3d5de4

File tree

9 files changed

+62
-29
lines changed

9 files changed

+62
-29
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

prdoc/pr_6665.prdoc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
title: Fix runtime api impl detection by construct runtime
2+
doc:
3+
- audience: Runtime Dev
4+
description: |-
5+
Construct runtime uses autoref-based specialization to fetch the metadata about the implemented runtime apis. This is done to not fail to compile when there are no runtime apis implemented. However, there was an issue with detecting runtime apis when they were implemented in a different file. The problem is solved by moving the trait implemented by `impl_runtime_apis!` to the metadata ir crate.
6+
7+
8+
Closes: https://github.com/paritytech/polkadot-sdk/issues/6659
9+
crates:
10+
- name: frame-support-procedural
11+
bump: patch
12+
- name: sp-api-proc-macro
13+
bump: patch
14+
- name: sp-metadata-ir
15+
bump: patch

substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ pub fn expand_runtime_metadata(
113113
<#extrinsic as #scrate::traits::SignedTransactionBuilder>::Extension
114114
>();
115115

116+
use #scrate::__private::metadata_ir::InternalImplRuntimeApis;
117+
116118
#scrate::__private::metadata_ir::MetadataIR {
117119
pallets: #scrate::__private::vec![ #(#pallets),* ],
118120
extrinsic: #scrate::__private::metadata_ir::ExtrinsicMetadataIR {

substrate/frame/support/procedural/src/construct_runtime/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,6 @@ fn construct_runtime_final_expansion(
466466
// Therefore, the `Deref` trait will resolve the `runtime_metadata` from `impl_runtime_apis!`
467467
// when both macros are called; and will resolve an empty `runtime_metadata` when only the `construct_runtime!`
468468
// is called.
469-
470469
#[doc(hidden)]
471470
trait InternalConstructRuntime {
472471
#[inline(always)]
@@ -477,6 +476,8 @@ fn construct_runtime_final_expansion(
477476
#[doc(hidden)]
478477
impl InternalConstructRuntime for &#name {}
479478

479+
use #scrate::__private::metadata_ir::InternalImplRuntimeApis;
480+
480481
#outer_event
481482

482483
#outer_error

substrate/frame/support/test/tests/runtime_metadata.rs

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -80,34 +80,39 @@ sp_api::decl_runtime_apis! {
8080
}
8181
}
8282

83-
sp_api::impl_runtime_apis! {
84-
impl self::Api<Block> for Runtime {
85-
fn test(_data: u64) {
86-
unimplemented!()
87-
}
83+
// Module to emulate having the implementation in a different file.
84+
mod apis {
85+
use super::{Block, BlockT, Runtime};
8886

89-
fn something_with_block(_: Block) -> Block {
90-
unimplemented!()
91-
}
87+
sp_api::impl_runtime_apis! {
88+
impl crate::Api<Block> for Runtime {
89+
fn test(_data: u64) {
90+
unimplemented!()
91+
}
9292

93-
fn function_with_two_args(_: u64, _: Block) {
94-
unimplemented!()
95-
}
93+
fn something_with_block(_: Block) -> Block {
94+
unimplemented!()
95+
}
9696

97-
fn same_name() {}
97+
fn function_with_two_args(_: u64, _: Block) {
98+
unimplemented!()
99+
}
98100

99-
fn wild_card(_: u32) {}
100-
}
101+
fn same_name() {}
101102

102-
impl sp_api::Core<Block> for Runtime {
103-
fn version() -> sp_version::RuntimeVersion {
104-
unimplemented!()
105-
}
106-
fn execute_block(_: Block) {
107-
unimplemented!()
103+
fn wild_card(_: u32) {}
108104
}
109-
fn initialize_block(_: &<Block as BlockT>::Header) -> sp_runtime::ExtrinsicInclusionMode {
110-
unimplemented!()
105+
106+
impl sp_api::Core<Block> for Runtime {
107+
fn version() -> sp_version::RuntimeVersion {
108+
unimplemented!()
109+
}
110+
fn execute_block(_: Block) {
111+
unimplemented!()
112+
}
113+
fn initialize_block(_: &<Block as BlockT>::Header) -> sp_runtime::ExtrinsicInclusionMode {
114+
unimplemented!()
115+
}
111116
}
112117
}
113118
}

substrate/primitives/api/proc-macro/src/runtime_metadata.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -298,18 +298,14 @@ pub fn generate_impl_runtime_metadata(impls: &[ItemImpl]) -> Result<TokenStream2
298298
// Therefore, the `Deref` trait will resolve the `runtime_metadata` from `impl_runtime_apis!`
299299
// when both macros are called; and will resolve an empty `runtime_metadata` when only the
300300
// `construct_runtime!` is called.
301-
302301
Ok(quote!(
303302
#crate_::frame_metadata_enabled! {
304303
#[doc(hidden)]
305-
trait InternalImplRuntimeApis {
306-
#[inline(always)]
304+
impl #crate_::metadata_ir::InternalImplRuntimeApis for #runtime_name {
307305
fn runtime_metadata(&self) -> #crate_::vec::Vec<#crate_::metadata_ir::RuntimeApiMetadataIR> {
308306
#crate_::vec![ #( #metadata, )* ]
309307
}
310308
}
311-
#[doc(hidden)]
312-
impl InternalImplRuntimeApis for #runtime_name {}
313309
}
314310
))
315311
}

substrate/primitives/api/test/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ sp-version = { workspace = true, default-features = true }
2121
sp-tracing = { workspace = true, default-features = true }
2222
sp-runtime = { workspace = true, default-features = true }
2323
sp-consensus = { workspace = true, default-features = true }
24+
sp-metadata-ir = { workspace = true, default-features = true }
2425
sc-block-builder = { workspace = true, default-features = true }
2526
codec = { workspace = true, default-features = true }
2627
sp-state-machine = { workspace = true, default-features = true }
@@ -40,5 +41,5 @@ name = "bench"
4041
harness = false
4142

4243
[features]
43-
"enable-staging-api" = []
44+
enable-staging-api = []
4445
disable-ui-tests = []

substrate/primitives/api/test/tests/decl_and_impl.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,8 @@ fn mock_runtime_api_works_with_advanced() {
309309

310310
#[test]
311311
fn runtime_api_metadata_matches_version_implemented() {
312+
use sp_metadata_ir::InternalImplRuntimeApis;
313+
312314
let rt = Runtime {};
313315
let runtime_metadata = rt.runtime_metadata();
314316

substrate/primitives/metadata-ir/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,16 @@ pub fn into_unstable(metadata: MetadataIR) -> RuntimeMetadataPrefixed {
8787
latest.into()
8888
}
8989

90+
/// INTERNAL USE ONLY
91+
///
92+
/// Special trait that is used together with `InternalConstructRuntime` by `construct_runtime!` to
93+
/// fetch the runtime api metadata without exploding when there is no runtime api implementation
94+
/// available.
95+
#[doc(hidden)]
96+
pub trait InternalImplRuntimeApis {
97+
fn runtime_metadata(&self) -> alloc::vec::Vec<RuntimeApiMetadataIR>;
98+
}
99+
90100
#[cfg(test)]
91101
mod test {
92102
use super::*;

0 commit comments

Comments
 (0)