Skip to content
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

Fix runtime api impl detection by construct runtime #6665

Merged
merged 8 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions prdoc/pr_6665.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
title: Fix runtime api impl detection by construct runtime
doc:
- audience: Runtime Dev
description: |-
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: https://github.com/paritytech/polkadot-sdk/issues/6659
crates:
- name: frame-support-procedural
bump: patch
- name: sp-api-proc-macro
bump: patch
- name: sp-metadata-ir
bump: patch
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ pub fn expand_runtime_metadata(
<#extrinsic as #scrate::traits::SignedTransactionBuilder>::Extension
>();

use #scrate::__private::metadata_ir::InternalImplRuntimeApis;

#scrate::__private::metadata_ir::MetadataIR {
pallets: #scrate::__private::vec![ #(#pallets),* ],
extrinsic: #scrate::__private::metadata_ir::ExtrinsicMetadataIR {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,6 @@ fn construct_runtime_final_expansion(
// Therefore, the `Deref` trait will resolve the `runtime_metadata` from `impl_runtime_apis!`
// when both macros are called; and will resolve an empty `runtime_metadata` when only the `construct_runtime!`
// is called.

#[doc(hidden)]
trait InternalConstructRuntime {
#[inline(always)]
Expand All @@ -477,6 +476,8 @@ fn construct_runtime_final_expansion(
#[doc(hidden)]
impl InternalConstructRuntime for &#name {}

use #scrate::__private::metadata_ir::InternalImplRuntimeApis;

#outer_event

#outer_error
Expand Down
49 changes: 27 additions & 22 deletions substrate/frame/support/test/tests/runtime_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,34 +80,39 @@ sp_api::decl_runtime_apis! {
}
}

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

fn something_with_block(_: Block) -> Block {
unimplemented!()
}
sp_api::impl_runtime_apis! {
impl crate::Api<Block> for Runtime {
fn test(_data: u64) {
unimplemented!()
}

fn function_with_two_args(_: u64, _: Block) {
unimplemented!()
}
fn something_with_block(_: Block) -> Block {
unimplemented!()
}

fn same_name() {}
fn function_with_two_args(_: u64, _: Block) {
unimplemented!()
}

fn wild_card(_: u32) {}
}
fn same_name() {}

impl sp_api::Core<Block> for Runtime {
fn version() -> sp_version::RuntimeVersion {
unimplemented!()
}
fn execute_block(_: Block) {
unimplemented!()
fn wild_card(_: u32) {}
}
fn initialize_block(_: &<Block as BlockT>::Header) -> sp_runtime::ExtrinsicInclusionMode {
unimplemented!()

impl sp_api::Core<Block> for Runtime {
fn version() -> sp_version::RuntimeVersion {
unimplemented!()
}
fn execute_block(_: Block) {
unimplemented!()
}
fn initialize_block(_: &<Block as BlockT>::Header) -> sp_runtime::ExtrinsicInclusionMode {
unimplemented!()
}
}
}
}
Expand Down
6 changes: 1 addition & 5 deletions substrate/primitives/api/proc-macro/src/runtime_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,18 +298,14 @@ pub fn generate_impl_runtime_metadata(impls: &[ItemImpl]) -> Result<TokenStream2
// Therefore, the `Deref` trait will resolve the `runtime_metadata` from `impl_runtime_apis!`
// when both macros are called; and will resolve an empty `runtime_metadata` when only the
// `construct_runtime!` is called.

Ok(quote!(
#crate_::frame_metadata_enabled! {
#[doc(hidden)]
trait InternalImplRuntimeApis {
#[inline(always)]
impl #crate_::metadata_ir::InternalImplRuntimeApis for #runtime_name {
fn runtime_metadata(&self) -> #crate_::vec::Vec<#crate_::metadata_ir::RuntimeApiMetadataIR> {
#crate_::vec![ #( #metadata, )* ]
}
}
#[doc(hidden)]
impl InternalImplRuntimeApis for #runtime_name {}
}
))
}
3 changes: 2 additions & 1 deletion substrate/primitives/api/test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ sp-version = { workspace = true, default-features = true }
sp-tracing = { workspace = true, default-features = true }
sp-runtime = { workspace = true, default-features = true }
sp-consensus = { workspace = true, default-features = true }
sp-metadata-ir = { workspace = true, default-features = true }
sc-block-builder = { workspace = true, default-features = true }
codec = { workspace = true, default-features = true }
sp-state-machine = { workspace = true, default-features = true }
Expand All @@ -40,5 +41,5 @@ name = "bench"
harness = false

[features]
"enable-staging-api" = []
enable-staging-api = []
disable-ui-tests = []
2 changes: 2 additions & 0 deletions substrate/primitives/api/test/tests/decl_and_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,8 @@ fn mock_runtime_api_works_with_advanced() {

#[test]
fn runtime_api_metadata_matches_version_implemented() {
use sp_metadata_ir::InternalImplRuntimeApis;

let rt = Runtime {};
let runtime_metadata = rt.runtime_metadata();

Expand Down
10 changes: 10 additions & 0 deletions substrate/primitives/metadata-ir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@ pub fn into_unstable(metadata: MetadataIR) -> RuntimeMetadataPrefixed {
latest.into()
}

/// INTERNAL USE ONLY
///
/// Special trait that is used together with `InternalConstructRuntime` by `construct_runtime!` to
/// fetch the runtime api metadata without exploding when there is no runtime api implementation
/// available.
#[doc(hidden)]
pub trait InternalImplRuntimeApis {
fn runtime_metadata(&self) -> alloc::vec::Vec<RuntimeApiMetadataIR>;
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
Loading