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