From 7b46d9cfd4d72d1d9f264f485711373d1b974968 Mon Sep 17 00:00:00 2001 From: Pavlo Khrystenko Date: Mon, 9 Dec 2024 10:58:57 +0100 Subject: [PATCH 01/15] add the ability to declare multiple impl blocks --- .../support/test/tests/runtime_metadata.rs | 9 +- .../api/proc-macro/src/impl_runtime_apis.rs | 161 ++++++++++++++++-- .../primitives/api/proc-macro/src/lib.rs | 5 + .../api/proc-macro/src/runtime_metadata.rs | 37 +++- substrate/primitives/api/src/lib.rs | 4 + .../api/test/tests/decl_and_impl.rs | 25 ++- 6 files changed, 212 insertions(+), 29 deletions(-) diff --git a/substrate/frame/support/test/tests/runtime_metadata.rs b/substrate/frame/support/test/tests/runtime_metadata.rs index a098643abb91..0d3e864d78f3 100644 --- a/substrate/frame/support/test/tests/runtime_metadata.rs +++ b/substrate/frame/support/test/tests/runtime_metadata.rs @@ -102,7 +102,12 @@ mod apis { fn wild_card(_: u32) {} } + pub use ext::*; + } + #[sp_api::impl_runtime_apis_ext] + mod ext { + use super::*; impl sp_api::Core for Runtime { fn version() -> sp_version::RuntimeVersion { unimplemented!() @@ -110,7 +115,9 @@ mod apis { fn execute_block(_: Block) { unimplemented!() } - fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { + fn initialize_block( + _: &::Header, + ) -> sp_runtime::ExtrinsicInclusionMode { unimplemented!() } } diff --git a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs index 5c9448da2bc7..d5a5dc8fb26a 100644 --- a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -15,11 +15,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::utils::{ - extract_api_version, extract_block_type_from_trait_path, extract_impl_trait, - extract_parameter_names_types_and_borrows, generate_crate_access, - generate_runtime_mod_name_for_trait, prefix_function_with_trait, versioned_trait_name, - AllowSelfRefInParameters, ApiVersion, RequireQualifiedTraitPath, +use crate::{ + runtime_metadata::Kind, + utils::{ + extract_api_version, extract_block_type_from_trait_path, extract_impl_trait, + extract_parameter_names_types_and_borrows, generate_crate_access, + generate_runtime_mod_name_for_trait, prefix_function_with_trait, versioned_trait_name, + AllowSelfRefInParameters, ApiVersion, RequireQualifiedTraitPath, + }, }; use proc_macro2::{Span, TokenStream}; @@ -32,7 +35,8 @@ use syn::{ parse_macro_input, parse_quote, spanned::Spanned, visit_mut::{self, VisitMut}, - Attribute, Ident, ImplItem, ItemImpl, Path, Signature, Type, TypePath, + Attribute, Ident, ImplItem, ItemImpl, ItemMod, ItemUse, Path, Signature, Type, TypePath, + UseTree, }; use std::collections::HashMap; @@ -40,20 +44,26 @@ use std::collections::HashMap; /// The structure used for parsing the runtime api implementations. struct RuntimeApiImpls { impls: Vec, + uses: Vec, } impl Parse for RuntimeApiImpls { fn parse(input: ParseStream) -> Result { let mut impls = Vec::new(); - + let mut uses = Vec::new(); while !input.is_empty() { - impls.push(ItemImpl::parse(input)?); + if input.peek(syn::Token![use]) || input.peek2(syn::Token![use]) { + let item = input.parse::()?; + uses.push(item); + } else { + impls.push(input.parse::()?); + } } if impls.is_empty() { Err(Error::new(Span::call_site(), "No api implementation given!")) } else { - Ok(Self { impls }) + Ok(Self { impls, uses }) } } } @@ -192,7 +202,7 @@ fn generate_impl_calls( } /// Generate the dispatch function that is used in native to call into the runtime. -fn generate_dispatch_function(impls: &[ItemImpl]) -> Result { +fn generate_dispatch_function(impls: &[ItemImpl], kind: Kind) -> Result { let data = Ident::new("_sp_api_input_data_", Span::call_site()); let c = generate_crate_access(); let impl_calls = @@ -205,13 +215,33 @@ fn generate_dispatch_function(impls: &[ItemImpl]) -> Result { #name => Some(#c::Encode::encode(&{ #impl_ })), ) }); - + let other_branches = match kind { + Kind::Main(paths) => { + let items = paths + .iter() + .map(|x| { + quote::quote! { + if let Some(res) = #x::api::dispatch(method, #data) { + return Some(res); + } + } + }) + .collect::>(); + quote::quote! { + #(#items)* + None + } + }, + Kind::Ext => quote::quote! { None }, + }; Ok(quote!( #c::std_enabled! { pub fn dispatch(method: &str, mut #data: &[u8]) -> Option> { match method { #( #impl_calls )* - _ => None, + _ => { + #other_branches + }, } } } @@ -818,26 +848,56 @@ fn rename_self_in_trait_impls(impls: &mut [ItemImpl]) { /// The implementation of the `impl_runtime_apis!` macro. pub fn impl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream { // Parse all impl blocks - let RuntimeApiImpls { impls: mut api_impls } = parse_macro_input!(input as RuntimeApiImpls); + let RuntimeApiImpls { impls: mut api_impls, uses } = + parse_macro_input!(input as RuntimeApiImpls); - impl_runtime_apis_impl_inner(&mut api_impls) + impl_runtime_apis_impl_inner(&mut api_impls, &uses) .unwrap_or_else(|e| e.to_compile_error()) .into() } -fn impl_runtime_apis_impl_inner(api_impls: &mut [ItemImpl]) -> Result { +fn impl_runtime_apis_impl_inner( + api_impls: &mut [ItemImpl], + uses: &[ItemUse], +) -> Result { rename_self_in_trait_impls(api_impls); - let dispatch_impl = generate_dispatch_function(api_impls)?; let api_impls_for_runtime = generate_api_impl_for_runtime(api_impls)?; let base_runtime_api = generate_runtime_api_base_structures()?; let runtime_api_versions = generate_runtime_api_versions(api_impls)?; let wasm_interface = generate_wasm_interface(api_impls)?; let api_impls_for_runtime_api = generate_api_impl_for_runtime_api(api_impls)?; + let modules: Vec = uses + .iter() + .map(|item| { + let mut path: Vec = vec![]; + fn call(path: &mut Vec, item: &UseTree) { + match &item { + syn::UseTree::Path(use_path) => { + path.push(use_path.ident.clone()); + call(path, use_path.tree.as_ref()); + }, + syn::UseTree::Glob(_) => (), + syn::UseTree::Name(_) | syn::UseTree::Rename(_) | syn::UseTree::Group(_) => + unimplemented!(), + } + } + call(&mut path, &item.tree); + let tok = quote::quote! {#(#path)::*}; + syn::parse::(tok.into()).unwrap() + }) + .collect(); - let runtime_metadata = crate::runtime_metadata::generate_impl_runtime_metadata(api_impls)?; + let dispatch_impl = generate_dispatch_function(api_impls, Kind::Main(&modules))?; + + let runtime_metadata = + crate::runtime_metadata::generate_impl_runtime_metadata(api_impls, Kind::Main(&modules))?; + + let c = generate_crate_access(); let impl_ = quote!( + #(#uses)* + #base_runtime_api #api_impls_for_runtime @@ -848,6 +908,11 @@ fn impl_runtime_apis_impl_inner(api_impls: &mut [ItemImpl]) -> Result #c::ApisVec { + let api = #c::vec::Vec::from([RUNTIME_API_VERSIONS.into_owned(), #(#modules::RUNTIME_API_VERSIONS.into_owned()),*]).concat(); + api.into() + } + pub mod api { use super::*; @@ -866,6 +931,66 @@ fn impl_runtime_apis_impl_inner(api_impls: &mut [ItemImpl]) -> Result proc_macro::TokenStream { + let module = parse_macro_input!(input as ItemMod); + let (_, items) = module.content.unwrap(); + let contents = quote::quote! { #(#items)* }; + let contents: proc_macro::TokenStream = contents.into(); + // Parse all impl blocks + let RuntimeApiImpls { impls: mut api_impls, uses } = + parse_macro_input!(contents as RuntimeApiImpls); + + impl_runtime_apis_impl_inner_ext(module.ident, &mut api_impls, &uses) + .unwrap_or_else(|e| e.to_compile_error()) + .into() +} + +fn impl_runtime_apis_impl_inner_ext( + module: Ident, + api_impls: &mut [ItemImpl], + uses: &[ItemUse], +) -> Result { + rename_self_in_trait_impls(api_impls); + let dispatch_impl = generate_dispatch_function(api_impls, Kind::Ext)?; + let api_impls_for_runtime = generate_api_impl_for_runtime(api_impls)?; + let runtime_api_versions = generate_runtime_api_versions(api_impls)?; + let wasm_interface = generate_wasm_interface(api_impls)?; + let api_impls_for_runtime_api = generate_api_impl_for_runtime_api(api_impls)?; + + let runtime_metadata = + crate::runtime_metadata::generate_impl_runtime_metadata(api_impls, Kind::Ext)?; + let impl_ = quote!( + pub mod #module { + #(#uses)* + + #api_impls_for_runtime + + #api_impls_for_runtime_api + + #runtime_api_versions + + #runtime_metadata + + pub mod api { + use super::*; + + #dispatch_impl + + #wasm_interface + } + } + ); + + let impl_ = expander::Expander::new("impl_runtime_apis_ext") + .dry(std::env::var("EXPAND_MACROS").is_err()) + .verbose(true) + .write_to_out_dir(impl_) + .expect("Does not fail because of IO in OUT_DIR; qed"); + + Ok(impl_) +} + // Filters all attributes except the cfg ones. fn filter_cfg_attrs(attrs: &[Attribute]) -> Vec { attrs.iter().filter(|a| a.path().is_ident("cfg")).cloned().collect() @@ -914,7 +1039,7 @@ mod tests { }; // Parse the items - let RuntimeApiImpls { impls: mut api_impls } = + let RuntimeApiImpls { impls: mut api_impls, uses } = syn::parse2::(code).unwrap(); // Run the renamer which is being run first in the `impl_runtime_apis!` macro. diff --git a/substrate/primitives/api/proc-macro/src/lib.rs b/substrate/primitives/api/proc-macro/src/lib.rs index d34f4b7f9cf6..945a91beada5 100644 --- a/substrate/primitives/api/proc-macro/src/lib.rs +++ b/substrate/primitives/api/proc-macro/src/lib.rs @@ -42,3 +42,8 @@ pub fn mock_impl_runtime_apis(input: TokenStream) -> TokenStream { pub fn decl_runtime_apis(input: TokenStream) -> TokenStream { decl_runtime_apis::decl_runtime_apis_impl(input) } + +#[proc_macro_attribute] +pub fn impl_runtime_apis_ext(_attrs: TokenStream, tokens: TokenStream) -> TokenStream { + impl_runtime_apis::impl_runtime_apis_impl_ext(tokens) +} diff --git a/substrate/primitives/api/proc-macro/src/runtime_metadata.rs b/substrate/primitives/api/proc-macro/src/runtime_metadata.rs index 1706f8ca6fbb..1c594ff31467 100644 --- a/substrate/primitives/api/proc-macro/src/runtime_metadata.rs +++ b/substrate/primitives/api/proc-macro/src/runtime_metadata.rs @@ -17,7 +17,7 @@ use proc_macro2::TokenStream as TokenStream2; use quote::quote; -use syn::{parse_quote, spanned::Spanned, ItemImpl, ItemTrait, Result}; +use syn::{parse_quote, spanned::Spanned, ItemImpl, ItemTrait, Result, TypePath}; use crate::utils::{ extract_api_version, extract_impl_trait, filter_cfg_attributes, generate_crate_access, @@ -190,12 +190,17 @@ pub fn generate_decl_runtime_metadata<'a>( ) } +pub(crate) enum Kind<'a> { + Main(&'a [TypePath]), + Ext, +} + /// Implement the `runtime_metadata` function on the runtime that /// generates the metadata for the given traits. /// /// The metadata of each trait is extracted from the generic function /// exposed by `generate_decl_runtime_metadata`. -pub fn generate_impl_runtime_metadata(impls: &[ItemImpl]) -> Result { +pub fn generate_impl_runtime_metadata(impls: &[ItemImpl], kind: Kind) -> Result { if impls.is_empty() { return Ok(quote!()); } @@ -298,14 +303,30 @@ pub fn generate_impl_runtime_metadata(impls: &[ItemImpl]) -> Result #crate_::vec::Vec<#crate_::metadata_ir::RuntimeApiMetadataIR> { - #crate_::vec![ #( #metadata, )* ] + let block = match kind { + Kind::Main(paths) => { + quote! { + #[doc(hidden)] + impl #crate_::metadata_ir::InternalImplRuntimeApis for #runtime_name { + fn runtime_metadata(&self) -> #crate_::vec::Vec<#crate_::metadata_ir::RuntimeApiMetadataIR> { + let other_apis: #crate_::vec::Vec<#crate_::metadata_ir::RuntimeApiMetadataIR> = #crate_::vec::Vec::from([#crate_::vec![ #( #metadata, )*], #(#paths::runtime_metadata(),)*]).concat(); + other_apis + } } } + }, + Kind::Ext => quote! { + #[doc(hidden)] + #[inline(always)] + pub fn runtime_metadata() -> #crate_::vec::Vec<#crate_::metadata_ir::RuntimeApiMetadataIR> { + #crate_::vec![ #( #metadata, )* ] + } + + }, + }; + Ok(quote!( + #crate_::frame_metadata_enabled! { + #block } )) } diff --git a/substrate/primitives/api/src/lib.rs b/substrate/primitives/api/src/lib.rs index b412d4b52fed..fd5542f1f942 100644 --- a/substrate/primitives/api/src/lib.rs +++ b/substrate/primitives/api/src/lib.rs @@ -523,6 +523,9 @@ pub use sp_api_proc_macro::impl_runtime_apis; /// ``` pub use sp_api_proc_macro::mock_impl_runtime_apis; +/// Ass +pub use sp_api_proc_macro::impl_runtime_apis_ext; + /// A type that records all accessed trie nodes and generates a proof out of it. #[cfg(feature = "std")] pub type ProofRecorder = sp_trie::recorder::Recorder>; @@ -848,3 +851,4 @@ decl_runtime_apis! { sp_core::generate_feature_enabled_macro!(std_enabled, feature = "std", $); sp_core::generate_feature_enabled_macro!(std_disabled, not(feature = "std"), $); sp_core::generate_feature_enabled_macro!(frame_metadata_enabled, feature = "frame-metadata", $); +pub trait RuntimeBase {} diff --git a/substrate/primitives/api/test/tests/decl_and_impl.rs b/substrate/primitives/api/test/tests/decl_and_impl.rs index 2e5a078cb382..11441ae6ade2 100644 --- a/substrate/primitives/api/test/tests/decl_and_impl.rs +++ b/substrate/primitives/api/test/tests/decl_and_impl.rs @@ -25,7 +25,6 @@ use substrate_test_runtime_client::runtime::{Block, Hash}; /// The declaration of the `Runtime` type is done by the `construct_runtime!` macro in a real /// runtime. pub struct Runtime {} - decl_runtime_apis! { pub trait Api { fn test(data: u64); @@ -42,6 +41,10 @@ decl_runtime_apis! { fn same_name() -> String; } + pub trait Example { + fn same_name() -> String; + } + #[api_version(2)] pub trait ApiWithMultipleVersions { fn stable_one(data: u64); @@ -143,6 +146,18 @@ impl_runtime_apis! { unimplemented!() } } + + pub use ext::*; +} + +#[sp_api::impl_runtime_apis_ext] +mod ext { + use super::*; + impl super::Example for Runtime { + fn same_name() -> String { + "example".to_string() + } + } } struct MockApi { @@ -236,7 +251,7 @@ fn check_runtime_api_info() { } fn check_runtime_api_versions_contains() { - assert!(RUNTIME_API_VERSIONS.iter().any(|v| v == &(T::ID, T::VERSION))); + assert!(self::runtime_api_versions().iter().any(|v| v == &(T::ID, T::VERSION))); } fn check_staging_runtime_api_versions(_staging_ver: u32) { @@ -366,4 +381,10 @@ fn runtime_api_metadata_matches_version_implemented() { "staging_one", ], ); + assert_has_api_with_methods("Example", &["same_name"]); +} + +#[test] +fn runtime_api_works_with_ext() { + check_runtime_api_versions_contains::>(); } From 50a45d2ee83c93b1cd82d0ceeabec0ae22b5d9ea Mon Sep 17 00:00:00 2001 From: Pavlo Khrystenko Date: Mon, 9 Dec 2024 11:47:33 +0100 Subject: [PATCH 02/15] clippy --- substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs index d5a5dc8fb26a..32d4683f3dd5 100644 --- a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -1039,7 +1039,7 @@ mod tests { }; // Parse the items - let RuntimeApiImpls { impls: mut api_impls, uses } = + let RuntimeApiImpls { impls: mut api_impls, uses : _ } = syn::parse2::(code).unwrap(); // Run the renamer which is being run first in the `impl_runtime_apis!` macro. From 640c06c7c9b2783020a616a7ddf056f7eb6bc4ec Mon Sep 17 00:00:00 2001 From: Pavlo Khrystenko Date: Wed, 11 Dec 2024 01:24:50 +0100 Subject: [PATCH 03/15] docstrings --- substrate/primitives/api/src/lib.rs | 85 ++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/substrate/primitives/api/src/lib.rs b/substrate/primitives/api/src/lib.rs index fd5542f1f942..981e3eae61f9 100644 --- a/substrate/primitives/api/src/lib.rs +++ b/substrate/primitives/api/src/lib.rs @@ -415,6 +415,22 @@ pub use sp_api_proc_macro::decl_runtime_apis; /// // impl skipped /// } /// ``` +/// +/// # Importing implementations defined using `sp_api::impl_runtime_apis_ext` +/// +/// `impl_runtime_apis!` allows the user to define implementaions in multiple modules/blocks +/// through `impl_runtime_apis_ext` and including them through a `use` inside the block. +/// ```ignore +/// sp_api::impl_runtime_apis! { +/// impl self::ExampleApi for Runtime { +/// fn stable_one(_: u64) {} +/// +/// #[cfg(feature = "enable-staging-api")] +/// fn staging_one() {} +/// } +/// use path::to::the::extension::module::*; +/// } +/// ``` pub use sp_api_proc_macro::impl_runtime_apis; /// Mocks given trait implementations as runtime apis. @@ -523,7 +539,74 @@ pub use sp_api_proc_macro::impl_runtime_apis; /// ``` pub use sp_api_proc_macro::mock_impl_runtime_apis; -/// Ass +/// Tags given trait implementations as runtime apis in an extension module. +/// +/// All traits given to this macro, need to be declared with the +/// [`decl_runtime_apis!`](macro.decl_runtime_apis.html) macro. The implementation of the trait +/// should follow the declaration given to the +/// [`decl_runtime_apis!`](macro.decl_runtime_apis.html) macro, besides the `Block` type that +/// is required as first generic parameter for each runtime api trait. When implementing a +/// runtime api trait, it is required that the trait is referenced by a path, e.g. `impl +/// my_trait::MyTrait for Runtime`. The macro will use this path to access the declaration of +/// the trait for the runtime side. +/// +/// # Usage +/// +/// This macro follows the same rules and structure as `impl_runtime_apis!` except for a few +/// differnces: +/// - It is a proc-macro attribute that needs to be used on a module within a file. +/// - It doesn't generate base RuntimeApi scaffolding as `impl_runtime_apis!`. +/// - To be effectively visible from `impl_runtime_apis!` it needs to be imported inside of it +/// through `pub use`/`use`. +/// +/// # Example +/// +/// ```ignore +/// pub enum Runtime {} +/// +/// sp_api::decl_runtime_apis! { +/// /// Declare the api trait. +/// pub trait Balance { +/// /// Get the balance. +/// fn get_balance() -> u64; +/// /// Set the balance. +/// fn set_balance(val: u64); +/// } +/// pub trait BlockBuilder { +/// fn build_block() -> Block; +/// } +/// } +/// +/// sp_api::impl_runtime_apis! { +/// impl sp_api::Core for Runtime { +/// fn version() -> sp_version::RuntimeVersion { +/// unimplemented!() +/// } +/// fn execute_block(_block: Block) {} +/// fn initialize_block(_header: &::Header) -> ExtrinsicInclusionMode { +/// unimplemented!() +/// } +/// } +/// // Using the code declared inside `extensions` module. +/// pub use extensions::*; +/// impl self::BlockBuilder for Runtime { +/// fn build_block() -> Block { +/// unimplemented!("Please implement me!") +/// } +/// } +/// } +/// #[impl_runtime_apis_ext] +/// mod extensions { +/// impl self::Balance for Runtime { +/// fn get_balance() -> u64 { +/// 1 +/// } +/// fn set_balance(_bal: u64) { +/// // Store the balance +/// } +/// } +/// } +/// ``` pub use sp_api_proc_macro::impl_runtime_apis_ext; /// A type that records all accessed trie nodes and generates a proof out of it. From 4f9b6ef11a989696620e02a749cc92fc90752117 Mon Sep 17 00:00:00 2001 From: Pavlo Khrystenko Date: Wed, 11 Dec 2024 02:02:06 +0100 Subject: [PATCH 04/15] ui test --- .../api/proc-macro/src/impl_runtime_apis.rs | 33 ++++++---- .../tests/ui/incorrect_extension_import.rs | 61 +++++++++++++++++++ .../ui/incorrect_extension_import.stderr | 21 +++++++ 3 files changed, 104 insertions(+), 11 deletions(-) create mode 100644 substrate/primitives/api/test/tests/ui/incorrect_extension_import.rs create mode 100644 substrate/primitives/api/test/tests/ui/incorrect_extension_import.stderr diff --git a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs index 32d4683f3dd5..8a582e171fb7 100644 --- a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -867,27 +867,38 @@ fn impl_runtime_apis_impl_inner( let runtime_api_versions = generate_runtime_api_versions(api_impls)?; let wasm_interface = generate_wasm_interface(api_impls)?; let api_impls_for_runtime_api = generate_api_impl_for_runtime_api(api_impls)?; - let modules: Vec = uses + let modules = match uses .iter() .map(|item| { let mut path: Vec = vec![]; - fn call(path: &mut Vec, item: &UseTree) { + fn call(path: &mut Vec, item: &UseTree) -> Result<()> { match &item { syn::UseTree::Path(use_path) => { path.push(use_path.ident.clone()); - call(path, use_path.tree.as_ref()); + call(path, use_path.tree.as_ref()) + }, + syn::UseTree::Glob(_) => Ok(()), + syn::UseTree::Name(_) | syn::UseTree::Rename(_) | syn::UseTree::Group(_) => { + let error = Error::new( + item.span(), + "Unsupported syntax used to import api implementaions from an extension module. \ + Try using `pub use ::*` or `use ::*`", + ); + return Err(error) }, - syn::UseTree::Glob(_) => (), - syn::UseTree::Name(_) | syn::UseTree::Rename(_) | syn::UseTree::Group(_) => - unimplemented!(), } } - call(&mut path, &item.tree); + call(&mut path, &item.tree)?; let tok = quote::quote! {#(#path)::*}; - syn::parse::(tok.into()).unwrap() + Ok(syn::parse::(tok.into()) + .expect("Can't happen, a valid TypePath was used in the `UseTree`")) }) - .collect(); - + .collect::>>() + .map_err(|e| e.into_compile_error()) + { + Ok(items) => items, + Err(e) => return Ok(e), + }; let dispatch_impl = generate_dispatch_function(api_impls, Kind::Main(&modules))?; let runtime_metadata = @@ -1039,7 +1050,7 @@ mod tests { }; // Parse the items - let RuntimeApiImpls { impls: mut api_impls, uses : _ } = + let RuntimeApiImpls { impls: mut api_impls, uses: _ } = syn::parse2::(code).unwrap(); // Run the renamer which is being run first in the `impl_runtime_apis!` macro. diff --git a/substrate/primitives/api/test/tests/ui/incorrect_extension_import.rs b/substrate/primitives/api/test/tests/ui/incorrect_extension_import.rs new file mode 100644 index 000000000000..96cbf1206171 --- /dev/null +++ b/substrate/primitives/api/test/tests/ui/incorrect_extension_import.rs @@ -0,0 +1,61 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use sp_runtime::traits::Block as BlockT; +use substrate_test_runtime_client::runtime::Block; + +struct Runtime {} + +sp_api::decl_runtime_apis! { + #[api_version(2)] + pub trait Api { + fn test1(); + fn test2(); + #[api_version(3)] + fn test3(); + #[api_version(4)] + fn test4(); + } +} + +sp_api::impl_runtime_apis! { + impl sp_api::Core for Runtime { + fn version() -> sp_version::RuntimeVersion { + unimplemented!() + } + fn execute_block(_: Block) { + unimplemented!() + } + fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { + unimplemented!() + } + } + + use example::{api, *}; +} + +#[sp_api::impl_runtime_apis_ext] +mod example { + use super::*; + #[api_version(2)] + impl self::Api for Runtime { + fn test1() {} + fn test2() {} + } +} + +fn main() {} diff --git a/substrate/primitives/api/test/tests/ui/incorrect_extension_import.stderr b/substrate/primitives/api/test/tests/ui/incorrect_extension_import.stderr new file mode 100644 index 000000000000..8eaa6dbc0456 --- /dev/null +++ b/substrate/primitives/api/test/tests/ui/incorrect_extension_import.stderr @@ -0,0 +1,21 @@ +error: Unsupported syntax used to import api implementaions from an extension module. Try using `pub use ::*` or `use ::*` + --> tests/ui/incorrect_extension_import.rs:48:15 + | +48 | use example::{api, *}; + | ^^^^^^^^ + +error[E0412]: cannot find type `RuntimeApiImpl` in this scope + --> tests/ui/incorrect_extension_import.rs:51:1 + | +51 | #[sp_api::impl_runtime_apis_ext] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | + = note: this error originates in the attribute macro `sp_api::impl_runtime_apis_ext` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: unused import: `sp_runtime::traits::Block` + --> tests/ui/incorrect_extension_import.rs:18:5 + | +18 | use sp_runtime::traits::Block as BlockT; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` on by default From f0f1f738d2fe92ca2e596a28f30572509cc74be2 Mon Sep 17 00:00:00 2001 From: Pavlo Khrystenko Date: Wed, 11 Dec 2024 10:03:28 +0100 Subject: [PATCH 05/15] add silencing for imports --- substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs index 8a582e171fb7..de88cc83c969 100644 --- a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -907,7 +907,10 @@ fn impl_runtime_apis_impl_inner( let c = generate_crate_access(); let impl_ = quote!( - #(#uses)* + #( + #[allow(unused_imports)] + #uses + )* #base_runtime_api From 7810da508808007251e54c9609bab83eb0abd4eb Mon Sep 17 00:00:00 2001 From: Pavlo Khrystenko Date: Thu, 12 Dec 2024 17:35:44 +0100 Subject: [PATCH 06/15] bug fix with visibility --- .../support/test/tests/runtime_metadata.rs | 32 +++++++++---------- .../api/proc-macro/src/impl_runtime_apis.rs | 20 ++++++------ 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/substrate/frame/support/test/tests/runtime_metadata.rs b/substrate/frame/support/test/tests/runtime_metadata.rs index 0d3e864d78f3..0470c05debb7 100644 --- a/substrate/frame/support/test/tests/runtime_metadata.rs +++ b/substrate/frame/support/test/tests/runtime_metadata.rs @@ -82,7 +82,7 @@ sp_api::decl_runtime_apis! { // Module to emulate having the implementation in a different file. mod apis { - use super::{Block, BlockT, Runtime}; + use super::{ext, Block, Runtime}; sp_api::impl_runtime_apis! { impl crate::Api for Runtime { @@ -104,22 +104,22 @@ mod apis { } pub use ext::*; } +} - #[sp_api::impl_runtime_apis_ext] - mod ext { - use super::*; - impl sp_api::Core for Runtime { - fn version() -> sp_version::RuntimeVersion { - unimplemented!() - } - fn execute_block(_: Block) { - unimplemented!() - } - fn initialize_block( - _: &::Header, - ) -> sp_runtime::ExtrinsicInclusionMode { - unimplemented!() - } +#[sp_api::impl_runtime_apis_ext] +mod ext { + use super::*; + use crate::apis::RuntimeApiImpl; + + impl sp_api::Core for Runtime { + fn version() -> sp_version::RuntimeVersion { + unimplemented!() + } + fn execute_block(_: Block) { + unimplemented!() + } + fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { + unimplemented!() } } } diff --git a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs index de88cc83c969..c4be1e63ff68 100644 --- a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -294,13 +294,13 @@ fn generate_runtime_api_base_structures() -> Result { #crate_::std_enabled! { /// Implements all runtime apis for the client side. pub struct RuntimeApiImpl + 'static> { - call: &'static C, - transaction_depth: std::cell::RefCell, - changes: std::cell::RefCell<#crate_::OverlayedChanges<#crate_::HashingFor>>, - recorder: std::option::Option<#crate_::ProofRecorder>, - call_context: #crate_::CallContext, - extensions: std::cell::RefCell<#crate_::Extensions>, - extensions_generated_for: std::cell::RefCell>, + pub(crate) call: &'static C, + pub(crate) transaction_depth: std::cell::RefCell, + pub(crate) changes: std::cell::RefCell<#crate_::OverlayedChanges<#crate_::HashingFor>>, + pub(crate) recorder: std::option::Option<#crate_::ProofRecorder>, + pub(crate) call_context: #crate_::CallContext, + pub(crate) extensions: std::cell::RefCell<#crate_::Extensions>, + pub(crate) extensions_generated_for: std::cell::RefCell>, } #[automatically_derived] @@ -404,7 +404,7 @@ fn generate_runtime_api_base_structures() -> Result { { type RuntimeApi = RuntimeApiImpl; - fn construct_runtime_api<'a>( + fn construct_runtime_api<'a>( call: &'a C, ) -> #crate_::ApiRef<'a, Self::RuntimeApi> { RuntimeApiImpl { @@ -421,7 +421,7 @@ fn generate_runtime_api_base_structures() -> Result { #[automatically_derived] impl> RuntimeApiImpl { - fn commit_or_rollback_transaction(&self, commit: bool) { + pub(crate) fn commit_or_rollback_transaction(&self, commit: bool) { let proof = "\ We only close a transaction when we opened one ourself. Other parts of the runtime that make use of transactions (state-machine) @@ -461,7 +461,7 @@ fn generate_runtime_api_base_structures() -> Result { std::result::Result::expect(res, proof); } - fn start_transaction(&self) { + pub(crate) fn start_transaction(&self) { #crate_::OverlayedChanges::start_transaction( &mut std::cell::RefCell::borrow_mut(&self.changes) ); From 201167d0f682bdac42b0af95ed9a90f0a09ee400 Mon Sep 17 00:00:00 2001 From: Pavlo Khrystenko Date: Mon, 16 Dec 2024 16:04:33 +0100 Subject: [PATCH 07/15] add prdoc --- prdoc/pr_6795.prdoc | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 prdoc/pr_6795.prdoc diff --git a/prdoc/pr_6795.prdoc b/prdoc/pr_6795.prdoc new file mode 100644 index 000000000000..e21b0919c697 --- /dev/null +++ b/prdoc/pr_6795.prdoc @@ -0,0 +1,21 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: ... + +doc: + - audience: Runtime Dev + description: | + Makes possible to split internals of `sp_api::impl_runtime_apis!` into multiple blocks. + to do this user is required to use `sp_api::impl_runtime_apis_ext` proc-macro attribute on a + module that defines additional `impl` items that will be included in `impl_runtime_apis!` through `use ::*` declarations. + + +crates: +- name: sp-api + bump: major +- name: sp-api-proc-macro + bump: major +- name: frame-support + bump: major + From 543444ca33676f31db2ab2e7c92a3410894444a7 Mon Sep 17 00:00:00 2001 From: Pavlo Khrystenko Date: Wed, 8 Jan 2025 17:02:11 +0100 Subject: [PATCH 08/15] review comments --- substrate/primitives/api/output.rs | 0 .../api/proc-macro/src/impl_runtime_apis.rs | 145 +++++++++++------- .../api/proc-macro/src/runtime_metadata.rs | 4 +- .../api/test/tests/decl_and_impl.rs | 23 ++- 4 files changed, 109 insertions(+), 63 deletions(-) create mode 100644 substrate/primitives/api/output.rs diff --git a/substrate/primitives/api/output.rs b/substrate/primitives/api/output.rs new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs index c4be1e63ff68..701b6dfbca7f 100644 --- a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -44,7 +44,13 @@ use std::collections::HashMap; /// The structure used for parsing the runtime api implementations. struct RuntimeApiImpls { impls: Vec, - uses: Vec, + uses: Vec, +} + +mod custom_kw { + use syn::custom_keyword; + + custom_keyword!(external_impls); } impl Parse for RuntimeApiImpls { @@ -52,9 +58,15 @@ impl Parse for RuntimeApiImpls { let mut impls = Vec::new(); let mut uses = Vec::new(); while !input.is_empty() { - if input.peek(syn::Token![use]) || input.peek2(syn::Token![use]) { - let item = input.parse::()?; - uses.push(item); + if input.peek(custom_kw::external_impls) || input.peek2(syn::Token![!]) { + let content; + input.parse::()?; + input.parse::()?; + syn::braced!(content in input); + let items = content.parse_terminated(syn::TypePath::parse, syn::Token![,])?; + for item in items.into_iter() { + uses.push(item) + } } else { impls.push(input.parse::()?); } @@ -221,7 +233,7 @@ fn generate_dispatch_function(impls: &[ItemImpl], kind: Kind) -> Result Result { let api_ver = api_ver.map(|a| quote!( #a )).unwrap_or_else(|| base_api_version); populate_runtime_api_versions(&mut result, &mut sections, attrs, id, api_ver, &c); } - Ok(quote!( - pub const RUNTIME_API_VERSIONS: #c::ApisVec = #c::create_apis_vec!([ #( #result ),* ]); + pub const PARTIAL_RUNTIME_API_VERSIONS: &[([u8;8], u32)] = &[ #( #result ),* ]; #( #sections )* )) @@ -856,9 +867,27 @@ pub fn impl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::Tok .into() } +fn parse_path(path: &mut Vec, item: &UseTree) -> Result<()> { + match &item { + syn::UseTree::Path(use_path) => { + path.push(use_path.ident.clone()); + parse_path(path, use_path.tree.as_ref()) + }, + syn::UseTree::Glob(_) => Ok(()), + syn::UseTree::Name(_) | syn::UseTree::Rename(_) | syn::UseTree::Group(_) => { + let error = Error::new( + item.span(), + "Unsupported syntax used to import api implementaions from an extension module. \ + Try using `pub use ::*` or `use ::*`", + ); + return Err(error) + }, + } +} + fn impl_runtime_apis_impl_inner( api_impls: &mut [ItemImpl], - uses: &[ItemUse], + uses: &[TypePath], ) -> Result { rename_self_in_trait_impls(api_impls); @@ -867,49 +896,48 @@ fn impl_runtime_apis_impl_inner( let runtime_api_versions = generate_runtime_api_versions(api_impls)?; let wasm_interface = generate_wasm_interface(api_impls)?; let api_impls_for_runtime_api = generate_api_impl_for_runtime_api(api_impls)?; - let modules = match uses - .iter() - .map(|item| { - let mut path: Vec = vec![]; - fn call(path: &mut Vec, item: &UseTree) -> Result<()> { - match &item { - syn::UseTree::Path(use_path) => { - path.push(use_path.ident.clone()); - call(path, use_path.tree.as_ref()) - }, - syn::UseTree::Glob(_) => Ok(()), - syn::UseTree::Name(_) | syn::UseTree::Rename(_) | syn::UseTree::Group(_) => { - let error = Error::new( - item.span(), - "Unsupported syntax used to import api implementaions from an extension module. \ - Try using `pub use ::*` or `use ::*`", - ); - return Err(error) - }, - } - } - call(&mut path, &item.tree)?; - let tok = quote::quote! {#(#path)::*}; - Ok(syn::parse::(tok.into()) - .expect("Can't happen, a valid TypePath was used in the `UseTree`")) - }) - .collect::>>() - .map_err(|e| e.into_compile_error()) - { - Ok(items) => items, - Err(e) => return Ok(e), - }; - let dispatch_impl = generate_dispatch_function(api_impls, Kind::Main(&modules))?; + let dispatch_impl = generate_dispatch_function(api_impls, Kind::Main(&uses))?; let runtime_metadata = - crate::runtime_metadata::generate_impl_runtime_metadata(api_impls, Kind::Main(&modules))?; + crate::runtime_metadata::generate_impl_runtime_metadata(api_impls, Kind::Main(&uses))?; let c = generate_crate_access(); - let impl_ = quote!( + let runtime_api_versions_full = quote! { + + pub const RUNTIME_API_VERSIONS: #c::ApisVec = { + const LEN: usize = #(#uses::internal::PARTIAL_RUNTIME_API_VERSIONS.len() + )* PARTIAL_RUNTIME_API_VERSIONS.len() + 0; + const ARR: [([u8;8], u32); LEN] = { + let mut arr: [([u8;8], u32); LEN] = [([0;8],0); LEN]; + let mut base: usize = 0; + { + let mut i = 0; + while i < PARTIAL_RUNTIME_API_VERSIONS.len() { + arr[base + i] = PARTIAL_RUNTIME_API_VERSIONS[i]; + i += 1; + } + base += PARTIAL_RUNTIME_API_VERSIONS.len(); + } + #({ + let s = #uses::internal::PARTIAL_RUNTIME_API_VERSIONS; + let mut i = 0; + while i < s.len() { + arr[base + i] = s[i]; + i += 1; + } + base += s.len(); + })* + if base != LEN { panic!("invalid length"); } + arr + }; + #c::create_apis_vec!(ARR) + }; + }; + + let impl_ = quote! { #( #[allow(unused_imports)] - #uses + pub use #uses::*; )* #base_runtime_api @@ -922,10 +950,7 @@ fn impl_runtime_apis_impl_inner( #runtime_metadata - pub fn runtime_api_versions() -> #c::ApisVec { - let api = #c::vec::Vec::from([RUNTIME_API_VERSIONS.into_owned(), #(#modules::RUNTIME_API_VERSIONS.into_owned()),*]).concat(); - api.into() - } + #runtime_api_versions_full pub mod api { use super::*; @@ -934,7 +959,7 @@ fn impl_runtime_apis_impl_inner( #wasm_interface } - ); + }; let impl_ = expander::Expander::new("impl_runtime_apis") .dry(std::env::var("EXPAND_MACROS").is_err()) @@ -963,7 +988,7 @@ pub fn impl_runtime_apis_impl_ext(input: proc_macro::TokenStream) -> proc_macro: fn impl_runtime_apis_impl_inner_ext( module: Ident, api_impls: &mut [ItemImpl], - uses: &[ItemUse], + uses: &[TypePath], ) -> Result { rename_self_in_trait_impls(api_impls); let dispatch_impl = generate_dispatch_function(api_impls, Kind::Ext)?; @@ -976,22 +1001,28 @@ fn impl_runtime_apis_impl_inner_ext( crate::runtime_metadata::generate_impl_runtime_metadata(api_impls, Kind::Ext)?; let impl_ = quote!( pub mod #module { - #(#uses)* + #( + pub use #uses::*; + )* #api_impls_for_runtime #api_impls_for_runtime_api - #runtime_api_versions + pub mod internal { + use super::*; - #runtime_metadata + #runtime_api_versions - pub mod api { - use super::*; + #runtime_metadata - #dispatch_impl + pub mod api { + use super::*; - #wasm_interface + #dispatch_impl + + #wasm_interface + } } } ); diff --git a/substrate/primitives/api/proc-macro/src/runtime_metadata.rs b/substrate/primitives/api/proc-macro/src/runtime_metadata.rs index 1c594ff31467..e01c0ae73c94 100644 --- a/substrate/primitives/api/proc-macro/src/runtime_metadata.rs +++ b/substrate/primitives/api/proc-macro/src/runtime_metadata.rs @@ -309,7 +309,7 @@ pub fn generate_impl_runtime_metadata(impls: &[ItemImpl], kind: Kind) -> Result< #[doc(hidden)] impl #crate_::metadata_ir::InternalImplRuntimeApis for #runtime_name { fn runtime_metadata(&self) -> #crate_::vec::Vec<#crate_::metadata_ir::RuntimeApiMetadataIR> { - let other_apis: #crate_::vec::Vec<#crate_::metadata_ir::RuntimeApiMetadataIR> = #crate_::vec::Vec::from([#crate_::vec![ #( #metadata, )*], #(#paths::runtime_metadata(),)*]).concat(); + let other_apis: #crate_::vec::Vec<#crate_::metadata_ir::RuntimeApiMetadataIR> = #crate_::vec::Vec::from([#crate_::vec![ #( #metadata, )*], #(#paths::internal::partial_metadata(),)*]).concat(); other_apis } } @@ -318,7 +318,7 @@ pub fn generate_impl_runtime_metadata(impls: &[ItemImpl], kind: Kind) -> Result< Kind::Ext => quote! { #[doc(hidden)] #[inline(always)] - pub fn runtime_metadata() -> #crate_::vec::Vec<#crate_::metadata_ir::RuntimeApiMetadataIR> { + pub fn partial_metadata() -> #crate_::vec::Vec<#crate_::metadata_ir::RuntimeApiMetadataIR> { #crate_::vec![ #( #metadata, )* ] } diff --git a/substrate/primitives/api/test/tests/decl_and_impl.rs b/substrate/primitives/api/test/tests/decl_and_impl.rs index 11441ae6ade2..e7651b71621c 100644 --- a/substrate/primitives/api/test/tests/decl_and_impl.rs +++ b/substrate/primitives/api/test/tests/decl_and_impl.rs @@ -45,6 +45,10 @@ decl_runtime_apis! { fn same_name() -> String; } + pub trait Example2 { + fn same_name() -> String; + } + #[api_version(2)] pub trait ApiWithMultipleVersions { fn stable_one(data: u64); @@ -146,13 +150,13 @@ impl_runtime_apis! { unimplemented!() } } - - pub use ext::*; + external_impls!{ext, ext2} } #[sp_api::impl_runtime_apis_ext] mod ext { - use super::*; + external_impls! {super} + impl super::Example for Runtime { fn same_name() -> String { "example".to_string() @@ -160,6 +164,16 @@ mod ext { } } +#[sp_api::impl_runtime_apis_ext] +mod ext2 { + external_impls! {super} + impl super::Example2 for Runtime { + fn same_name() -> String { + "example".to_string() + } + } +} + struct MockApi { block: Option, } @@ -251,7 +265,7 @@ fn check_runtime_api_info() { } fn check_runtime_api_versions_contains() { - assert!(self::runtime_api_versions().iter().any(|v| v == &(T::ID, T::VERSION))); + assert!(RUNTIME_API_VERSIONS.iter().any(|v| v == &(T::ID, T::VERSION))); } fn check_staging_runtime_api_versions(_staging_ver: u32) { @@ -387,4 +401,5 @@ fn runtime_api_metadata_matches_version_implemented() { #[test] fn runtime_api_works_with_ext() { check_runtime_api_versions_contains::>(); + check_runtime_api_versions_contains::>(); } From 185b4b9cea295e20d88beb3e67c6c39c6b88611d Mon Sep 17 00:00:00 2001 From: Pavlo Khrystenko Date: Wed, 8 Jan 2025 17:03:54 +0100 Subject: [PATCH 09/15] cleanup --- .../api/proc-macro/src/impl_runtime_apis.rs | 21 +------------------ 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs index 701b6dfbca7f..ab242dcc4e93 100644 --- a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -35,8 +35,7 @@ use syn::{ parse_macro_input, parse_quote, spanned::Spanned, visit_mut::{self, VisitMut}, - Attribute, Ident, ImplItem, ItemImpl, ItemMod, ItemUse, Path, Signature, Type, TypePath, - UseTree, + Attribute, Ident, ImplItem, ItemImpl, ItemMod, Path, Signature, Type, TypePath, UseTree, }; use std::collections::HashMap; @@ -867,24 +866,6 @@ pub fn impl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::Tok .into() } -fn parse_path(path: &mut Vec, item: &UseTree) -> Result<()> { - match &item { - syn::UseTree::Path(use_path) => { - path.push(use_path.ident.clone()); - parse_path(path, use_path.tree.as_ref()) - }, - syn::UseTree::Glob(_) => Ok(()), - syn::UseTree::Name(_) | syn::UseTree::Rename(_) | syn::UseTree::Group(_) => { - let error = Error::new( - item.span(), - "Unsupported syntax used to import api implementaions from an extension module. \ - Try using `pub use ::*` or `use ::*`", - ); - return Err(error) - }, - } -} - fn impl_runtime_apis_impl_inner( api_impls: &mut [ItemImpl], uses: &[TypePath], From 4efa082df4a0aace819251dba13f12b0bc035813 Mon Sep 17 00:00:00 2001 From: Pavlo Khrystenko Date: Wed, 8 Jan 2025 17:05:29 +0100 Subject: [PATCH 10/15] rm expander placeholder --- substrate/primitives/api/output.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 substrate/primitives/api/output.rs diff --git a/substrate/primitives/api/output.rs b/substrate/primitives/api/output.rs deleted file mode 100644 index e69de29bb2d1..000000000000 From a101d578b2619642952ac7d34b14d29025550f4f Mon Sep 17 00:00:00 2001 From: Pavlo Khrystenko Date: Wed, 8 Jan 2025 17:09:29 +0100 Subject: [PATCH 11/15] update failing test --- .../api/test/tests/ui/incorrect_extension_import.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/substrate/primitives/api/test/tests/ui/incorrect_extension_import.rs b/substrate/primitives/api/test/tests/ui/incorrect_extension_import.rs index 96cbf1206171..abb81fb69590 100644 --- a/substrate/primitives/api/test/tests/ui/incorrect_extension_import.rs +++ b/substrate/primitives/api/test/tests/ui/incorrect_extension_import.rs @@ -45,12 +45,13 @@ sp_api::impl_runtime_apis! { } } - use example::{api, *}; + extension_impls!{ api } + use api::*; } #[sp_api::impl_runtime_apis_ext] mod example { - use super::*; + extension_impls! { super } #[api_version(2)] impl self::Api for Runtime { fn test1() {} From 7a50661bb134fd8b94748846c50d7eee3a9aee08 Mon Sep 17 00:00:00 2001 From: Pavlo Khrystenko Date: Wed, 8 Jan 2025 17:11:03 +0100 Subject: [PATCH 12/15] clippy --- substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs index ab242dcc4e93..930c02ade339 100644 --- a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -35,7 +35,7 @@ use syn::{ parse_macro_input, parse_quote, spanned::Spanned, visit_mut::{self, VisitMut}, - Attribute, Ident, ImplItem, ItemImpl, ItemMod, Path, Signature, Type, TypePath, UseTree, + Attribute, Ident, ImplItem, ItemImpl, ItemMod, Path, Signature, Type, TypePath, }; use std::collections::HashMap; From c8375d0470ef9c0a6e3064137d33abeefc4649b2 Mon Sep 17 00:00:00 2001 From: Pavlo Khrystenko Date: Wed, 8 Jan 2025 17:39:23 +0100 Subject: [PATCH 13/15] fixup --- .../api/proc-macro/src/impl_runtime_apis.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs index 930c02ade339..4ed2dc3461a1 100644 --- a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -67,7 +67,21 @@ impl Parse for RuntimeApiImpls { uses.push(item) } } else { - impls.push(input.parse::()?); + match input.parse::() { + Ok(res) => impls.push(res), + Err(e) => { + let mut error = syn::Error::new( + input.span(), + r#"Invalid syntax inside block. + supported item are: + - impl blocks + - references to other impl_api_blocks through `external_impls!{ } + "#, + ); + error.combine(e); + return Err(error) + }, + } } } From a104ae0971ff33cf67727f6dee4b3e7709e2e07f Mon Sep 17 00:00:00 2001 From: Pavlo Khrystenko Date: Fri, 10 Jan 2025 11:09:21 +0100 Subject: [PATCH 14/15] fixup --- substrate/frame/support/test/tests/runtime_metadata.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/substrate/frame/support/test/tests/runtime_metadata.rs b/substrate/frame/support/test/tests/runtime_metadata.rs index 0470c05debb7..9bda6f7d3936 100644 --- a/substrate/frame/support/test/tests/runtime_metadata.rs +++ b/substrate/frame/support/test/tests/runtime_metadata.rs @@ -102,14 +102,15 @@ mod apis { fn wild_card(_: u32) {} } - pub use ext::*; + + external_impls!{ext} } } #[sp_api::impl_runtime_apis_ext] mod ext { - use super::*; - use crate::apis::RuntimeApiImpl; + + external_impls! {super, crate::apis} impl sp_api::Core for Runtime { fn version() -> sp_version::RuntimeVersion { From 4960eccb7a523a4523763a8a1f6d65aef5a610db Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Fri, 10 Jan 2025 11:32:48 +0000 Subject: [PATCH 15/15] Update from pkhry running command 'update-ui' --- .../ui/incorrect_extension_import.stderr | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/substrate/primitives/api/test/tests/ui/incorrect_extension_import.stderr b/substrate/primitives/api/test/tests/ui/incorrect_extension_import.stderr index 8eaa6dbc0456..a7b0d2e7a70e 100644 --- a/substrate/primitives/api/test/tests/ui/incorrect_extension_import.stderr +++ b/substrate/primitives/api/test/tests/ui/incorrect_extension_import.stderr @@ -1,21 +1,26 @@ -error: Unsupported syntax used to import api implementaions from an extension module. Try using `pub use ::*` or `use ::*` - --> tests/ui/incorrect_extension_import.rs:48:15 +error: expected `external_impls` + --> tests/ui/incorrect_extension_import.rs:48:2 | -48 | use example::{api, *}; - | ^^^^^^^^ +48 | extension_impls!{ api } + | ^^^^^^^^^^^^^^^ -error[E0412]: cannot find type `RuntimeApiImpl` in this scope - --> tests/ui/incorrect_extension_import.rs:51:1 +error: expected `external_impls` + --> tests/ui/incorrect_extension_import.rs:54:2 | -51 | #[sp_api::impl_runtime_apis_ext] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope +54 | extension_impls! { super } + | ^^^^^^^^^^^^^^^ + +error: unused import: `substrate_test_runtime_client::runtime::Block` + --> tests/ui/incorrect_extension_import.rs:19:5 + | +19 | use substrate_test_runtime_client::runtime::Block; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: this error originates in the attribute macro `sp_api::impl_runtime_apis_ext` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: `-D unused-imports` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(unused_imports)]` -warning: unused import: `sp_runtime::traits::Block` +error: unused import: `sp_runtime::traits::Block` --> tests/ui/incorrect_extension_import.rs:18:5 | 18 | use sp_runtime::traits::Block as BlockT; | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(unused_imports)]` on by default