diff --git a/prdoc/pr_7412.prdoc b/prdoc/pr_7412.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..fd6bbea8654137266f634868e2f11f80117b1f99 --- /dev/null +++ b/prdoc/pr_7412.prdoc @@ -0,0 +1,16 @@ +title: 'Pallet view functions: improve metadata, API docs and testing' +doc: +- audience: Runtime Dev + description: |- + - refactor view functions metadata according to #6833 in preparation for V16, and move them to pallet-level metadata + - add `view_functions_experimental` macro to `pallet_macros` with API docs + - improve UI testing for view functions +crates: +- name: frame-support-procedural + bump: minor +- name: sp-metadata-ir + bump: major +- name: pallet-example-view-functions + bump: patch +- name: frame-support + bump: minor diff --git a/substrate/frame/examples/view-functions/src/lib.rs b/substrate/frame/examples/view-functions/src/lib.rs index e842a718ad33442b1f83a88963d637b2e6ca77bf..9cad8ab1bcdb0bd54a0f55263efcb1122a8c5c55 100644 --- a/substrate/frame/examples/view-functions/src/lib.rs +++ b/substrate/frame/examples/view-functions/src/lib.rs @@ -63,12 +63,12 @@ pub mod pallet { where T::AccountId: From<SomeType1> + SomeAssociation1, { - /// Query value no args. + /// Query value with no input args. pub fn get_value() -> Option<u32> { SomeValue::<T>::get() } - /// Query value with args. + /// Query value with input args. pub fn get_value_with_arg(key: u32) -> Option<u32> { SomeMap::<T>::get(key) } @@ -101,12 +101,12 @@ pub mod pallet2 { where T::AccountId: From<SomeType1> + SomeAssociation1, { - /// Query value no args. + /// Query value with no input args. pub fn get_value() -> Option<u32> { SomeValue::<T, I>::get() } - /// Query value with args. + /// Query value with input args. pub fn get_value_with_arg(key: u32) -> Option<u32> { SomeMap::<T, I>::get(key) } diff --git a/substrate/frame/examples/view-functions/src/tests.rs b/substrate/frame/examples/view-functions/src/tests.rs index 25f5f094651d6a085c041702118a8e69a5f7e4c1..01a2d15dc6cde67378c5ec597d8f31ad9c33fd65 100644 --- a/substrate/frame/examples/view-functions/src/tests.rs +++ b/substrate/frame/examples/view-functions/src/tests.rs @@ -23,11 +23,14 @@ use crate::{ pallet2, }; use codec::{Decode, Encode}; -use scale_info::{form::PortableForm, meta_type}; +use scale_info::meta_type; use frame_support::{derive_impl, pallet_prelude::PalletInfoAccess, view_functions::ViewFunction}; use sp_io::hashing::twox_128; -use sp_metadata_ir::{ViewFunctionArgMetadataIR, ViewFunctionGroupIR, ViewFunctionMetadataIR}; +use sp_metadata_ir::{ + DeprecationStatusIR, PalletViewFunctionMethodMetadataIR, + PalletViewFunctionMethodParamMetadataIR, +}; use sp_runtime::testing::TestXt; pub type AccountId = u32; @@ -111,8 +114,7 @@ fn metadata_ir_definitions() { new_test_ext().execute_with(|| { let metadata_ir = Runtime::metadata_ir(); let pallet1 = metadata_ir - .view_functions - .groups + .pallets .iter() .find(|pallet| pallet.name == "ViewFunctionsExample") .unwrap(); @@ -137,44 +139,30 @@ fn metadata_ir_definitions() { pretty_assertions::assert_eq!( pallet1.view_functions, vec![ - ViewFunctionMetadataIR { + PalletViewFunctionMethodMetadataIR { name: "get_value", id: get_value_id, - args: vec![], + inputs: vec![], output: meta_type::<Option<u32>>(), - docs: vec![" Query value no args."], + docs: vec![" Query value with no input args."], + deprecation_info: DeprecationStatusIR::NotDeprecated, }, - ViewFunctionMetadataIR { + PalletViewFunctionMethodMetadataIR { name: "get_value_with_arg", id: get_value_with_arg_id, - args: vec![ViewFunctionArgMetadataIR { name: "key", ty: meta_type::<u32>() },], + inputs: vec![PalletViewFunctionMethodParamMetadataIR { + name: "key", + ty: meta_type::<u32>() + },], output: meta_type::<Option<u32>>(), - docs: vec![" Query value with args."], + docs: vec![" Query value with input args."], + deprecation_info: DeprecationStatusIR::NotDeprecated, }, ] ); }); } -#[test] -fn metadata_encoded_to_custom_value() { - new_test_ext().execute_with(|| { - let metadata = sp_metadata_ir::into_latest(Runtime::metadata_ir()); - // metadata is currently experimental so lives as a custom value. - let frame_metadata::RuntimeMetadata::V15(v15) = metadata.1 else { - panic!("Expected metadata v15") - }; - let custom_value = v15 - .custom - .map - .get("view_functions_experimental") - .expect("Expected custom value"); - let view_function_groups: Vec<ViewFunctionGroupIR<PortableForm>> = - Decode::decode(&mut &custom_value.value[..]).unwrap(); - assert_eq!(view_function_groups.len(), 4); - }); -} - fn test_dispatch_view_function<Q, V>(query: &Q, expected: V) where Q: ViewFunction + Encode, diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs index d246c00628640d8dfd27a133a2c06637b3953eb8..be5678f4e5d291774b69619175e5af2feca75842 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs @@ -45,6 +45,7 @@ pub fn expand_runtime_metadata( let index = &decl.index; let storage = expand_pallet_metadata_storage(&filtered_names, runtime, decl); let calls = expand_pallet_metadata_calls(&filtered_names, runtime, decl); + let view_functions = expand_pallet_metadata_view_functions(runtime, decl); let event = expand_pallet_metadata_events(&filtered_names, runtime, decl); let constants = expand_pallet_metadata_constants(runtime, decl); let errors = expand_pallet_metadata_errors(runtime, decl); @@ -59,6 +60,7 @@ pub fn expand_runtime_metadata( index: #index, storage: #storage, calls: #calls, + view_functions: #view_functions, event: #event, constants: #constants, error: #errors, @@ -70,20 +72,6 @@ pub fn expand_runtime_metadata( }) .collect::<Vec<_>>(); - let view_functions = pallet_declarations.iter().map(|decl| { - let name = &decl.name; - let path = &decl.path; - let instance = decl.instance.as_ref().into_iter(); - let attr = decl.get_attributes(); - - quote! { - #attr - #path::Pallet::<#runtime #(, #path::#instance)*>::pallet_view_functions_metadata( - ::core::stringify!(#name) - ) - } - }); - quote! { impl #runtime { fn metadata_ir() -> #scrate::__private::metadata_ir::MetadataIR { @@ -156,10 +144,6 @@ pub fn expand_runtime_metadata( event_enum_ty: #scrate::__private::scale_info::meta_type::<RuntimeEvent>(), error_enum_ty: #scrate::__private::scale_info::meta_type::<RuntimeError>(), }, - view_functions: #scrate::__private::metadata_ir::RuntimeViewFunctionsIR { - ty: #scrate::__private::scale_info::meta_type::<RuntimeViewFunction>(), - groups: #scrate::__private::sp_std::vec![ #(#view_functions),* ], - } } } @@ -216,6 +200,15 @@ fn expand_pallet_metadata_calls( } } +fn expand_pallet_metadata_view_functions(runtime: &Ident, decl: &Pallet) -> TokenStream { + let path = &decl.path; + let instance = decl.instance.as_ref().into_iter(); + + quote! { + #path::Pallet::<#runtime #(, #path::#instance)*>::pallet_view_functions_metadata() + } +} + fn expand_pallet_metadata_events( filtered_names: &[&'static str], runtime: &Ident, diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/view_function.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/view_function.rs index 094dcca4a5b5249cfe3026790d9938a84f5649fe..df6b4c42a9b053018cfa90c4de5ec9a6eed5d25f 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/view_function.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/view_function.rs @@ -62,7 +62,7 @@ pub fn expand_outer_query( } impl #runtime_name { - /// Convenience function for query execution from the runtime API. + /// Convenience function for view functions dispatching and execution from the runtime API. pub fn execute_view_function( id: #scrate::view_functions::ViewFunctionId, input: #scrate::__private::Vec<::core::primitive::u8>, diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index 26703a2438ef9ad368c3718bc497c9563bb407fe..3a106aa05d51c23303100b59ebd34906cb9e5bb7 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -1091,6 +1091,16 @@ pub fn validate_unsigned(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } +/// +/// --- +/// +/// Documentation for this macro can be found at +/// `frame_support::pallet_macros::view_functions_experimental`. +#[proc_macro_attribute] +pub fn view_functions_experimental(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + /// /// --- /// diff --git a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs index 587e74a2ac182f2dc817db9bb6058e2c93611bc2..5838db9d89ddcf5dbae38fa9fcd2d42ad54df99f 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -20,14 +20,10 @@ use proc_macro2::{Span, TokenStream}; use syn::spanned::Spanned; pub fn expand_view_functions(def: &Def) -> TokenStream { - let (span, where_clause, view_fns, docs) = match def.view_functions.as_ref() { - Some(view_fns) => ( - view_fns.attr_span, - view_fns.where_clause.clone(), - view_fns.view_functions.clone(), - view_fns.docs.clone(), - ), - None => (def.item.span(), def.config.where_clause.clone(), Vec::new(), Vec::new()), + let (span, where_clause, view_fns) = match def.view_functions.as_ref() { + Some(view_fns) => + (view_fns.attr_span, view_fns.where_clause.clone(), view_fns.view_functions.clone()), + None => (def.item.span(), def.config.where_clause.clone(), Vec::new()), }; let view_function_prefix_impl = @@ -39,7 +35,7 @@ pub fn expand_view_functions(def: &Def) -> TokenStream { let impl_dispatch_view_function = impl_dispatch_view_function(def, span, where_clause.as_ref(), &view_fns); let impl_view_function_metadata = - impl_view_function_metadata(def, span, where_clause.as_ref(), &view_fns, &docs); + impl_view_function_metadata(def, span, where_clause.as_ref(), &view_fns); quote::quote! { #view_function_prefix_impl @@ -201,7 +197,6 @@ fn impl_view_function_metadata( span: Span, where_clause: Option<&syn::WhereClause>, view_fns: &[ViewFunctionDef], - docs: &[syn::Expr], ) -> TokenStream { let frame_support = &def.frame_support; let pallet_ident = &def.pallet_struct.pallet; @@ -211,14 +206,14 @@ fn impl_view_function_metadata( let view_functions = view_fns.iter().map(|view_fn| { let view_function_struct_ident = view_fn.view_function_struct_ident(); let name = &view_fn.name; - let args = view_fn.args.iter().filter_map(|fn_arg| { + let inputs = view_fn.args.iter().filter_map(|fn_arg| { match fn_arg { syn::FnArg::Receiver(_) => None, syn::FnArg::Typed(typed) => { let pat = &typed.pat; let ty = &typed.ty; Some(quote::quote! { - #frame_support::__private::metadata_ir::ViewFunctionArgMetadataIR { + #frame_support::__private::metadata_ir::PalletViewFunctionMethodParamMetadataIR { name: ::core::stringify!(#pat), ty: #frame_support::__private::scale_info::meta_type::<#ty>(), } @@ -230,33 +225,34 @@ fn impl_view_function_metadata( let no_docs = vec![]; let doc = if cfg!(feature = "no-metadata-docs") { &no_docs } else { &view_fn.docs }; + let deprecation = match crate::deprecation::get_deprecation( + "e::quote! { #frame_support }, + &def.item.attrs, + ) { + Ok(deprecation) => deprecation, + Err(e) => return e.into_compile_error(), + }; + quote::quote! { - #frame_support::__private::metadata_ir::ViewFunctionMetadataIR { + #frame_support::__private::metadata_ir::PalletViewFunctionMethodMetadataIR { name: ::core::stringify!(#name), id: <#view_function_struct_ident<#type_use_gen> as #frame_support::view_functions::ViewFunction>::id().into(), - args: #frame_support::__private::sp_std::vec![ #( #args ),* ], + inputs: #frame_support::__private::sp_std::vec![ #( #inputs ),* ], output: #frame_support::__private::scale_info::meta_type::< <#view_function_struct_ident<#type_use_gen> as #frame_support::view_functions::ViewFunction>::ReturnType >(), docs: #frame_support::__private::sp_std::vec![ #( #doc ),* ], + deprecation_info: #deprecation, } } }); - let no_docs = vec![]; - let doc = if cfg!(feature = "no-metadata-docs") { &no_docs } else { docs }; - quote::quote! { impl<#type_impl_gen> #pallet_ident<#type_use_gen> #where_clause { #[doc(hidden)] - pub fn pallet_view_functions_metadata(name: &'static ::core::primitive::str) - -> #frame_support::__private::metadata_ir::ViewFunctionGroupIR - { - #frame_support::__private::metadata_ir::ViewFunctionGroupIR { - name, - view_functions: #frame_support::__private::sp_std::vec![ #( #view_functions ),* ], - docs: #frame_support::__private::sp_std::vec![ #( #doc ),* ], - } + pub fn pallet_view_functions_metadata() + -> #frame_support::__private::Vec<#frame_support::__private::metadata_ir::PalletViewFunctionMethodMetadataIR> { + #frame_support::__private::vec![ #( #view_functions ),* ] } } } diff --git a/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs b/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs index 766bcb13da8b3cbddc164a8fdd2a2ecab066f6d4..469ee0fe5b795953177a668955cf69b04b10e22f 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs @@ -25,8 +25,6 @@ pub struct ViewFunctionsImplDef { pub where_clause: Option<syn::WhereClause>, /// The span of the pallet::view_functions_experimental attribute. pub attr_span: proc_macro2::Span, - /// Docs, specified on the impl Block. - pub docs: Vec<syn::Expr>, /// The view function definitions. pub view_functions: Vec<ViewFunctionDef>, } @@ -67,7 +65,6 @@ impl ViewFunctionsImplDef { view_functions, attr_span, where_clause: item_impl.generics.where_clause.clone(), - docs: get_doc_literals(&item_impl.attrs), }) } } diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 97d16e2a06d23349fe4ea653be73428dde976a68..cd3312ebfd860b03d99e1f1b6fac87bb81af4052 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -1709,6 +1709,61 @@ pub mod pallet_macros { /// in the future to give information directly to [`frame_support::construct_runtime`]. pub use frame_support_procedural::validate_unsigned; + /// Allows defining view functions on a pallet. + /// + /// A pallet view function is a read-only function providing access to the state of the + /// pallet from both outside and inside the runtime. It should provide a _stable_ interface + /// for querying the state of the pallet, avoiding direct storage access and upgrading + /// along with the runtime. + /// + /// ## Syntax + /// View functions methods must be read-only and always return some output. A + /// `view_functions_experimental` impl block only allows methods to be defined inside of + /// it. + /// + /// ## Example + /// ``` + /// #[frame_support::pallet] + /// pub mod pallet { + /// use frame_support::pallet_prelude::*; + /// + /// #[pallet::config] + /// pub trait Config: frame_system::Config {} + /// + /// #[pallet::pallet] + /// pub struct Pallet<T>(_); + /// + /// #[pallet::storage] + /// pub type SomeMap<T: Config> = StorageMap<_, Twox64Concat, u32, u32, OptionQuery>; + /// + /// #[pallet::view_functions_experimental] + /// impl<T: Config> Pallet<T> { + /// /// Retrieve a map storage value by key. + /// pub fn get_value_with_arg(key: u32) -> Option<u32> { + /// SomeMap::<T>::get(key) + /// } + /// } + /// } + /// ``` + /// + /// + /// ## Usage and implementation details + /// To allow outside access to pallet view functions, you need to add a runtime API that + /// accepts view function queries and dispatches them to the right pallet. You can do that + /// by implementing the + /// [`RuntimeViewFunction`](frame_support::view_functions::runtime_api::RuntimeViewFunction) + /// trait for the runtime inside an [`impl_runtime_apis!`](sp_api::impl_runtime_apis) + /// block. + /// + /// The `RuntimeViewFunction` trait implements a hashing-based dispatching mechanism to + /// dispatch view functions to the right method in the right pallet based on their IDs. A + /// view function ID depends both on its pallet and on its method signature, so it remains + /// stable as long as those two elements are not modified. In general, pallet view + /// functions should expose a _stable_ interface and changes to the method signature are + /// strongly discouraged. For more details on the dispatching mechanism, see the + /// [`DispatchViewFunction`](frame_support::view_functions::DispatchViewFunction) trait. + pub use frame_support_procedural::view_functions_experimental; + /// Allows defining a struct implementing the [`Get`](frame_support::traits::Get) trait to /// ease the use of storage types. /// diff --git a/substrate/frame/support/src/view_functions.rs b/substrate/frame/support/src/view_functions.rs index dd23fad94a4fd578bdc3d63f86bcb1a1750fe064..cba451b554eb67513a0ae56da1f63af581abadf6 100644 --- a/substrate/frame/support/src/view_functions.rs +++ b/substrate/frame/support/src/view_functions.rs @@ -63,6 +63,12 @@ impl From<codec::Error> for ViewFunctionDispatchError { /// Implemented by both pallets and the runtime. The runtime is dispatching by prefix using the /// pallet implementation of `ViewFunctionIdPrefix` then the pallet is dispatching by suffix using /// the methods implementation of `ViewFunctionIdSuffix`. +/// +/// In more details, `ViewFunctionId` = `ViewFunctionIdPrefix` ++ `ViewFunctionIdSuffix`, where +/// `ViewFunctionIdPrefix=twox_128(pallet_name)` and +/// `ViewFunctionIdSuffix=twox_128("fn_name(fnarg_types) -> return_ty")`. The prefix is the same as +/// the storage prefix for pallets. The suffix is generated from the view function method type +/// signature, so is guaranteed to be unique for that pallet implementation. pub trait DispatchViewFunction { fn dispatch_view_function<O: Output>( id: &ViewFunctionId, diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr index faa9cb558c262f09111a488a4e2f4bf114a74375..444096bd9a5b895649c1228144525074e063977e 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr @@ -620,7 +620,7 @@ note: the trait `Config` must be implemented | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0599]: the variant or associated item `event_metadata` exists for enum `Event<Runtime>`, but its trait bounds were not satisfied +error[E0599]: the function or associated item `pallet_view_functions_metadata` exists for struct `Pallet<Runtime>`, but its trait bounds were not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | construct_runtime! { @@ -634,7 +634,7 @@ error[E0599]: the variant or associated item `event_metadata` exists for enum `E ... | 27 | | } 28 | | } - | |__^ variant or associated item cannot be called on `Event<Runtime>` due to unsatisfied trait bounds + | |__^ function or associated item cannot be called on `Pallet<Runtime>` due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: `Runtime: Config` @@ -645,7 +645,7 @@ note: the trait `Config` must be implemented | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0599]: the function or associated item `pallet_constants_metadata` exists for struct `Pallet<Runtime>`, but its trait bounds were not satisfied +error[E0599]: the variant or associated item `event_metadata` exists for enum `Event<Runtime>`, but its trait bounds were not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | construct_runtime! { @@ -659,7 +659,7 @@ error[E0599]: the function or associated item `pallet_constants_metadata` exists ... | 27 | | } 28 | | } - | |__^ function or associated item cannot be called on `Pallet<Runtime>` due to unsatisfied trait bounds + | |__^ variant or associated item cannot be called on `Event<Runtime>` due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: `Runtime: Config` @@ -670,7 +670,7 @@ note: the trait `Config` must be implemented | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0599]: the function or associated item `error_metadata` exists for struct `Pallet<Runtime>`, but its trait bounds were not satisfied +error[E0599]: the function or associated item `pallet_constants_metadata` exists for struct `Pallet<Runtime>`, but its trait bounds were not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | construct_runtime! { @@ -695,7 +695,7 @@ note: the trait `Config` must be implemented | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0599]: the function or associated item `pallet_documentation_metadata` exists for struct `Pallet<Runtime>`, but its trait bounds were not satisfied +error[E0599]: the function or associated item `error_metadata` exists for struct `Pallet<Runtime>`, but its trait bounds were not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | construct_runtime! { @@ -720,7 +720,7 @@ note: the trait `Config` must be implemented | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0599]: the function or associated item `pallet_associated_types_metadata` exists for struct `Pallet<Runtime>`, but its trait bounds were not satisfied +error[E0599]: the function or associated item `pallet_documentation_metadata` exists for struct `Pallet<Runtime>`, but its trait bounds were not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | construct_runtime! { @@ -745,7 +745,7 @@ note: the trait `Config` must be implemented | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0599]: the function or associated item `pallet_view_functions_metadata` exists for struct `Pallet<Runtime>`, but its trait bounds were not satisfied +error[E0599]: the function or associated item `pallet_associated_types_metadata` exists for struct `Pallet<Runtime>`, but its trait bounds were not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | construct_runtime! { diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/view_function_valid.rs b/substrate/frame/support/test/tests/pallet_ui/pass/view_function_valid.rs new file mode 100644 index 0000000000000000000000000000000000000000..a4c3a6eb9baf563994c49046c0c3cbd79f429f51 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/pass/view_function_valid.rs @@ -0,0 +1,39 @@ +// 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. + +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + + #[pallet::config(with_default)] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet<T>(_); + + #[pallet::storage] + pub type MyStorage<T> = StorageValue<_, u32>; + + #[pallet::view_functions_experimental] + impl<T: Config> Pallet<T> { + pub fn get_value() -> Option<u32> { + MyStorage::<T>::get() + } + } +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/pallet_ui/view_function_invalid_item.rs b/substrate/frame/support/test/tests/pallet_ui/view_function_invalid_item.rs new file mode 100644 index 0000000000000000000000000000000000000000..81a794d9b0d6bd9c9bf3efb13c8dc8f8a9743e2b --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/view_function_invalid_item.rs @@ -0,0 +1,34 @@ +// 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. + +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + + #[pallet::config(with_default)] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet<T>(_); + + #[pallet::view_functions_experimental] + impl<T: Config> Pallet<T> { + pub const SECONDS_PER_MINUTE: u32 = 60; + } +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/pallet_ui/view_function_invalid_item.stderr b/substrate/frame/support/test/tests/pallet_ui/view_function_invalid_item.stderr new file mode 100644 index 0000000000000000000000000000000000000000..6afdf707fce60c933bcb30c1c0c6c396f56c545f --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/view_function_invalid_item.stderr @@ -0,0 +1,5 @@ +error: Invalid pallet::view_functions_experimental, expected a function + --> tests/pallet_ui/view_function_invalid_item.rs:30:3 + | +30 | pub const SECONDS_PER_MINUTE: u32 = 60; + | ^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/view_function_no_return.rs b/substrate/frame/support/test/tests/pallet_ui/view_function_no_return.rs new file mode 100644 index 0000000000000000000000000000000000000000..3356e354ca72cad0c0a648b52016c1347ce86d14 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/view_function_no_return.rs @@ -0,0 +1,39 @@ +// 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. + +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + + #[pallet::config(with_default)] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet<T>(_); + + #[pallet::storage] + pub type MyStorage<T> = StorageValue<_, u32>; + + #[pallet::view_functions_experimental] + impl<T: Config> Pallet<T> { + pub fn get_value() { + MyStorage::<T>::set(0); + } + } +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/pallet_ui/view_function_no_return.stderr b/substrate/frame/support/test/tests/pallet_ui/view_function_no_return.stderr new file mode 100644 index 0000000000000000000000000000000000000000..689253e1c6e7023bc82c7ae1db7afe65830f3700 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/view_function_no_return.stderr @@ -0,0 +1,5 @@ +error: view functions must return a value + --> tests/pallet_ui/view_function_no_return.rs:33:7 + | +33 | pub fn get_value() { + | ^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/view_function_not_public.rs b/substrate/frame/support/test/tests/pallet_ui/view_function_not_public.rs new file mode 100644 index 0000000000000000000000000000000000000000..e6611013335c628f5e736ad7c3ad9142d5ff7ac0 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/view_function_not_public.rs @@ -0,0 +1,39 @@ +// 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. + +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + + #[pallet::config(with_default)] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet<T>(_); + + #[pallet::storage] + pub type MyStorage<T> = StorageValue<_, u32>; + + #[pallet::view_functions_experimental] + impl<T: Config> Pallet<T> { + fn get_value() -> Option<u32> { + MyStorage::<T>::get() + } + } +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/pallet_ui/view_function_not_public.stderr b/substrate/frame/support/test/tests/pallet_ui/view_function_not_public.stderr new file mode 100644 index 0000000000000000000000000000000000000000..7b0688af07974d8476f869bb6aa01747886cd1bb --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/view_function_not_public.stderr @@ -0,0 +1,5 @@ +error: Invalid pallet::view_functions_experimental, view function must be public: `pub fn` + --> tests/pallet_ui/view_function_not_public.rs:33:3 + | +33 | fn get_value() -> Option<u32> { + | ^^ diff --git a/substrate/primitives/metadata-ir/src/lib.rs b/substrate/primitives/metadata-ir/src/lib.rs index e048010a34b75a7facb2cd0abe019eb305734096..dc01f7eaadb3337f1a4ff42322417d2e353ba299 100644 --- a/substrate/primitives/metadata-ir/src/lib.rs +++ b/substrate/primitives/metadata-ir/src/lib.rs @@ -122,7 +122,6 @@ mod test { event_enum_ty: meta_type::<()>(), error_enum_ty: meta_type::<()>(), }, - view_functions: RuntimeViewFunctionsIR { ty: meta_type::<()>(), groups: vec![] }, } } diff --git a/substrate/primitives/metadata-ir/src/types.rs b/substrate/primitives/metadata-ir/src/types.rs index 0617fc7dfb94f7d8c397d4ccbcd4219d400c488d..986925e6f516804d5f6028aaeec2fc3965a0f2b1 100644 --- a/substrate/primitives/metadata-ir/src/types.rs +++ b/substrate/primitives/metadata-ir/src/types.rs @@ -41,8 +41,6 @@ pub struct MetadataIR<T: Form = MetaForm> { pub apis: Vec<RuntimeApiMetadataIR<T>>, /// The outer enums types as found in the runtime. pub outer_enums: OuterEnumsIR<T>, - /// Metadata of view function queries - pub view_functions: RuntimeViewFunctionsIR<T>, } /// Metadata of a runtime trait. @@ -120,83 +118,52 @@ impl IntoPortable for RuntimeApiMethodParamMetadataIR { } } -/// Metadata of the top level runtime view function dispatch. +/// Metadata of a pallet view function method. #[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)] -pub struct RuntimeViewFunctionsIR<T: Form = MetaForm> { - /// The type implementing the runtime query dispatch. - pub ty: T::Type, - /// The view function groupings metadata. - pub groups: Vec<ViewFunctionGroupIR<T>>, -} - -/// Metadata of a runtime view function group. -/// -/// For example, view functions associated with a pallet would form a view function group. -#[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)] -pub struct ViewFunctionGroupIR<T: Form = MetaForm> { - /// Name of the view function group. - pub name: T::String, - /// View functions belonging to the group. - pub view_functions: Vec<ViewFunctionMetadataIR<T>>, - /// View function group documentation. - pub docs: Vec<T::String>, -} - -impl IntoPortable for ViewFunctionGroupIR { - type Output = ViewFunctionGroupIR<PortableForm>; - - fn into_portable(self, registry: &mut Registry) -> Self::Output { - ViewFunctionGroupIR { - name: self.name.into_portable(registry), - view_functions: registry.map_into_portable(self.view_functions), - docs: registry.map_into_portable(self.docs), - } - } -} - -/// Metadata of a runtime view function. -#[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)] -pub struct ViewFunctionMetadataIR<T: Form = MetaForm> { - /// Query name. +pub struct PalletViewFunctionMethodMetadataIR<T: Form = MetaForm> { + /// Method name. pub name: T::String, - /// Query id. + /// Method id. pub id: [u8; 32], - /// Query args. - pub args: Vec<ViewFunctionArgMetadataIR<T>>, - /// Query output. + /// Method parameters. + pub inputs: Vec<PalletViewFunctionMethodParamMetadataIR<T>>, + /// Method output. pub output: T::Type, - /// Query documentation. + /// Method documentation. pub docs: Vec<T::String>, + /// Deprecation info + pub deprecation_info: DeprecationStatusIR<T>, } -impl IntoPortable for ViewFunctionMetadataIR { - type Output = ViewFunctionMetadataIR<PortableForm>; +impl IntoPortable for PalletViewFunctionMethodMetadataIR { + type Output = PalletViewFunctionMethodMetadataIR<PortableForm>; fn into_portable(self, registry: &mut Registry) -> Self::Output { - ViewFunctionMetadataIR { + PalletViewFunctionMethodMetadataIR { name: self.name.into_portable(registry), id: self.id, - args: registry.map_into_portable(self.args), + inputs: registry.map_into_portable(self.inputs), output: registry.register_type(&self.output), docs: registry.map_into_portable(self.docs), + deprecation_info: self.deprecation_info.into_portable(registry), } } } -/// Metadata of a runtime method argument. +/// Metadata of a pallet view function method argument. #[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)] -pub struct ViewFunctionArgMetadataIR<T: Form = MetaForm> { - /// Query argument name. +pub struct PalletViewFunctionMethodParamMetadataIR<T: Form = MetaForm> { + /// Parameter name. pub name: T::String, - /// Query argument type. + /// Parameter type. pub ty: T::Type, } -impl IntoPortable for ViewFunctionArgMetadataIR { - type Output = ViewFunctionArgMetadataIR<PortableForm>; +impl IntoPortable for PalletViewFunctionMethodParamMetadataIR { + type Output = PalletViewFunctionMethodParamMetadataIR<PortableForm>; fn into_portable(self, registry: &mut Registry) -> Self::Output { - ViewFunctionArgMetadataIR { + PalletViewFunctionMethodParamMetadataIR { name: self.name.into_portable(registry), ty: registry.register_type(&self.ty), } @@ -212,6 +179,8 @@ pub struct PalletMetadataIR<T: Form = MetaForm> { pub storage: Option<PalletStorageMetadataIR<T>>, /// Pallet calls metadata. pub calls: Option<PalletCallMetadataIR<T>>, + /// Pallet view functions metadata. + pub view_functions: Vec<PalletViewFunctionMethodMetadataIR<T>>, /// Pallet event metadata. pub event: Option<PalletEventMetadataIR<T>>, /// Pallet constants metadata. @@ -237,6 +206,11 @@ impl IntoPortable for PalletMetadataIR { name: self.name.into_portable(registry), storage: self.storage.map(|storage| storage.into_portable(registry)), calls: self.calls.map(|calls| calls.into_portable(registry)), + view_functions: self + .view_functions + .into_iter() + .map(|view_functions| view_functions.into_portable(registry)) + .collect(), event: self.event.map(|event| event.into_portable(registry)), constants: registry.map_into_portable(self.constants), error: self.error.map(|error| error.into_portable(registry)), diff --git a/substrate/primitives/metadata-ir/src/unstable.rs b/substrate/primitives/metadata-ir/src/unstable.rs index d46ce3ec6a7d470abca872501fad3c7d0632ad32..412cb78ce84f14cf7f805446d99e210514daef1a 100644 --- a/substrate/primitives/metadata-ir/src/unstable.rs +++ b/substrate/primitives/metadata-ir/src/unstable.rs @@ -85,6 +85,8 @@ impl From<PalletMetadataIR> for PalletMetadata { name: ir.name, storage: ir.storage.map(Into::into), calls: ir.calls.map(Into::into), + // TODO: add with the new v16 release of frame-metadata + // view_functions: ir.view_functions.into_iter().map(Into::into).collect(), event: ir.event.map(Into::into), constants: ir.constants.into_iter().map(Into::into).collect(), error: ir.error.map(Into::into), diff --git a/substrate/primitives/metadata-ir/src/v15.rs b/substrate/primitives/metadata-ir/src/v15.rs index 7bc76f22b58d004507c900bd139c9c58f1e8dbf3..64bc3e843ab5898b6fb8b6b16e41944d00c4c035 100644 --- a/substrate/primitives/metadata-ir/src/v15.rs +++ b/substrate/primitives/metadata-ir/src/v15.rs @@ -23,9 +23,9 @@ use super::types::{ }; use frame_metadata::v15::{ - CustomMetadata, CustomValueMetadata, ExtrinsicMetadata, OuterEnums, PalletMetadata, - RuntimeApiMetadata, RuntimeApiMethodMetadata, RuntimeApiMethodParamMetadata, - RuntimeMetadataV15, SignedExtensionMetadata, + CustomMetadata, ExtrinsicMetadata, OuterEnums, PalletMetadata, RuntimeApiMetadata, + RuntimeApiMethodMetadata, RuntimeApiMethodParamMetadata, RuntimeMetadataV15, + SignedExtensionMetadata, }; use scale_info::{IntoPortable, Registry}; @@ -39,15 +39,7 @@ impl From<MetadataIR> for RuntimeMetadataV15 { let apis = registry.map_into_portable(ir.apis.into_iter().map(Into::<RuntimeApiMetadata>::into)); let outer_enums = Into::<OuterEnums>::into(ir.outer_enums).into_portable(&mut registry); - - let view_function_groups = registry.map_into_portable(ir.view_functions.groups.into_iter()); - let view_functions_custom_metadata = CustomValueMetadata { - ty: ir.view_functions.ty, - value: codec::Encode::encode(&view_function_groups), - }; - let mut custom_map = alloc::collections::BTreeMap::new(); - custom_map.insert("view_functions_experimental", view_functions_custom_metadata); - let custom = CustomMetadata { map: custom_map }.into_portable(&mut registry); + let custom = CustomMetadata { map: Default::default() }; Self { types: registry.into(), pallets, extrinsic, ty, apis, outer_enums, custom } }