From 264b902ab29396a7d9dfefd2097c8d5e7d75c76c Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 20 May 2024 11:25:32 +0100 Subject: [PATCH 01/45] Add view functions parsing and definition --- .../procedural/src/pallet/parse/mod.rs | 10 ++++ .../src/pallet/parse/view_functions.rs | 49 +++++++++++++++++++ substrate/frame/support/test/tests/pallet.rs | 9 ++++ 3 files changed, 68 insertions(+) create mode 100644 substrate/frame/support/procedural/src/pallet/parse/view_functions.rs diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index 6e12774611dd..86398c13e3ef 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -36,6 +36,7 @@ pub mod storage; pub mod tasks; pub mod type_value; pub mod validate_unsigned; +pub mod view_functions; #[cfg(test)] pub mod tests; @@ -104,6 +105,7 @@ impl Def { let mut storages = vec![]; let mut type_values = vec![]; let mut composites: Vec = vec![]; + let mut view_functions = None; for (index, item) in items.iter_mut().enumerate() { let pallet_attr: Option = helper::take_first_item_pallet_attr(item)?; @@ -206,6 +208,9 @@ impl Def { } composites.push(composite); }, + Some(PalletAttr::ViewFunctions(span)) => { + view_functions = Some(view_functions::ViewFunctionsDef::try_from(span)?); + } Some(attr) => { let msg = "Invalid duplicated attribute"; return Err(syn::Error::new(attr.span(), msg)) @@ -560,6 +565,7 @@ mod keyword { syn::custom_keyword!(pallet); syn::custom_keyword!(extra_constants); syn::custom_keyword!(composite_enum); + syn::custom_keyword!(view_functions); } /// Parse attributes for item in pallet module @@ -622,6 +628,7 @@ enum PalletAttr { TypeValue(proc_macro2::Span), ExtraConstants(proc_macro2::Span), Composite(proc_macro2::Span), + ViewFunctions(proc_macro2::Span), } impl PalletAttr { @@ -647,6 +654,7 @@ impl PalletAttr { Self::TypeValue(span) => *span, Self::ExtraConstants(span) => *span, Self::Composite(span) => *span, + Self::ViewFunctions(span) => *span, } } } @@ -712,6 +720,8 @@ impl syn::parse::Parse for PalletAttr { Ok(PalletAttr::ExtraConstants(content.parse::()?.span())) } else if lookahead.peek(keyword::composite_enum) { Ok(PalletAttr::Composite(content.parse::()?.span())) + } else if lookahead.peek(keyword::view_functions) { + Ok(PalletAttr::ViewFunctions(content.parse::()?.span())) } else { Err(lookahead.error()) } diff --git a/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs b/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs new file mode 100644 index 000000000000..68a39d76edac --- /dev/null +++ b/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs @@ -0,0 +1,49 @@ +// 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 super::{helper, InheritedCallWeightAttr}; +use frame_support_procedural_tools::get_doc_literals; +use proc_macro2::Span; +use quote::ToTokens; +use std::collections::HashMap; +use syn::{spanned::Spanned, ExprClosure}; + +/// Definition of dispatchables typically `impl Pallet { ... }` +pub struct ViewFunctionsDef { + // /// The where_clause used. + // pub where_clause: Option, + // /// A set of usage of instance, must be check for consistency with trait. + // pub instances: Vec, + // /// The index of call item in pallet module. + // pub index: usize, + // /// Information on methods (used for expansion). + // pub methods: Vec, + // /// The span of the pallet::call attribute. + // pub attr_span: proc_macro2::Span, + // /// Docs, specified on the impl Block. + // pub docs: Vec, + // /// The optional `weight` attribute on the `pallet::call`. + // pub inherited_call_weight: Option, +} + +impl ViewFunctionsDef { + pub fn try_from( + attr_span: proc_macro2::Span, + ) -> syn::Result { + Ok(Self { }) + } +} diff --git a/substrate/frame/support/test/tests/pallet.rs b/substrate/frame/support/test/tests/pallet.rs index f41e606ad7c3..f5d98799acd1 100644 --- a/substrate/frame/support/test/tests/pallet.rs +++ b/substrate/frame/support/test/tests/pallet.rs @@ -450,6 +450,13 @@ pub mod pallet { _myfield: u32, } + #[pallet::view_functions] + impl Pallet + where + T::AccountId: From + SomeAssociation1, + { + } + #[pallet::genesis_build] impl BuildGenesisConfig for GenesisConfig where @@ -548,6 +555,8 @@ pub mod pallet { } pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"testpall"; + + } // Test that a pallet with non generic event and generic genesis_config is correctly handled From 987802cb6568544a296fde6a489b14daa8af21f7 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 20 May 2024 11:54:16 +0100 Subject: [PATCH 02/45] Add to view functions mod definition --- .../procedural/src/pallet/parse/mod.rs | 2 +- .../src/pallet/parse/view_functions.rs | 41 ++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index 86398c13e3ef..1f7c36131db9 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -209,7 +209,7 @@ impl Def { composites.push(composite); }, Some(PalletAttr::ViewFunctions(span)) => { - view_functions = Some(view_functions::ViewFunctionsDef::try_from(span)?); + view_functions = Some(view_functions::ViewFunctionsDef::try_from(span, item)?); } Some(attr) => { let msg = "Invalid duplicated attribute"; 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 68a39d76edac..a733b6a3b2e9 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs @@ -38,12 +38,51 @@ pub struct ViewFunctionsDef { // pub docs: Vec, // /// The optional `weight` attribute on the `pallet::call`. // pub inherited_call_weight: Option, + view_functions: Vec +} + +pub struct ViewFunctionDef { + pub name: syn::Ident, + pub return_type: syn::Type, } impl ViewFunctionsDef { pub fn try_from( attr_span: proc_macro2::Span, + item: &mut syn::Item, ) -> syn::Result { - Ok(Self { }) + let item_impl = if let syn::Item::Impl(item) = item { + item + } else { + return Err(syn::Error::new(item.span(), "Invalid pallet::view_functions, expected item impl")) + }; + let mut view_functions = Vec::new(); + for item in &mut item_impl.items { + if let syn::ImplItem::Fn(method) = item { + if !matches!(method.vis, syn::Visibility::Public(_)) { + let msg = "Invalid pallet::view_functions, view function must be public: \ + `pub fn`"; + + let span = match method.vis { + syn::Visibility::Inherited => method.sig.span(), + _ => method.vis.span(), + }; + + return Err(syn::Error::new(span, msg)) + } + + let syn::ReturnType::Type(_, type_) = &method.sig.output else { + return Err(syn::Error::new(method.sig.output.span(), "view functions must return a value")) + }; + + view_functions.push(ViewFunctionDef { + name: method.sig.ident.clone(), + return_type: *type_.clone(), + }) + } + } + Ok(Self { + view_functions, + }) } } From 4f7a513fb5004f7ea03fa40cea6239334a31340b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 21 May 2024 13:12:51 +0100 Subject: [PATCH 03/45] Adding traits and types and wiring up expansion --- .../procedural/src/pallet/expand/mod.rs | 1 + .../src/pallet/expand/view_functions.rs | 24 ++++++++++ .../procedural/src/pallet/parse/mod.rs | 2 + substrate/frame/support/src/traits.rs | 3 ++ substrate/frame/support/src/traits/query.rs | 47 +++++++++++++++++++ 5 files changed, 77 insertions(+) create mode 100644 substrate/frame/support/procedural/src/pallet/expand/view_functions.rs create mode 100644 substrate/frame/support/src/traits/query.rs diff --git a/substrate/frame/support/procedural/src/pallet/expand/mod.rs b/substrate/frame/support/procedural/src/pallet/expand/mod.rs index 067839c28463..389923f6f480 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/mod.rs @@ -36,6 +36,7 @@ mod tt_default_parts; mod type_value; mod validate_unsigned; mod warnings; +mod view_functions; use crate::pallet::Def; use quote::ToTokens; diff --git a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs new file mode 100644 index 000000000000..742dbfaafe02 --- /dev/null +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -0,0 +1,24 @@ +// 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 crate::pallet::Def; +use proc_macro2::TokenStream; + +pub fn expand_view_functions(def: &mut Def) -> TokenStream { + quote::quote!() +} + diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index 1f7c36131db9..b9b68a0ff8b9 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -71,6 +71,7 @@ pub struct Def { pub frame_system: syn::Path, pub frame_support: syn::Path, pub dev_mode: bool, + pub view_functions: Option, } impl Def { @@ -256,6 +257,7 @@ impl Def { frame_system, frame_support, dev_mode, + view_functions, }; def.check_instance_usage()?; diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index a423656c394f..578913e70ad9 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -132,6 +132,9 @@ pub use tasks::Task; #[cfg(feature = "try-runtime")] mod try_runtime; + +mod query; + #[cfg(feature = "try-runtime")] pub use try_runtime::{ Select as TryStateSelect, TryDecodeEntireStorage, TryDecodeEntireStorageError, TryState, diff --git a/substrate/frame/support/src/traits/query.rs b/substrate/frame/support/src/traits/query.rs new file mode 100644 index 000000000000..16436c9b1e92 --- /dev/null +++ b/substrate/frame/support/src/traits/query.rs @@ -0,0 +1,47 @@ +// 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 fsor the specific language governing permissions and +// limitations under the License. + +//! Traits for querying pallet view functions. + +use codec::{Decode, Encode}; + +/// implemented by the runtime dispatching by prefix and then the pallet dispatching by suffix +pub trait DispatchQuery { + fn dispatch_query(id: &QueryId, input: Vec) -> Result, codec::Error>; +} + +pub trait QueryIdPrefix { + const PREFIX: [u8; 16]; // same as `PalletInfo::name_hash` twox_128 +} + +pub trait QueryIdSuffix { + const SUFFIX: [u8; 16]; +} + +#[derive(Encode, Decode)] +pub struct QueryId { + prefix: [u8; 16], + suffix: [u8; 16], +} + +/// implemented for each pallet view function method +pub trait Query { + type ReturnType: codec::Codec; + + fn query(self) -> Self::ReturnType; +} + From e8af3c2238e37ff64983c5c744b9734b316d7b7c Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 22 May 2024 09:46:47 +0100 Subject: [PATCH 04/45] Use ToTokens for expansion --- .../src/pallet/expand/view_functions.rs | 34 +++++++++++++++++- .../src/pallet/parse/view_functions.rs | 35 ++++++++++++++----- 2 files changed, 59 insertions(+), 10 deletions(-) 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 742dbfaafe02..c172443cb659 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -16,9 +16,41 @@ // limitations under the License. use crate::pallet::Def; +use inflector::Inflector; use proc_macro2::TokenStream; +use quote::ToTokens; +use crate::pallet::parse::view_functions::{ + ViewFunctionDef, ViewFunctionsDef +}; pub fn expand_view_functions(def: &mut Def) -> TokenStream { - quote::quote!() + let Some(view_fns_def) = def.view_functions.as_ref() else { + return TokenStream::new(); + }; + + quote::quote! { + #view_fns_def + } +} + +impl ToTokens for ViewFunctionsDef { + fn to_tokens(&self, tokens: &mut TokenStream) { + let view_fn_impls = self.view_functions.iter().map(|view_fn| { + quote::quote! { #view_fn } + }); + + tokens.extend(quote::quote! { + #( #view_fn_impls )* + }); + } +} + +impl ToTokens for ViewFunctionDef { + fn to_tokens(&self, tokens: &mut TokenStream) { + let name = self.query_struct_ident(); + tokens.extend(quote::quote! { + pub struct #name; + }); + } } 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 a733b6a3b2e9..8a9f89598cea 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs @@ -20,6 +20,7 @@ use frame_support_procedural_tools::get_doc_literals; use proc_macro2::Span; use quote::ToTokens; use std::collections::HashMap; +use inflector::Inflector; use syn::{spanned::Spanned, ExprClosure}; /// Definition of dispatchables typically `impl Pallet { ... }` @@ -38,11 +39,12 @@ pub struct ViewFunctionsDef { // pub docs: Vec, // /// The optional `weight` attribute on the `pallet::call`. // pub inherited_call_weight: Option, - view_functions: Vec + pub view_functions: Vec } pub struct ViewFunctionDef { pub name: syn::Ident, + pub args: Vec, pub return_type: syn::Type, } @@ -71,14 +73,8 @@ impl ViewFunctionsDef { return Err(syn::Error::new(span, msg)) } - let syn::ReturnType::Type(_, type_) = &method.sig.output else { - return Err(syn::Error::new(method.sig.output.span(), "view functions must return a value")) - }; - - view_functions.push(ViewFunctionDef { - name: method.sig.ident.clone(), - return_type: *type_.clone(), - }) + let view_fn_def = ViewFunctionDef::try_from(method.clone())?; + view_functions.push(view_fn_def) } } Ok(Self { @@ -86,3 +82,24 @@ impl ViewFunctionsDef { }) } } + +impl TryFrom for ViewFunctionDef { + type Error = syn::Error; + fn try_from(method: syn::ImplItemFn) -> Result { + let syn::ReturnType::Type(_, type_) = method.sig.output else { + return Err(syn::Error::new(method.sig.output.span(), "view functions must return a value")) + }; + + Ok(Self { + name: method.sig.ident.clone(), + args: method.sig.inputs.iter().cloned().collect::>(), + return_type: *type_.clone(), + }) + } +} + +impl ViewFunctionDef { + pub fn query_struct_ident(&self) -> syn::Ident { + syn::Ident::new(&format!("{}Query", self.name), self.name.span()) + } +} From 70387108bbb1a1609106566642fc1a287d63073c Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 22 May 2024 09:47:57 +0100 Subject: [PATCH 05/45] fmtl --- .../procedural/src/pallet/expand/mod.rs | 2 +- .../src/pallet/expand/view_functions.rs | 51 +++++++++---------- .../src/pallet/parse/view_functions.rs | 23 +++++---- substrate/frame/support/src/traits/query.rs | 15 +++--- substrate/frame/support/test/tests/pallet.rs | 8 +-- 5 files changed, 46 insertions(+), 53 deletions(-) diff --git a/substrate/frame/support/procedural/src/pallet/expand/mod.rs b/substrate/frame/support/procedural/src/pallet/expand/mod.rs index 389923f6f480..54e847c87157 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/mod.rs @@ -35,8 +35,8 @@ mod tasks; mod tt_default_parts; mod type_value; mod validate_unsigned; -mod warnings; mod view_functions; +mod warnings; use crate::pallet::Def; use quote::ToTokens; 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 c172443cb659..5de6db10f0f0 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -15,42 +15,41 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::pallet::Def; +use crate::pallet::{ + parse::view_functions::{ViewFunctionDef, ViewFunctionsDef}, + Def, +}; use inflector::Inflector; use proc_macro2::TokenStream; use quote::ToTokens; -use crate::pallet::parse::view_functions::{ - ViewFunctionDef, ViewFunctionsDef -}; pub fn expand_view_functions(def: &mut Def) -> TokenStream { - let Some(view_fns_def) = def.view_functions.as_ref() else { - return TokenStream::new(); - }; + let Some(view_fns_def) = def.view_functions.as_ref() else { + return TokenStream::new(); + }; - quote::quote! { - #view_fns_def - } + quote::quote! { + #view_fns_def + } } impl ToTokens for ViewFunctionsDef { - fn to_tokens(&self, tokens: &mut TokenStream) { - let view_fn_impls = self.view_functions.iter().map(|view_fn| { - quote::quote! { #view_fn } - }); - - tokens.extend(quote::quote! { - #( #view_fn_impls )* - }); - } + fn to_tokens(&self, tokens: &mut TokenStream) { + let view_fn_impls = self.view_functions.iter().map(|view_fn| { + quote::quote! { #view_fn } + }); + + tokens.extend(quote::quote! { + #( #view_fn_impls )* + }); + } } impl ToTokens for ViewFunctionDef { - fn to_tokens(&self, tokens: &mut TokenStream) { - let name = self.query_struct_ident(); - tokens.extend(quote::quote! { - pub struct #name; - }); - } + fn to_tokens(&self, tokens: &mut TokenStream) { + let name = self.query_struct_ident(); + tokens.extend(quote::quote! { + pub struct #name; + }); + } } - 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 8a9f89598cea..b95919f9f397 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs @@ -17,10 +17,10 @@ use super::{helper, InheritedCallWeightAttr}; use frame_support_procedural_tools::get_doc_literals; +use inflector::Inflector; use proc_macro2::Span; use quote::ToTokens; use std::collections::HashMap; -use inflector::Inflector; use syn::{spanned::Spanned, ExprClosure}; /// Definition of dispatchables typically `impl Pallet { ... }` @@ -39,7 +39,7 @@ pub struct ViewFunctionsDef { // pub docs: Vec, // /// The optional `weight` attribute on the `pallet::call`. // pub inherited_call_weight: Option, - pub view_functions: Vec + pub view_functions: Vec, } pub struct ViewFunctionDef { @@ -49,14 +49,14 @@ pub struct ViewFunctionDef { } impl ViewFunctionsDef { - pub fn try_from( - attr_span: proc_macro2::Span, - item: &mut syn::Item, - ) -> syn::Result { + pub fn try_from(attr_span: proc_macro2::Span, item: &mut syn::Item) -> syn::Result { let item_impl = if let syn::Item::Impl(item) = item { item } else { - return Err(syn::Error::new(item.span(), "Invalid pallet::view_functions, expected item impl")) + return Err(syn::Error::new( + item.span(), + "Invalid pallet::view_functions, expected item impl", + )) }; let mut view_functions = Vec::new(); for item in &mut item_impl.items { @@ -77,9 +77,7 @@ impl ViewFunctionsDef { view_functions.push(view_fn_def) } } - Ok(Self { - view_functions, - }) + Ok(Self { view_functions }) } } @@ -87,7 +85,10 @@ impl TryFrom for ViewFunctionDef { type Error = syn::Error; fn try_from(method: syn::ImplItemFn) -> Result { let syn::ReturnType::Type(_, type_) = method.sig.output else { - return Err(syn::Error::new(method.sig.output.span(), "view functions must return a value")) + return Err(syn::Error::new( + method.sig.output.span(), + "view functions must return a value", + )) }; Ok(Self { diff --git a/substrate/frame/support/src/traits/query.rs b/substrate/frame/support/src/traits/query.rs index 16436c9b1e92..33261b80d44a 100644 --- a/substrate/frame/support/src/traits/query.rs +++ b/substrate/frame/support/src/traits/query.rs @@ -21,27 +21,26 @@ use codec::{Decode, Encode}; /// implemented by the runtime dispatching by prefix and then the pallet dispatching by suffix pub trait DispatchQuery { - fn dispatch_query(id: &QueryId, input: Vec) -> Result, codec::Error>; + fn dispatch_query(id: &QueryId, input: Vec) -> Result, codec::Error>; } pub trait QueryIdPrefix { - const PREFIX: [u8; 16]; // same as `PalletInfo::name_hash` twox_128 + const PREFIX: [u8; 16]; // same as `PalletInfo::name_hash` twox_128 } pub trait QueryIdSuffix { - const SUFFIX: [u8; 16]; + const SUFFIX: [u8; 16]; } #[derive(Encode, Decode)] pub struct QueryId { - prefix: [u8; 16], - suffix: [u8; 16], + prefix: [u8; 16], + suffix: [u8; 16], } /// implemented for each pallet view function method pub trait Query { - type ReturnType: codec::Codec; + type ReturnType: codec::Codec; - fn query(self) -> Self::ReturnType; + fn query(self) -> Self::ReturnType; } - diff --git a/substrate/frame/support/test/tests/pallet.rs b/substrate/frame/support/test/tests/pallet.rs index f5d98799acd1..7f7f2788d4e7 100644 --- a/substrate/frame/support/test/tests/pallet.rs +++ b/substrate/frame/support/test/tests/pallet.rs @@ -451,11 +451,7 @@ pub mod pallet { } #[pallet::view_functions] - impl Pallet - where - T::AccountId: From + SomeAssociation1, - { - } + impl Pallet where T::AccountId: From + SomeAssociation1 {} #[pallet::genesis_build] impl BuildGenesisConfig for GenesisConfig @@ -555,8 +551,6 @@ pub mod pallet { } pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"testpall"; - - } // Test that a pallet with non generic event and generic genesis_config is correctly handled From 9267519fc00eb086a8c9cae538ac450a3a69e952 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 22 May 2024 14:41:59 +0100 Subject: [PATCH 06/45] Adding generics etc to query struct --- .../src/pallet/expand/view_functions.rs | 53 +++++++++++-------- .../procedural/src/pallet/parse/mod.rs | 4 +- .../src/pallet/parse/view_functions.rs | 38 +++++++------ 3 files changed, 52 insertions(+), 43 deletions(-) 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 5de6db10f0f0..a215747af4cf 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -16,40 +16,51 @@ // limitations under the License. use crate::pallet::{ - parse::view_functions::{ViewFunctionDef, ViewFunctionsDef}, + parse::view_functions::{ViewFunctionDef, ViewFunctionsImplDef}, Def, }; -use inflector::Inflector; use proc_macro2::TokenStream; -use quote::ToTokens; -pub fn expand_view_functions(def: &mut Def) -> TokenStream { +pub fn expand_view_functions(def: &Def) -> TokenStream { let Some(view_fns_def) = def.view_functions.as_ref() else { return TokenStream::new(); }; + let view_fn_impls = view_fns_def.view_functions.iter().map(|view_fn| { + expand_view_function(def, &view_fns_def, view_fn) + }); + quote::quote! { - #view_fns_def + #( #view_fn_impls )* } } -impl ToTokens for ViewFunctionsDef { - fn to_tokens(&self, tokens: &mut TokenStream) { - let view_fn_impls = self.view_functions.iter().map(|view_fn| { - quote::quote! { #view_fn } - }); +fn expand_view_function(def: &Def, view_fns_impl: &ViewFunctionsImplDef, view_fn: &ViewFunctionDef) -> TokenStream { + let span = view_fns_impl.attr_span; + let frame_support = &def.frame_support; + let type_impl_gen = &def.type_impl_generics(span); + let type_decl_bounded_gen = &def.type_decl_bounded_generics(span); + let type_use_gen = &def.type_use_generics(span); + let capture_docs = if cfg!(feature = "no-metadata-docs") { "never" } else { "always" }; + let where_clause = &view_fns_impl.where_clause; - tokens.extend(quote::quote! { - #( #view_fn_impls )* - }); - } -} + let query_struct_ident = view_fn.query_struct_ident(); + quote::quote! { + #[derive( + #frame_support::RuntimeDebugNoBound, + #frame_support::CloneNoBound, + #frame_support::EqNoBound, + #frame_support::PartialEqNoBound, + #frame_support::__private::codec::Encode, + #frame_support::__private::codec::Decode, + #frame_support::__private::scale_info::TypeInfo, + )] + #[codec(encode_bound())] + #[codec(decode_bound())] + #[scale_info(skip_type_params(#type_use_gen), capture_docs = #capture_docs)] + #[allow(non_camel_case_types)] + pub struct #query_struct_ident<#type_decl_bounded_gen> #where_clause { -impl ToTokens for ViewFunctionDef { - fn to_tokens(&self, tokens: &mut TokenStream) { - let name = self.query_struct_ident(); - tokens.extend(quote::quote! { - pub struct #name; - }); + }; } } diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index b9b68a0ff8b9..30e64ac67621 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -71,7 +71,7 @@ pub struct Def { pub frame_system: syn::Path, pub frame_support: syn::Path, pub dev_mode: bool, - pub view_functions: Option, + pub view_functions: Option, } impl Def { @@ -210,7 +210,7 @@ impl Def { composites.push(composite); }, Some(PalletAttr::ViewFunctions(span)) => { - view_functions = Some(view_functions::ViewFunctionsDef::try_from(span, item)?); + view_functions = Some(view_functions::ViewFunctionsImplDef::try_from(span, item)?); } Some(attr) => { let msg = "Invalid duplicated attribute"; 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 b95919f9f397..a3bbd949ff1f 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs @@ -15,26 +15,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -use super::{helper, InheritedCallWeightAttr}; -use frame_support_procedural_tools::get_doc_literals; -use inflector::Inflector; -use proc_macro2::Span; -use quote::ToTokens; -use std::collections::HashMap; -use syn::{spanned::Spanned, ExprClosure}; +use syn::{spanned::Spanned}; /// Definition of dispatchables typically `impl Pallet { ... }` -pub struct ViewFunctionsDef { - // /// The where_clause used. - // pub where_clause: Option, +pub struct ViewFunctionsImplDef { + /// The where_clause used. + pub where_clause: Option, // /// A set of usage of instance, must be check for consistency with trait. // pub instances: Vec, // /// The index of call item in pallet module. // pub index: usize, // /// Information on methods (used for expansion). // pub methods: Vec, - // /// The span of the pallet::call attribute. - // pub attr_span: proc_macro2::Span, + /// The span of the pallet::view_functions attribute. + pub attr_span: proc_macro2::Span, // /// Docs, specified on the impl Block. // pub docs: Vec, // /// The optional `weight` attribute on the `pallet::call`. @@ -42,13 +36,7 @@ pub struct ViewFunctionsDef { pub view_functions: Vec, } -pub struct ViewFunctionDef { - pub name: syn::Ident, - pub args: Vec, - pub return_type: syn::Type, -} - -impl ViewFunctionsDef { +impl ViewFunctionsImplDef { pub fn try_from(attr_span: proc_macro2::Span, item: &mut syn::Item) -> syn::Result { let item_impl = if let syn::Item::Impl(item) = item { item @@ -77,10 +65,20 @@ impl ViewFunctionsDef { view_functions.push(view_fn_def) } } - Ok(Self { view_functions }) + Ok(Self { + view_functions, + attr_span, + where_clause: item_impl.generics.where_clause.clone(), + }) } } +pub struct ViewFunctionDef { + pub name: syn::Ident, + pub args: Vec, + pub return_type: syn::Type, +} + impl TryFrom for ViewFunctionDef { type Error = syn::Error; fn try_from(method: syn::ImplItemFn) -> Result { From c6a4e42eee985d2a35d8f595aa1b75d8cdb140e9 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 22 May 2024 14:42:29 +0100 Subject: [PATCH 07/45] fmt --- .../procedural/src/pallet/expand/view_functions.rs | 13 +++++++++---- .../procedural/src/pallet/parse/view_functions.rs | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) 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 a215747af4cf..b35aea6bfc32 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -26,16 +26,21 @@ pub fn expand_view_functions(def: &Def) -> TokenStream { return TokenStream::new(); }; - let view_fn_impls = view_fns_def.view_functions.iter().map(|view_fn| { - expand_view_function(def, &view_fns_def, view_fn) - }); + let view_fn_impls = view_fns_def + .view_functions + .iter() + .map(|view_fn| expand_view_function(def, &view_fns_def, view_fn)); quote::quote! { #( #view_fn_impls )* } } -fn expand_view_function(def: &Def, view_fns_impl: &ViewFunctionsImplDef, view_fn: &ViewFunctionDef) -> TokenStream { +fn expand_view_function( + def: &Def, + view_fns_impl: &ViewFunctionsImplDef, + view_fn: &ViewFunctionDef, +) -> TokenStream { let span = view_fns_impl.attr_span; let frame_support = &def.frame_support; let type_impl_gen = &def.type_impl_generics(span); 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 a3bbd949ff1f..735f7b8cbe30 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use syn::{spanned::Spanned}; +use syn::spanned::Spanned; /// Definition of dispatchables typically `impl Pallet { ... }` pub struct ViewFunctionsImplDef { From 140f7d97a2d0b0d4803474a2a6713268c2116dca Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 23 May 2024 09:34:15 +0100 Subject: [PATCH 08/45] example with args --- substrate/frame/support/test/tests/pallet.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/substrate/frame/support/test/tests/pallet.rs b/substrate/frame/support/test/tests/pallet.rs index 7f7f2788d4e7..4bb2c3263edc 100644 --- a/substrate/frame/support/test/tests/pallet.rs +++ b/substrate/frame/support/test/tests/pallet.rs @@ -451,7 +451,20 @@ pub mod pallet { } #[pallet::view_functions] - impl Pallet where T::AccountId: From + SomeAssociation1 {} + impl Pallet + where + T::AccountId: From + SomeAssociation1, + { + /// Query value no args. + pub fn get_value() -> Option { + Value::::get() + } + + /// Query value with args. + pub fn get_value_with_arg(key: u16) -> Option { + Map2::::get(key) + } + } #[pallet::genesis_build] impl BuildGenesisConfig for GenesisConfig From 23b9ebfc906d57ec1d88a2535db5cb562da7f2c6 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 23 May 2024 13:37:55 +0100 Subject: [PATCH 09/45] add example for testing --- Cargo.lock | 17 ++++ substrate/frame/examples/Cargo.toml | 3 + substrate/frame/examples/src/lib.rs | 3 + .../frame/examples/view-functions/Cargo.toml | 55 +++++++++++++ .../frame/examples/view-functions/src/lib.rs | 82 +++++++++++++++++++ .../frame/examples/view-functions/src/mock.rs | 51 ++++++++++++ .../examples/view-functions/src/tests.rs | 31 +++++++ 7 files changed, 242 insertions(+) create mode 100644 substrate/frame/examples/view-functions/Cargo.toml create mode 100644 substrate/frame/examples/view-functions/src/lib.rs create mode 100644 substrate/frame/examples/view-functions/src/mock.rs create mode 100644 substrate/frame/examples/view-functions/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index 2a4b9b138bf8..654ca0bc4b27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10392,6 +10392,22 @@ dependencies = [ "sp-std 14.0.0", ] +[[package]] +name = "pallet-example-view-functions" +version = "1.0.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 14.0.0", +] + [[package]] name = "pallet-examples" version = "4.0.0-dev" @@ -10405,6 +10421,7 @@ dependencies = [ "pallet-example-single-block-migrations", "pallet-example-split", "pallet-example-tasks", + "pallet-example-view-functions", ] [[package]] diff --git a/substrate/frame/examples/Cargo.toml b/substrate/frame/examples/Cargo.toml index 45c7440eb891..48abdd115d67 100644 --- a/substrate/frame/examples/Cargo.toml +++ b/substrate/frame/examples/Cargo.toml @@ -25,6 +25,7 @@ pallet-example-offchain-worker = { path = "offchain-worker", default-features = pallet-example-split = { path = "split", default-features = false } pallet-example-single-block-migrations = { path = "single-block-migrations", default-features = false } pallet-example-tasks = { path = "tasks", default-features = false } +pallet-example-view-functions = { path = "view-functions", default-features = false } [features] default = ["std"] @@ -38,6 +39,7 @@ std = [ "pallet-example-single-block-migrations/std", "pallet-example-split/std", "pallet-example-tasks/std", + "pallet-example-view-functions/std", ] try-runtime = [ "pallet-default-config-example/try-runtime", @@ -48,4 +50,5 @@ try-runtime = [ "pallet-example-single-block-migrations/try-runtime", "pallet-example-split/try-runtime", "pallet-example-tasks/try-runtime", + "pallet-example-view-functions/try-runtime", ] diff --git a/substrate/frame/examples/src/lib.rs b/substrate/frame/examples/src/lib.rs index dee23a41379f..3752e08ca636 100644 --- a/substrate/frame/examples/src/lib.rs +++ b/substrate/frame/examples/src/lib.rs @@ -48,4 +48,7 @@ //! //! - [`pallet_example_tasks`]: This pallet demonstrates the use of `Tasks` to execute service work. //! +//! - [`pallet_example_view_functions`]: This pallet demonstrates the use of view functions to query +//! pallet state. +//! //! **Tip**: Use `cargo doc --package --open` to view each pallet's documentation. diff --git a/substrate/frame/examples/view-functions/Cargo.toml b/substrate/frame/examples/view-functions/Cargo.toml new file mode 100644 index 000000000000..add2159e1f26 --- /dev/null +++ b/substrate/frame/examples/view-functions/Cargo.toml @@ -0,0 +1,55 @@ +[package] +name = "pallet-example-view-functions" +version = "1.0.0" +authors.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +description = "Pallet to demonstrate the usage of view functions to query pallet state" + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } +log = { workspace = true } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } + +frame-support = { path = "../../support", default-features = false } +frame-system = { path = "../../system", default-features = false } + +sp-io = { path = "../../../primitives/io", default-features = false } +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } +sp-core = { default-features = false, path = "../../../primitives/core" } + +frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "log/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "sp-runtime/try-runtime", +] \ No newline at end of file diff --git a/substrate/frame/examples/view-functions/src/lib.rs b/substrate/frame/examples/view-functions/src/lib.rs new file mode 100644 index 000000000000..22f1b3694ee4 --- /dev/null +++ b/substrate/frame/examples/view-functions/src/lib.rs @@ -0,0 +1,82 @@ +// 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. + +//! This pallet demonstrates the use of the `pallet::task` api for service work. +#![cfg_attr(not(feature = "std"), no_std)] + +pub mod mock; +pub mod tests; + +use frame_support::{dispatch::DispatchResult, Parameter}; +use frame_system::offchain::SendTransactionTypes; +use scale_info::TypeInfo; + +// Re-export pallet items so that they can be accessed from the crate namespace. +pub use pallet::*; + +pub struct SomeType1; +impl From for u64 { + fn from(_t: SomeType1) -> Self { + 0u64 + } +} + +pub trait SomeAssociation1 { + type _1: Parameter + codec::MaxEncodedLen + TypeInfo; +} +impl SomeAssociation1 for u64 { + type _1 = u64; +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::error] + pub enum Error {} + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + pub type SomeValue = StorageValue<_, u32>; + + /// Numbers to be added into the total. + #[pallet::storage] + pub type SomeMap = StorageMap<_, Twox64Concat, u32, u32, OptionQuery>; + + #[pallet::view_functions] + impl Pallet + where + T::AccountId: From + SomeAssociation1, + { + /// Query value no args. + pub fn get_value() -> Option { + SomeValue::::get() + } + + /// Query value with args. + pub fn get_value_with_arg(key: u32) -> Option { + SomeMap::::get(key) + } + } +} diff --git a/substrate/frame/examples/view-functions/src/mock.rs b/substrate/frame/examples/view-functions/src/mock.rs new file mode 100644 index 000000000000..95f66a40cc3b --- /dev/null +++ b/substrate/frame/examples/view-functions/src/mock.rs @@ -0,0 +1,51 @@ +// 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. + +//! Mock runtime for `view-functions-example` tests. +#![cfg(test)] + +use crate::{self as view_functions_example}; +use frame_support::{derive_impl, Parameter}; +use scale_info::TypeInfo; +use sp_runtime::testing::TestXt; + +pub type AccountId = u32; +pub type Balance = u32; + +type Block = frame_system::mocking::MockBlock; +frame_support::construct_runtime!( + pub enum Runtime { + System: frame_system, + ViewFunctionsExample: view_functions_example, + } +); + +pub type Extrinsic = TestXt; + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl frame_system::Config for Runtime { + type Block = Block; +} + +impl view_functions_example::Config for Runtime {} + +pub fn new_test_ext() -> sp_io::TestExternalities { + use sp_runtime::BuildStorage; + + let t = RuntimeGenesisConfig { system: Default::default() }.build_storage().unwrap(); + t.into() +} diff --git a/substrate/frame/examples/view-functions/src/tests.rs b/substrate/frame/examples/view-functions/src/tests.rs new file mode 100644 index 000000000000..2b31f425401c --- /dev/null +++ b/substrate/frame/examples/view-functions/src/tests.rs @@ -0,0 +1,31 @@ +// 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. + +//! Tests for `pallet-example-tasks`. +#![cfg(test)] + +use crate::mock::*; +use frame_support::traits::Task; +use sp_runtime::BuildStorage; + +#[test] +fn task_enumerate_works() { + new_test_ext().execute_with(|| { + // Numbers::::insert(0, 1); + // assert_eq!(crate::pallet::Task::::iter().collect::>().len(), 1); + }); +} From 86c5f2fcb9c5522de5cb23659fbb3ae81af1aaad Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 24 May 2024 10:16:20 +0100 Subject: [PATCH 10/45] wire up codegen for view functions --- .../frame/examples/view-functions/src/lib.rs | 1 - .../examples/view-functions/src/tests.rs | 21 ++++++++++++++----- .../procedural/src/pallet/expand/mod.rs | 2 ++ .../src/pallet/expand/view_functions.rs | 4 ++-- .../src/pallet/parse/view_functions.rs | 6 +++++- substrate/frame/support/src/traits.rs | 1 + substrate/frame/support/src/traits/query.rs | 1 + 7 files changed, 27 insertions(+), 9 deletions(-) diff --git a/substrate/frame/examples/view-functions/src/lib.rs b/substrate/frame/examples/view-functions/src/lib.rs index 22f1b3694ee4..a097dc857fbf 100644 --- a/substrate/frame/examples/view-functions/src/lib.rs +++ b/substrate/frame/examples/view-functions/src/lib.rs @@ -60,7 +60,6 @@ pub mod pallet { #[pallet::storage] pub type SomeValue = StorageValue<_, u32>; - /// Numbers to be added into the total. #[pallet::storage] pub type SomeMap = StorageMap<_, Twox64Concat, u32, u32, OptionQuery>; diff --git a/substrate/frame/examples/view-functions/src/tests.rs b/substrate/frame/examples/view-functions/src/tests.rs index 2b31f425401c..c07c1248bd86 100644 --- a/substrate/frame/examples/view-functions/src/tests.rs +++ b/substrate/frame/examples/view-functions/src/tests.rs @@ -18,14 +18,25 @@ //! Tests for `pallet-example-tasks`. #![cfg(test)] -use crate::mock::*; -use frame_support::traits::Task; +use crate::{ + mock::*, + pallet::{self, Pallet}, +}; +use frame_support::traits::{DispatchQuery, Query}; use sp_runtime::BuildStorage; #[test] -fn task_enumerate_works() { +fn pallet_get_value_query() { new_test_ext().execute_with(|| { - // Numbers::::insert(0, 1); - // assert_eq!(crate::pallet::Task::::iter().collect::>().len(), 1); + let some_value = Some(99); + pallet::SomeValue::::set(some_value); + assert_eq!(some_value, Pallet::::get_value()); + assert_eq!( + some_value, + as DispatchQuery>::dispatch_query( + & as Query>::ID, + vec![], + ) + ); }); } diff --git a/substrate/frame/support/procedural/src/pallet/expand/mod.rs b/substrate/frame/support/procedural/src/pallet/expand/mod.rs index 54e847c87157..15810933e593 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/mod.rs @@ -66,6 +66,7 @@ pub fn expand(mut def: Def) -> proc_macro2::TokenStream { let error = error::expand_error(&mut def); let event = event::expand_event(&mut def); let storages = storage::expand_storages(&mut def); + let view_functions = view_functions::expand_view_functions(&def); let inherents = inherent::expand_inherents(&mut def); let instances = instances::expand_instances(&mut def); let hooks = hooks::expand_hooks(&mut def); @@ -107,6 +108,7 @@ storage item. Otherwise, all storage items are listed among [*Type Definitions*] #error #event #storages + #view_functions #inherents #instances #hooks 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 b35aea6bfc32..b43511c1fada 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -65,7 +65,7 @@ fn expand_view_function( #[scale_info(skip_type_params(#type_use_gen), capture_docs = #capture_docs)] #[allow(non_camel_case_types)] pub struct #query_struct_ident<#type_decl_bounded_gen> #where_clause { - - }; + _marker: ::core::marker::PhantomData<(#type_use_gen,)>, + } } } 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 735f7b8cbe30..38672849161b 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs @@ -15,6 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use inflector::Inflector; use syn::spanned::Spanned; /// Definition of dispatchables typically `impl Pallet { ... }` @@ -99,6 +100,9 @@ impl TryFrom for ViewFunctionDef { impl ViewFunctionDef { pub fn query_struct_ident(&self) -> syn::Ident { - syn::Ident::new(&format!("{}Query", self.name), self.name.span()) + syn::Ident::new( + &format!("{}Query", self.name.to_string().to_pascal_case()), + self.name.span(), + ) } } diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 578913e70ad9..481a365c402b 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -134,6 +134,7 @@ pub use tasks::Task; mod try_runtime; mod query; +pub use query::{DispatchQuery, Query}; #[cfg(feature = "try-runtime")] pub use try_runtime::{ diff --git a/substrate/frame/support/src/traits/query.rs b/substrate/frame/support/src/traits/query.rs index 33261b80d44a..5941be48b918 100644 --- a/substrate/frame/support/src/traits/query.rs +++ b/substrate/frame/support/src/traits/query.rs @@ -40,6 +40,7 @@ pub struct QueryId { /// implemented for each pallet view function method pub trait Query { + const ID: QueryId; type ReturnType: codec::Codec; fn query(self) -> Self::ReturnType; From f42c5c44840045bd4de30b5c4a54a14c4da0eabd Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 24 May 2024 11:53:28 +0100 Subject: [PATCH 11/45] Generate DispatchQuery impl --- .../examples/view-functions/src/tests.rs | 17 +++++++--- .../src/pallet/expand/view_functions.rs | 32 +++++++++++++++++++ substrate/frame/support/src/traits.rs | 2 +- substrate/frame/support/src/traits/query.rs | 4 +-- 4 files changed, 47 insertions(+), 8 deletions(-) diff --git a/substrate/frame/examples/view-functions/src/tests.rs b/substrate/frame/examples/view-functions/src/tests.rs index c07c1248bd86..b6ac1085ff77 100644 --- a/substrate/frame/examples/view-functions/src/tests.rs +++ b/substrate/frame/examples/view-functions/src/tests.rs @@ -23,7 +23,7 @@ use crate::{ pallet::{self, Pallet}, }; use frame_support::traits::{DispatchQuery, Query}; -use sp_runtime::BuildStorage; +use codec::{Encode, Decode}; #[test] fn pallet_get_value_query() { @@ -31,12 +31,19 @@ fn pallet_get_value_query() { let some_value = Some(99); pallet::SomeValue::::set(some_value); assert_eq!(some_value, Pallet::::get_value()); + + let query = pallet::GetValueQuery::::new(); + + let query_result = as DispatchQuery>::dispatch_query( + & as Query>::ID, + &*query.encode(), + ).unwrap(); + + let query_result = >::decode(&mut &query_result[..]).unwrap(); + assert_eq!( some_value, - as DispatchQuery>::dispatch_query( - & as Query>::ID, - vec![], - ) + query_result, ); }); } 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 b43511c1fada..fb7e53d7aaaf 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -30,9 +30,11 @@ pub fn expand_view_functions(def: &Def) -> TokenStream { .view_functions .iter() .map(|view_fn| expand_view_function(def, &view_fns_def, view_fn)); + let impl_dispatch_query = impl_dispatch_query(def, view_fns_def); quote::quote! { #( #view_fn_impls )* + #impl_dispatch_query } } @@ -67,5 +69,35 @@ fn expand_view_function( pub struct #query_struct_ident<#type_decl_bounded_gen> #where_clause { _marker: ::core::marker::PhantomData<(#type_use_gen,)>, } + + impl<#type_impl_gen> #query_struct_ident<#type_use_gen> #where_clause { + pub fn new() -> Self { + Self { _marker: ::core::default::Default::default() } + } + } + } +} + +fn impl_dispatch_query(def: &Def, view_fns_impl: &ViewFunctionsImplDef) -> TokenStream { + let span = view_fns_impl.attr_span; + let frame_support = &def.frame_support; + let pallet_ident = &def.pallet_struct.pallet; + let type_impl_gen = &def.type_impl_generics(span); + let type_decl_bounded_gen = &def.type_decl_bounded_generics(span); + let type_use_gen = &def.type_use_generics(span); + + quote::quote! { + impl<#type_impl_gen> #frame_support::traits::DispatchQuery + for #pallet_ident<#type_use_gen> + { + fn dispatch_query< + I: #frame_support::__private::codec::Input, + O: #frame_support::__private::codec::Output, + > + (id: & #frame_support::traits::QueryId, input: I) -> Result + { + todo!() + } + } } } diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 481a365c402b..0fb9c32a3642 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -134,7 +134,7 @@ pub use tasks::Task; mod try_runtime; mod query; -pub use query::{DispatchQuery, Query}; +pub use query::{DispatchQuery, Query, QueryId}; #[cfg(feature = "try-runtime")] pub use try_runtime::{ diff --git a/substrate/frame/support/src/traits/query.rs b/substrate/frame/support/src/traits/query.rs index 5941be48b918..fc5a0fa81952 100644 --- a/substrate/frame/support/src/traits/query.rs +++ b/substrate/frame/support/src/traits/query.rs @@ -17,11 +17,11 @@ //! Traits for querying pallet view functions. -use codec::{Decode, Encode}; +use codec::{Decode, Encode, Input, Output}; /// implemented by the runtime dispatching by prefix and then the pallet dispatching by suffix pub trait DispatchQuery { - fn dispatch_query(id: &QueryId, input: Vec) -> Result, codec::Error>; + fn dispatch_query(id: &QueryId, input: I) -> Result; } pub trait QueryIdPrefix { From ac6643e6340dcedd7d66ba9751086b2b374d8e24 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 24 May 2024 18:52:52 +0100 Subject: [PATCH 12/45] Wire up runtime PalletQuery --- .../examples/view-functions/src/tests.rs | 2 +- substrate/frame/support/procedural/src/lib.rs | 3 ++- .../src/pallet/expand/view_functions.rs | 21 +++++++++++++++++++ substrate/frame/support/src/traits.rs | 2 +- substrate/frame/support/src/traits/query.rs | 17 +++++++++++++-- substrate/frame/system/src/lib.rs | 10 +++++++++ 6 files changed, 50 insertions(+), 5 deletions(-) diff --git a/substrate/frame/examples/view-functions/src/tests.rs b/substrate/frame/examples/view-functions/src/tests.rs index b6ac1085ff77..79779b57487f 100644 --- a/substrate/frame/examples/view-functions/src/tests.rs +++ b/substrate/frame/examples/view-functions/src/tests.rs @@ -34,7 +34,7 @@ fn pallet_get_value_query() { let query = pallet::GetValueQuery::::new(); - let query_result = as DispatchQuery>::dispatch_query( + let query_result = as DispatchQuery>::dispatch_query::<_, Vec>( & as Query>::ID, &*query.encode(), ).unwrap(); diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index 53f01329d181..604579ad6d81 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -788,6 +788,7 @@ pub fn inject_runtime_type(_: TokenStream, tokens: TokenStream) -> TokenStream { if item.ident != "RuntimeCall" && item.ident != "RuntimeEvent" && item.ident != "RuntimeTask" && + item.ident != "RuntimeQuery" && item.ident != "RuntimeOrigin" && item.ident != "RuntimeHoldReason" && item.ident != "RuntimeFreezeReason" && @@ -797,7 +798,7 @@ pub fn inject_runtime_type(_: TokenStream, tokens: TokenStream) -> TokenStream { return syn::Error::new_spanned( item, "`#[inject_runtime_type]` can only be attached to `RuntimeCall`, `RuntimeEvent`, \ - `RuntimeTask`, `RuntimeOrigin`, `RuntimeParameters` or `PalletInfo`", + `RuntimeTask`, `RuntimeQuery`, `RuntimeOrigin`, `RuntimeParameters` or `PalletInfo`", ) .to_compile_error() .into() 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 fb7e53d7aaaf..4cfe058483c3 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -45,13 +45,18 @@ fn expand_view_function( ) -> TokenStream { let span = view_fns_impl.attr_span; let frame_support = &def.frame_support; + let frame_system = &def.frame_system; let type_impl_gen = &def.type_impl_generics(span); let type_decl_bounded_gen = &def.type_decl_bounded_generics(span); let type_use_gen = &def.type_use_generics(span); + let trait_use_gen = &def.trait_use_generics(span); let capture_docs = if cfg!(feature = "no-metadata-docs") { "never" } else { "always" }; let where_clause = &view_fns_impl.where_clause; let query_struct_ident = view_fn.query_struct_ident(); + // let args = todo!(); + let return_type = &view_fn.return_type; + quote::quote! { #[derive( #frame_support::RuntimeDebugNoBound, @@ -75,6 +80,22 @@ fn expand_view_function( Self { _marker: ::core::default::Default::default() } } } + + impl<#type_impl_gen> #frame_support::traits::QueryIdSuffix for #query_struct_ident<#type_use_gen> #where_clause { + const SUFFIX: [u8; 16] = [0u8; 16]; + } + + impl<#type_impl_gen> #frame_support::traits::Query for #query_struct_ident<#type_use_gen> #where_clause { + const ID: #frame_support::traits::QueryId = #frame_support::traits::QueryId { + prefix: <::RuntimeQuery as #frame_support::traits::QueryIdPrefix>::PREFIX, + suffix: ::SUFFIX, // todo: [AJ] handle instantiatable pallet suffix + }; + type ReturnType = #return_type; + + fn query(self) -> Self::ReturnType { + todo!() + } + } } } diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 0fb9c32a3642..3b2234c82117 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -134,7 +134,7 @@ pub use tasks::Task; mod try_runtime; mod query; -pub use query::{DispatchQuery, Query, QueryId}; +pub use query::{DispatchQuery, Query, QueryIdPrefix, QueryIdSuffix, QueryId}; #[cfg(feature = "try-runtime")] pub use try_runtime::{ diff --git a/substrate/frame/support/src/traits/query.rs b/substrate/frame/support/src/traits/query.rs index fc5a0fa81952..26205488e95a 100644 --- a/substrate/frame/support/src/traits/query.rs +++ b/substrate/frame/support/src/traits/query.rs @@ -24,6 +24,19 @@ pub trait DispatchQuery { fn dispatch_query(id: &QueryId, input: I) -> Result; } +impl DispatchQuery for () { + fn dispatch_query( + _id: &QueryId, + _input: I, + ) -> Result { + Err(codec::Error::from("DispatchQuery not implemented")) // todo: return "query not found" error? + } +} + +impl QueryIdPrefix for () { + const PREFIX: [u8; 16] = [0u8; 16]; +} + pub trait QueryIdPrefix { const PREFIX: [u8; 16]; // same as `PalletInfo::name_hash` twox_128 } @@ -34,8 +47,8 @@ pub trait QueryIdSuffix { #[derive(Encode, Decode)] pub struct QueryId { - prefix: [u8; 16], - suffix: [u8; 16], + pub prefix: [u8; 16], + pub suffix: [u8; 16], } /// implemented for each pallet view function method diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs index 7ed954d83aa8..80281b0350f8 100644 --- a/substrate/frame/system/src/lib.rs +++ b/substrate/frame/system/src/lib.rs @@ -299,6 +299,7 @@ pub mod pallet { type PalletInfo = (); #[inject_runtime_type] type RuntimeTask = (); + type RuntimeQuery = (); type BaseCallFilter = frame_support::traits::Everything; type BlockHashCount = frame_support::traits::ConstU64<10>; type OnSetCode = (); @@ -388,6 +389,10 @@ pub mod pallet { #[inject_runtime_type] type RuntimeTask = (); + /// The query dispatch type, injected by `construct_runtime!`. + #[inject_runtime_type] + type RuntimeQuery = (); + /// Converts a module to the index of the module, injected by `construct_runtime!`. #[inject_runtime_type] type PalletInfo = (); @@ -477,6 +482,11 @@ pub mod pallet { #[pallet::no_default_bounds] type RuntimeTask: Task; + /// Type for dispatching queries. + #[pallet::no_default_bounds] + type RuntimeQuery: frame_support::traits::QueryIdPrefix + + frame_support::traits::DispatchQuery; + /// This stores the number of previous transactions associated with a sender account. type Nonce: Parameter + Member From 2ea615855937b924feca3c8d0038f6a0f49428cf Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 28 May 2024 16:32:03 +0100 Subject: [PATCH 13/45] Wire up query args --- .../frame/examples/view-functions/src/lib.rs | 4 +- .../frame/examples/view-functions/src/mock.rs | 3 +- .../examples/view-functions/src/tests.rs | 19 ++++---- .../src/pallet/expand/view_functions.rs | 48 +++++++++++++++---- substrate/frame/support/src/traits.rs | 2 +- substrate/frame/support/src/traits/query.rs | 11 +++-- 6 files changed, 61 insertions(+), 26 deletions(-) diff --git a/substrate/frame/examples/view-functions/src/lib.rs b/substrate/frame/examples/view-functions/src/lib.rs index a097dc857fbf..d94e60e2d913 100644 --- a/substrate/frame/examples/view-functions/src/lib.rs +++ b/substrate/frame/examples/view-functions/src/lib.rs @@ -21,8 +21,7 @@ pub mod mock; pub mod tests; -use frame_support::{dispatch::DispatchResult, Parameter}; -use frame_system::offchain::SendTransactionTypes; +use frame_support::Parameter; use scale_info::TypeInfo; // Re-export pallet items so that they can be accessed from the crate namespace. @@ -46,7 +45,6 @@ impl SomeAssociation1 for u64 { pub mod pallet { use super::*; use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; #[pallet::error] pub enum Error {} diff --git a/substrate/frame/examples/view-functions/src/mock.rs b/substrate/frame/examples/view-functions/src/mock.rs index 95f66a40cc3b..d128c619598a 100644 --- a/substrate/frame/examples/view-functions/src/mock.rs +++ b/substrate/frame/examples/view-functions/src/mock.rs @@ -19,8 +19,7 @@ #![cfg(test)] use crate::{self as view_functions_example}; -use frame_support::{derive_impl, Parameter}; -use scale_info::TypeInfo; +use frame_support::derive_impl; use sp_runtime::testing::TestXt; pub type AccountId = u32; diff --git a/substrate/frame/examples/view-functions/src/tests.rs b/substrate/frame/examples/view-functions/src/tests.rs index 79779b57487f..27dc0987bf22 100644 --- a/substrate/frame/examples/view-functions/src/tests.rs +++ b/substrate/frame/examples/view-functions/src/tests.rs @@ -22,8 +22,8 @@ use crate::{ mock::*, pallet::{self, Pallet}, }; +use codec::{Decode, Encode}; use frame_support::traits::{DispatchQuery, Query}; -use codec::{Encode, Decode}; #[test] fn pallet_get_value_query() { @@ -33,17 +33,18 @@ fn pallet_get_value_query() { assert_eq!(some_value, Pallet::::get_value()); let query = pallet::GetValueQuery::::new(); + let input = query.encode(); + let mut output = Vec::new(); - let query_result = as DispatchQuery>::dispatch_query::<_, Vec>( + let _ = as DispatchQuery>::dispatch_query::<_, Vec>( & as Query>::ID, - &*query.encode(), - ).unwrap(); + &mut &input[..], + &mut output, + ) + .unwrap(); - let query_result = >::decode(&mut &query_result[..]).unwrap(); + let query_result = >::decode(&mut &output[..]).unwrap(); - assert_eq!( - some_value, - query_result, - ); + assert_eq!(some_value, query_result,); }); } 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 4cfe058483c3..ce1b8f4dd158 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -46,6 +46,7 @@ fn expand_view_function( let span = view_fns_impl.attr_span; let frame_support = &def.frame_support; let frame_system = &def.frame_system; + let pallet_ident = &def.pallet_struct.pallet; let type_impl_gen = &def.type_impl_generics(span); let type_decl_bounded_gen = &def.type_decl_bounded_generics(span); let type_use_gen = &def.type_use_generics(span); @@ -54,7 +55,18 @@ fn expand_view_function( let where_clause = &view_fns_impl.where_clause; let query_struct_ident = view_fn.query_struct_ident(); - // let args = todo!(); + let view_fn_name = &view_fn.name; + let (arg_names, arg_types): (Vec<_>, Vec<_>) = view_fn + .args + .iter() + .map(|arg| match arg { + syn::FnArg::Typed(pat_type) => match &*pat_type.pat { + syn::Pat::Ident(ident) => (ident.ident.clone(), pat_type.ty.clone()), + _ => panic!("Unsupported pattern in view function argument"), + }, + _ => panic!("Unsupported argument in view function"), + }) + .unzip(); let return_type = &view_fn.return_type; quote::quote! { @@ -72,12 +84,16 @@ fn expand_view_function( #[scale_info(skip_type_params(#type_use_gen), capture_docs = #capture_docs)] #[allow(non_camel_case_types)] pub struct #query_struct_ident<#type_decl_bounded_gen> #where_clause { + #( pub #arg_names: #arg_types, )* _marker: ::core::marker::PhantomData<(#type_use_gen,)>, } impl<#type_impl_gen> #query_struct_ident<#type_use_gen> #where_clause { - pub fn new() -> Self { - Self { _marker: ::core::default::Default::default() } + pub fn new(#( #arg_names: #arg_types, )*) -> Self { + Self { + #( #arg_names, )* + _marker: ::core::default::Default::default() + } } } @@ -93,7 +109,8 @@ fn expand_view_function( type ReturnType = #return_type; fn query(self) -> Self::ReturnType { - todo!() + let Self { #( #arg_names, )* _marker } = self; + #pallet_ident::<#type_use_gen> :: #view_fn_name( #( #arg_names, )* ) } } } @@ -104,20 +121,35 @@ fn impl_dispatch_query(def: &Def, view_fns_impl: &ViewFunctionsImplDef) -> Token let frame_support = &def.frame_support; let pallet_ident = &def.pallet_struct.pallet; let type_impl_gen = &def.type_impl_generics(span); - let type_decl_bounded_gen = &def.type_decl_bounded_generics(span); let type_use_gen = &def.type_use_generics(span); + let where_clause = &view_fns_impl.where_clause; + + let query_match_arms = view_fns_impl.view_functions.iter().map(|view_fn| { + let query_struct_ident = view_fn.query_struct_ident(); + quote::quote! { + <#query_struct_ident<#type_use_gen> as #frame_support::traits::QueryIdSuffix>::SUFFIX => { + let query = <#query_struct_ident<#type_use_gen> as #frame_support::__private::codec::Decode>::decode(input)?; + let result = <#query_struct_ident<#type_use_gen> as #frame_support::traits::Query>::query(query); + let output = #frame_support::__private::codec::Encode::encode_to(&result, output); + ::core::result::Result::Ok(output) + } + } + }); quote::quote! { impl<#type_impl_gen> #frame_support::traits::DispatchQuery - for #pallet_ident<#type_use_gen> + for #pallet_ident<#type_use_gen> #where_clause { fn dispatch_query< I: #frame_support::__private::codec::Input, O: #frame_support::__private::codec::Output, > - (id: & #frame_support::traits::QueryId, input: I) -> Result + (id: & #frame_support::traits::QueryId, input: &mut I, output: &mut O) -> Result<(), #frame_support::__private::codec::Error> { - todo!() + match id.suffix { + #( #query_match_arms )* + _ => Err(#frame_support::__private::codec::Error::from("DispatchQuery not implemented")), // todo: [AJ] + } } } } diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 3b2234c82117..40a2e954539b 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -134,7 +134,7 @@ pub use tasks::Task; mod try_runtime; mod query; -pub use query::{DispatchQuery, Query, QueryIdPrefix, QueryIdSuffix, QueryId}; +pub use query::{DispatchQuery, Query, QueryId, QueryIdPrefix, QueryIdSuffix}; #[cfg(feature = "try-runtime")] pub use try_runtime::{ diff --git a/substrate/frame/support/src/traits/query.rs b/substrate/frame/support/src/traits/query.rs index 26205488e95a..92bf4546efb6 100644 --- a/substrate/frame/support/src/traits/query.rs +++ b/substrate/frame/support/src/traits/query.rs @@ -21,14 +21,19 @@ use codec::{Decode, Encode, Input, Output}; /// implemented by the runtime dispatching by prefix and then the pallet dispatching by suffix pub trait DispatchQuery { - fn dispatch_query(id: &QueryId, input: I) -> Result; + fn dispatch_query( + id: &QueryId, + input: &mut I, + output: &mut O, + ) -> Result<(), codec::Error>; } impl DispatchQuery for () { fn dispatch_query( _id: &QueryId, - _input: I, - ) -> Result { + _input: &mut I, + _output: &mut O, + ) -> Result<(), codec::Error> { Err(codec::Error::from("DispatchQuery not implemented")) // todo: return "query not found" error? } } From 8b56a844b7d02477538acbdcce634c518dd53271 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 28 May 2024 18:32:23 +0100 Subject: [PATCH 14/45] Add get value with args query --- .../examples/view-functions/src/tests.rs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/substrate/frame/examples/view-functions/src/tests.rs b/substrate/frame/examples/view-functions/src/tests.rs index 27dc0987bf22..34882f441129 100644 --- a/substrate/frame/examples/view-functions/src/tests.rs +++ b/substrate/frame/examples/view-functions/src/tests.rs @@ -48,3 +48,28 @@ fn pallet_get_value_query() { assert_eq!(some_value, query_result,); }); } + +#[test] +fn pallet_get_value_with_arg_query() { + new_test_ext().execute_with(|| { + let some_key = 1u32; + let some_value = Some(123); + pallet::SomeMap::::set(some_key, some_value); + assert_eq!(some_value, Pallet::::get_value_with_arg(some_key)); + + let query = pallet::GetValueWithArgQuery::::new(some_key); + let input = query.encode(); + let mut output = Vec::new(); + + let _ = as DispatchQuery>::dispatch_query::<_, Vec>( + & as Query>::ID, + &mut &input[..], + &mut output, + ) + .unwrap(); + + let query_result = >::decode(&mut &output[..]).unwrap(); + + assert_eq!(some_value, query_result,); + }); +} From 06f9ffc1e7ef2ea80ca80109f6823e78d8ef5fba Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 29 May 2024 15:36:53 +0100 Subject: [PATCH 15/45] decode_all --- .../examples/view-functions/src/tests.rs | 58 ++++++++++++++++++- .../src/pallet/expand/view_functions.rs | 30 +++++----- substrate/frame/support/src/traits/query.rs | 10 ++-- 3 files changed, 77 insertions(+), 21 deletions(-) diff --git a/substrate/frame/examples/view-functions/src/tests.rs b/substrate/frame/examples/view-functions/src/tests.rs index 34882f441129..70e982162ce0 100644 --- a/substrate/frame/examples/view-functions/src/tests.rs +++ b/substrate/frame/examples/view-functions/src/tests.rs @@ -36,7 +36,7 @@ fn pallet_get_value_query() { let input = query.encode(); let mut output = Vec::new(); - let _ = as DispatchQuery>::dispatch_query::<_, Vec>( + let _ = as DispatchQuery>::dispatch_query::>( & as Query>::ID, &mut &input[..], &mut output, @@ -61,7 +61,7 @@ fn pallet_get_value_with_arg_query() { let input = query.encode(); let mut output = Vec::new(); - let _ = as DispatchQuery>::dispatch_query::<_, Vec>( + let _ = as DispatchQuery>::dispatch_query::>( & as Query>::ID, &mut &input[..], &mut output, @@ -73,3 +73,57 @@ fn pallet_get_value_with_arg_query() { assert_eq!(some_value, query_result,); }); } + +// pub struct Test(PhantomData); +// +// impl DispatchQuery for Test +// where +// T::AccountId: From + crate::SomeAssociation1, +// { +// #[automatically_derived] +// // #[deny(unreachable_patterns)] +// fn dispatch_query( +// id: &frame_support::traits::QueryId, +// input: &mut &[u8], +// output: &mut O, +// ) -> Result<(), codec::Error> { +// match id.suffix { +// as frame_support::traits::QueryIdSuffix>::SUFFIX => { +// let query = as codec::DecodeAll>::decode_all(input)?; +// let result = as frame_support::traits::Query>::query(query); +// let output = codec::Encode::encode_to( +// &result, +// output, +// ); +// ::core::result::Result::Ok(output) +// } +// as frame_support::traits::QueryIdSuffix>::SUFFIX => { +// let query = as codec::DecodeAll>::decode_all(input)?; +// let result = as frame_support::traits::Query>::query(query); +// let output = codec::Encode::encode_to( +// &result, +// output, +// ); +// ::core::result::Result::Ok(output) +// } +// _ => { +// Err( +// codec::Error::from( +// "DispatchQuery not implemented", +// ), +// ) +// } +// } +// } +// +// } 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 ce1b8f4dd158..8ad7113e5bab 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -82,7 +82,6 @@ fn expand_view_function( #[codec(encode_bound())] #[codec(decode_bound())] #[scale_info(skip_type_params(#type_use_gen), capture_docs = #capture_docs)] - #[allow(non_camel_case_types)] pub struct #query_struct_ident<#type_decl_bounded_gen> #where_clause { #( pub #arg_names: #arg_types, )* _marker: ::core::marker::PhantomData<(#type_use_gen,)>, @@ -128,7 +127,7 @@ fn impl_dispatch_query(def: &Def, view_fns_impl: &ViewFunctionsImplDef) -> Token let query_struct_ident = view_fn.query_struct_ident(); quote::quote! { <#query_struct_ident<#type_use_gen> as #frame_support::traits::QueryIdSuffix>::SUFFIX => { - let query = <#query_struct_ident<#type_use_gen> as #frame_support::__private::codec::Decode>::decode(input)?; + let query = <#query_struct_ident<#type_use_gen> as #frame_support::__private::codec::DecodeAll>::decode_all(input)?; let result = <#query_struct_ident<#type_use_gen> as #frame_support::traits::Query>::query(query); let output = #frame_support::__private::codec::Encode::encode_to(&result, output); ::core::result::Result::Ok(output) @@ -137,20 +136,23 @@ fn impl_dispatch_query(def: &Def, view_fns_impl: &ViewFunctionsImplDef) -> Token }); quote::quote! { - impl<#type_impl_gen> #frame_support::traits::DispatchQuery - for #pallet_ident<#type_use_gen> #where_clause - { - fn dispatch_query< - I: #frame_support::__private::codec::Input, - O: #frame_support::__private::codec::Output, - > - (id: & #frame_support::traits::QueryId, input: &mut I, output: &mut O) -> Result<(), #frame_support::__private::codec::Error> + const _: () = { + impl<#type_impl_gen> #frame_support::traits::DispatchQuery + for #pallet_ident<#type_use_gen> #where_clause { - match id.suffix { - #( #query_match_arms )* - _ => Err(#frame_support::__private::codec::Error::from("DispatchQuery not implemented")), // todo: [AJ] + #[deny(unreachable_patterns)] + fn dispatch_query< + O: #frame_support::__private::codec::Output, + > + (id: & #frame_support::traits::QueryId, input: &mut &[u8], output: &mut O) -> Result<(), #frame_support::__private::codec::Error> + { + let x = 1; + match id.suffix { + #( #query_match_arms )* + _ => Err(#frame_support::__private::codec::Error::from("DispatchQuery not implemented")), // todo: [AJ] + } } } - } + }; } } diff --git a/substrate/frame/support/src/traits/query.rs b/substrate/frame/support/src/traits/query.rs index 92bf4546efb6..91ab37d5d4c6 100644 --- a/substrate/frame/support/src/traits/query.rs +++ b/substrate/frame/support/src/traits/query.rs @@ -17,21 +17,21 @@ //! Traits for querying pallet view functions. -use codec::{Decode, Encode, Input, Output}; +use codec::{Decode, Encode, Output}; /// implemented by the runtime dispatching by prefix and then the pallet dispatching by suffix pub trait DispatchQuery { - fn dispatch_query( + fn dispatch_query( id: &QueryId, - input: &mut I, + input: &mut &[u8], output: &mut O, ) -> Result<(), codec::Error>; } impl DispatchQuery for () { - fn dispatch_query( + fn dispatch_query( _id: &QueryId, - _input: &mut I, + _input: &mut &[u8], _output: &mut O, ) -> Result<(), codec::Error> { Err(codec::Error::from("DispatchQuery not implemented")) // todo: return "query not found" error? From cd52010b6fc1327e19b8b7ac1a3e61d2504c629d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 30 May 2024 11:01:38 +0100 Subject: [PATCH 16/45] Docs --- .../procedural/src/pallet/expand/view_functions.rs | 8 +++++++- .../support/procedural/src/pallet/parse/view_functions.rs | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) 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 8ad7113e5bab..83a91124f916 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -68,8 +68,11 @@ fn expand_view_function( }) .unzip(); let return_type = &view_fn.return_type; + let docs = &view_fn.docs; quote::quote! { + #( #[doc = #docs] )* + #[allow(missing_docs)] #[derive( #frame_support::RuntimeDebugNoBound, #frame_support::CloneNoBound, @@ -83,11 +86,14 @@ fn expand_view_function( #[codec(decode_bound())] #[scale_info(skip_type_params(#type_use_gen), capture_docs = #capture_docs)] pub struct #query_struct_ident<#type_decl_bounded_gen> #where_clause { - #( pub #arg_names: #arg_types, )* + #( + pub #arg_names: #arg_types, + )* _marker: ::core::marker::PhantomData<(#type_use_gen,)>, } impl<#type_impl_gen> #query_struct_ident<#type_use_gen> #where_clause { + /// Create a new [`#query_struct_ident`] instance. pub fn new(#( #arg_names: #arg_types, )*) -> Self { Self { #( #arg_names, )* 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 38672849161b..ee57e1fa3337 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs @@ -17,6 +17,7 @@ use inflector::Inflector; use syn::spanned::Spanned; +use frame_support_procedural_tools::get_doc_literals; /// Definition of dispatchables typically `impl Pallet { ... }` pub struct ViewFunctionsImplDef { @@ -76,6 +77,7 @@ impl ViewFunctionsImplDef { pub struct ViewFunctionDef { pub name: syn::Ident, + pub docs: Vec, pub args: Vec, pub return_type: syn::Type, } @@ -92,6 +94,7 @@ impl TryFrom for ViewFunctionDef { Ok(Self { name: method.sig.ident.clone(), + docs: get_doc_literals(&method.attrs), args: method.sig.inputs.iter().cloned().collect::>(), return_type: *type_.clone(), }) From 44707b362b9298dc6fd9ae07d6ab7c3b6f546de2 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 30 May 2024 17:07:36 +0100 Subject: [PATCH 17/45] Generate suffix from view_fn signature --- .../src/pallet/expand/view_functions.rs | 20 ++++------- .../src/pallet/parse/view_functions.rs | 34 ++++++++++++++++++- 2 files changed, 39 insertions(+), 15 deletions(-) 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 83a91124f916..1fcbbd476a79 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -56,20 +56,12 @@ fn expand_view_function( let query_struct_ident = view_fn.query_struct_ident(); let view_fn_name = &view_fn.name; - let (arg_names, arg_types): (Vec<_>, Vec<_>) = view_fn - .args - .iter() - .map(|arg| match arg { - syn::FnArg::Typed(pat_type) => match &*pat_type.pat { - syn::Pat::Ident(ident) => (ident.ident.clone(), pat_type.ty.clone()), - _ => panic!("Unsupported pattern in view function argument"), - }, - _ => panic!("Unsupported argument in view function"), - }) - .unzip(); + let (arg_names, arg_types) = view_fn.args_names_types(); let return_type = &view_fn.return_type; let docs = &view_fn.docs; + let query_id_suffix_bytes = view_fn.query_id_suffix_bytes_lits(); + quote::quote! { #( #[doc = #docs] )* #[allow(missing_docs)] @@ -103,7 +95,7 @@ fn expand_view_function( } impl<#type_impl_gen> #frame_support::traits::QueryIdSuffix for #query_struct_ident<#type_use_gen> #where_clause { - const SUFFIX: [u8; 16] = [0u8; 16]; + const SUFFIX: [::core::primitive::u8; 16usize] = [ #( #query_id_suffix_bytes ),* ]; } impl<#type_impl_gen> #frame_support::traits::Query for #query_struct_ident<#type_use_gen> #where_clause { @@ -146,13 +138,13 @@ fn impl_dispatch_query(def: &Def, view_fns_impl: &ViewFunctionsImplDef) -> Token impl<#type_impl_gen> #frame_support::traits::DispatchQuery for #pallet_ident<#type_use_gen> #where_clause { - #[deny(unreachable_patterns)] + #[deny(unreachable_patterns)] // todo: [AJ] should error if identical suffixes, does not atm fn dispatch_query< O: #frame_support::__private::codec::Output, > (id: & #frame_support::traits::QueryId, input: &mut &[u8], output: &mut O) -> Result<(), #frame_support::__private::codec::Error> { - let x = 1; + // let y = 1; // todo: [AJ] why is unused variable error not triggered here - unused functions? match id.suffix { #( #query_match_arms )* _ => Err(#frame_support::__private::codec::Error::from("DispatchQuery not implemented")), // todo: [AJ] 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 ee57e1fa3337..6e39b924a32a 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs @@ -15,9 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +use frame_support_procedural_tools::get_doc_literals; use inflector::Inflector; use syn::spanned::Spanned; -use frame_support_procedural_tools::get_doc_literals; /// Definition of dispatchables typically `impl Pallet { ... }` pub struct ViewFunctionsImplDef { @@ -108,4 +108,36 @@ impl ViewFunctionDef { self.name.span(), ) } + + pub fn query_id_suffix_bytes_lits(&self) -> [syn::LitInt; 16] { + let mut output = [0u8; 16]; + let arg_types = self + .args_names_types() + .1 + .iter() + .map(|ty| quote::quote!(#ty).to_string()) + .collect::>() + .join(","); + let return_type = &self.return_type; + let view_fn_signature = + format!("{}({}) -> {}", self.name, arg_types, quote::quote!(#return_type),); + let hash = sp_crypto_hashing::twox_128(view_fn_signature.as_bytes()); + output.copy_from_slice(&hash[..]); + output.map(|byte| { + syn::LitInt::new(&format!("0x{:X}_u8", byte), proc_macro2::Span::call_site()) + }) + } + + pub fn args_names_types(&self) -> (Vec, Vec) { + self.args + .iter() + .map(|arg| match arg { + syn::FnArg::Typed(pat_type) => match &*pat_type.pat { + syn::Pat::Ident(ident) => (ident.ident.clone(), *pat_type.ty.clone()), + _ => panic!("Unsupported pattern in view function argument"), + }, + _ => panic!("Unsupported argument in view function"), + }) + .unzip() + } } From afa14900d66a3f9591e30145434b89662ee3bcb9 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 30 May 2024 17:38:18 +0100 Subject: [PATCH 18/45] separate suffix id --- .../src/pallet/expand/view_functions.rs | 4 +++- .../src/pallet/parse/view_functions.rs | 17 +++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) 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 1fcbbd476a79..b9f712227991 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -60,7 +60,9 @@ fn expand_view_function( let return_type = &view_fn.return_type; let docs = &view_fn.docs; - let query_id_suffix_bytes = view_fn.query_id_suffix_bytes_lits(); + let query_id_suffix_bytes = view_fn + .query_id_suffix_bytes() + .map(|byte| syn::LitInt::new(&format!("0x{:X}_u8", byte), proc_macro2::Span::call_site())); quote::quote! { #( #[doc = #docs] )* 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 6e39b924a32a..7b97952b383c 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs @@ -109,8 +109,10 @@ impl ViewFunctionDef { ) } - pub fn query_id_suffix_bytes_lits(&self) -> [syn::LitInt; 16] { + pub fn query_id_suffix_bytes(&self) -> [u8; 16] { let mut output = [0u8; 16]; + + // concatenate the signature string let arg_types = self .args_names_types() .1 @@ -119,13 +121,16 @@ impl ViewFunctionDef { .collect::>() .join(","); let return_type = &self.return_type; - let view_fn_signature = - format!("{}({}) -> {}", self.name, arg_types, quote::quote!(#return_type),); + let view_fn_signature = format!( + "{query_name}({arg_types}) -> {return_type}", + query_name = &self.name, + return_type = quote::quote!(#return_type), + ); + + // hash the signature string let hash = sp_crypto_hashing::twox_128(view_fn_signature.as_bytes()); output.copy_from_slice(&hash[..]); - output.map(|byte| { - syn::LitInt::new(&format!("0x{:X}_u8", byte), proc_macro2::Span::call_site()) - }) + output } pub fn args_names_types(&self) -> (Vec, Vec) { From f97a40c9d70081aaa64d5e9500d3876cad069313 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 30 May 2024 20:06:09 +0100 Subject: [PATCH 19/45] WIP expand runtime level query --- .../examples/view-functions/src/tests.rs | 2 +- .../src/construct_runtime/expand/mod.rs | 2 + .../src/construct_runtime/expand/query.rs | 68 +++++++++++++++++++ .../procedural/src/construct_runtime/mod.rs | 3 + 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 substrate/frame/support/procedural/src/construct_runtime/expand/query.rs diff --git a/substrate/frame/examples/view-functions/src/tests.rs b/substrate/frame/examples/view-functions/src/tests.rs index 70e982162ce0..1561a5627f8f 100644 --- a/substrate/frame/examples/view-functions/src/tests.rs +++ b/substrate/frame/examples/view-functions/src/tests.rs @@ -36,7 +36,7 @@ fn pallet_get_value_query() { let input = query.encode(); let mut output = Vec::new(); - let _ = as DispatchQuery>::dispatch_query::>( + let _ = ::RuntimeQuery::dispatch_query::>( & as Query>::ID, &mut &input[..], &mut output, diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/mod.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/mod.rs index 88f9a3c6e33f..dfe54955dfc2 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/mod.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/mod.rs @@ -28,6 +28,7 @@ mod outer_enums; mod slash_reason; mod task; mod unsigned; +mod query; pub use call::expand_outer_dispatch; pub use config::expand_outer_config; @@ -41,3 +42,4 @@ pub use outer_enums::{expand_outer_enum, OuterEnumType}; pub use slash_reason::expand_outer_slash_reason; pub use task::expand_outer_task; pub use unsigned::expand_outer_validate_unsigned; +pub use query::expand_outer_query; diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs new file mode 100644 index 000000000000..c649e6369683 --- /dev/null +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs @@ -0,0 +1,68 @@ +// 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 crate::construct_runtime::Pallet; +use proc_macro2::{Ident, Span, TokenStream as TokenStream2}; + +/// Expands implementation of runtime level `DispatchQuery`. +pub fn expand_outer_query( + runtime_name: &Ident, + pallet_decls: &[Pallet], + scrate: &TokenStream2, +) -> TokenStream2 { + let runtime_query = syn::Ident::new("RuntimeQuery", Span::call_site()); + + let query_match_arms = pallet_decls.iter().map(|pallet| { + let pallet_name = &pallet.name; + quote::quote! { + < #pallet_name< #runtime_name > as #scrate::traits::QueryIdPrefix>::PREFIX => { + < #pallet_name< #runtime_name > as #scrate::traits::DispatchQuery>::dispatch_query(id, input, output) + } + } + }); + + quote::quote! { + /// Runtime query type. + #[derive( + Clone, PartialEq, Eq, + #scrate::__private::codec::Encode, + #scrate::__private::codec::Decode, + #scrate::__private::scale_info::TypeInfo, + #scrate::__private::RuntimeDebug, + )] + pub enum #runtime_query {} + + const _: () = { + impl #scrate::traits::DispatchQuery for #runtime_query + { + #[deny(unreachable_patterns)] // todo: [AJ] should error if identical prefixes + fn dispatch_query( + id: & #scrate::traits::QueryId, + input: &mut &[u8], + output: &mut O + ) -> Result<(), #scrate::__private::codec::Error> + { + // let y = 1; // todo: [AJ] why is unused variable error not triggered here - unused functions? + match id.suffix { + #( #query_match_arms )* + _ => Err(#scrate::__private::codec::Error::from("DispatchQuery not implemented")), // todo: [AJ] + } + } + } + }; + } +} diff --git a/substrate/frame/support/procedural/src/construct_runtime/mod.rs b/substrate/frame/support/procedural/src/construct_runtime/mod.rs index 1505d158895f..4098234ae3a7 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/mod.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/mod.rs @@ -400,6 +400,7 @@ fn construct_runtime_final_expansion( let dispatch = expand::expand_outer_dispatch(&name, system_pallet, &pallets, &scrate); let tasks = expand::expand_outer_task(&name, &pallets, &scrate); + let query = expand::expand_outer_query(&name, &pallets, &scrate); let metadata = expand::expand_runtime_metadata( &name, &pallets, @@ -491,6 +492,8 @@ fn construct_runtime_final_expansion( #tasks + #query + #metadata #outer_config From ddff4d02c232092814490b677fa1b76585a13356 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 31 May 2024 15:56:01 +0100 Subject: [PATCH 20/45] Implement `DispatchQuery` for pallets even without queries --- .../src/construct_runtime/expand/mod.rs | 4 +- .../src/construct_runtime/expand/query.rs | 4 +- .../procedural/src/construct_runtime/parse.rs | 6 +++ .../src/pallet/expand/view_functions.rs | 40 ++++++++++--------- .../src/pallet/parse/view_functions.rs | 1 + 5 files changed, 33 insertions(+), 22 deletions(-) diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/mod.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/mod.rs index dfe54955dfc2..8bae23f08351 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/mod.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/mod.rs @@ -25,10 +25,10 @@ mod lock_id; mod metadata; mod origin; mod outer_enums; +mod query; mod slash_reason; mod task; mod unsigned; -mod query; pub use call::expand_outer_dispatch; pub use config::expand_outer_config; @@ -39,7 +39,7 @@ pub use lock_id::expand_outer_lock_id; pub use metadata::expand_runtime_metadata; pub use origin::expand_outer_origin; pub use outer_enums::{expand_outer_enum, OuterEnumType}; +pub use query::expand_outer_query; pub use slash_reason::expand_outer_slash_reason; pub use task::expand_outer_task; pub use unsigned::expand_outer_validate_unsigned; -pub use query::expand_outer_query; diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs index c649e6369683..70a0998285b9 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs @@ -29,8 +29,8 @@ pub fn expand_outer_query( let query_match_arms = pallet_decls.iter().map(|pallet| { let pallet_name = &pallet.name; quote::quote! { - < #pallet_name< #runtime_name > as #scrate::traits::QueryIdPrefix>::PREFIX => { - < #pallet_name< #runtime_name > as #scrate::traits::DispatchQuery>::dispatch_query(id, input, output) + < #pallet_name as #scrate::traits::QueryIdPrefix>::PREFIX => { + < #pallet_name as #scrate::traits::DispatchQuery>::dispatch_query(id, input, output) } } }); diff --git a/substrate/frame/support/procedural/src/construct_runtime/parse.rs b/substrate/frame/support/procedural/src/construct_runtime/parse.rs index ded77bed4c8e..3b4e43231b88 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/parse.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/parse.rs @@ -45,6 +45,7 @@ mod keyword { syn::custom_keyword!(Task); syn::custom_keyword!(LockId); syn::custom_keyword!(SlashReason); + syn::custom_keyword!(Query); syn::custom_keyword!(exclude_parts); syn::custom_keyword!(use_parts); syn::custom_keyword!(expanded); @@ -408,6 +409,7 @@ pub enum PalletPartKeyword { Task(keyword::Task), LockId(keyword::LockId), SlashReason(keyword::SlashReason), + Query(keyword::Query), } impl Parse for PalletPartKeyword { @@ -442,6 +444,8 @@ impl Parse for PalletPartKeyword { Ok(Self::LockId(input.parse()?)) } else if lookahead.peek(keyword::SlashReason) { Ok(Self::SlashReason(input.parse()?)) + } else if lookahead.peek(keyword::Query) { + Ok(Self::Query(input.parse()?)) } else { Err(lookahead.error()) } @@ -466,6 +470,7 @@ impl PalletPartKeyword { Self::Task(_) => "Task", Self::LockId(_) => "LockId", Self::SlashReason(_) => "SlashReason", + Self::Query(_) => "Query", } } @@ -497,6 +502,7 @@ impl ToTokens for PalletPartKeyword { Self::Task(inner) => inner.to_tokens(tokens), Self::LockId(inner) => inner.to_tokens(tokens), Self::SlashReason(inner) => inner.to_tokens(tokens), + Self::Query(inner) => inner.to_tokens(tokens), } } } 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 b9f712227991..fff1d78d28ce 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -15,22 +15,24 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::pallet::{ - parse::view_functions::{ViewFunctionDef, ViewFunctionsImplDef}, - Def, -}; -use proc_macro2::TokenStream; +use crate::pallet::{parse::view_functions::ViewFunctionDef, Def}; +use proc_macro2::{Span, TokenStream}; +use syn::spanned::Spanned; pub fn expand_view_functions(def: &Def) -> TokenStream { - let Some(view_fns_def) = def.view_functions.as_ref() else { - return TokenStream::new(); + let (span, where_clause, view_fns) = match def.view_functions.as_ref() { + Some(view_fns) => ( + view_fns.attr_span.clone(), + view_fns.where_clause.clone(), + view_fns.view_functions.clone(), + ), + None => (def.item.span(), def.config.where_clause.clone(), Vec::new()), }; - let view_fn_impls = view_fns_def - .view_functions + let view_fn_impls = view_fns .iter() - .map(|view_fn| expand_view_function(def, &view_fns_def, view_fn)); - let impl_dispatch_query = impl_dispatch_query(def, view_fns_def); + .map(|view_fn| expand_view_function(def, span, where_clause.as_ref(), view_fn)); + let impl_dispatch_query = impl_dispatch_query(def, span, where_clause.as_ref(), &view_fns); quote::quote! { #( #view_fn_impls )* @@ -40,10 +42,10 @@ pub fn expand_view_functions(def: &Def) -> TokenStream { fn expand_view_function( def: &Def, - view_fns_impl: &ViewFunctionsImplDef, + span: Span, + where_clause: Option<&syn::WhereClause>, view_fn: &ViewFunctionDef, ) -> TokenStream { - let span = view_fns_impl.attr_span; let frame_support = &def.frame_support; let frame_system = &def.frame_system; let pallet_ident = &def.pallet_struct.pallet; @@ -52,7 +54,6 @@ fn expand_view_function( let type_use_gen = &def.type_use_generics(span); let trait_use_gen = &def.trait_use_generics(span); let capture_docs = if cfg!(feature = "no-metadata-docs") { "never" } else { "always" }; - let where_clause = &view_fns_impl.where_clause; let query_struct_ident = view_fn.query_struct_ident(); let view_fn_name = &view_fn.name; @@ -115,15 +116,18 @@ fn expand_view_function( } } -fn impl_dispatch_query(def: &Def, view_fns_impl: &ViewFunctionsImplDef) -> TokenStream { - let span = view_fns_impl.attr_span; +fn impl_dispatch_query( + def: &Def, + span: Span, + where_clause: Option<&syn::WhereClause>, + view_fns: &[ViewFunctionDef], +) -> TokenStream { let frame_support = &def.frame_support; let pallet_ident = &def.pallet_struct.pallet; let type_impl_gen = &def.type_impl_generics(span); let type_use_gen = &def.type_use_generics(span); - let where_clause = &view_fns_impl.where_clause; - let query_match_arms = view_fns_impl.view_functions.iter().map(|view_fn| { + let query_match_arms = view_fns.iter().map(|view_fn| { let query_struct_ident = view_fn.query_struct_ident(); quote::quote! { <#query_struct_ident<#type_use_gen> as #frame_support::traits::QueryIdSuffix>::SUFFIX => { 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 7b97952b383c..fa8657c57bac 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs @@ -75,6 +75,7 @@ impl ViewFunctionsImplDef { } } +#[derive(Clone)] pub struct ViewFunctionDef { pub name: syn::Ident, pub docs: Vec, From 538ea8a8571be483f86d596eabb92fb3bac876ab Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 31 May 2024 17:44:49 +0100 Subject: [PATCH 21/45] WIP --- .../src/construct_runtime/expand/query.rs | 31 ++++++++++++++++--- .../src/pallet/expand/view_functions.rs | 2 +- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs index 70a0998285b9..187cc4e045bb 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs @@ -20,16 +20,38 @@ use proc_macro2::{Ident, Span, TokenStream as TokenStream2}; /// Expands implementation of runtime level `DispatchQuery`. pub fn expand_outer_query( - runtime_name: &Ident, + _runtime_name: &Ident, pallet_decls: &[Pallet], scrate: &TokenStream2, ) -> TokenStream2 { let runtime_query = syn::Ident::new("RuntimeQuery", Span::call_site()); + let query_id_prefix_impls = pallet_decls.iter().map(|pallet| { + let pallet_path = &pallet.path; + let pallet_name = &pallet.name; + + let mut output = [0u8; 16]; + let pallet_signature = format!( + "{path}::{pallet}", + path = quote::quote!(#pallet_path).to_string(), + pallet = quote::quote!(#pallet_name).to_string() + ); + let hash = sp_crypto_hashing::blake2_128(pallet_signature.as_bytes()); + output.copy_from_slice(&hash); + let query_id_prefix_bytes = + output.map(|byte| syn::LitInt::new(&format!("0x{:X}_u8", byte), Span::call_site())); + + quote::quote! { + impl #scrate::traits::QueryIdPrefix for #scrate::traits::PalletQueryId<#pallet_name> { + const PREFIX: [::core::primitive::u8; 16usize] = [ #( #query_id_prefix_bytes ),* ]; + } + } + }); + let query_match_arms = pallet_decls.iter().map(|pallet| { let pallet_name = &pallet.name; quote::quote! { - < #pallet_name as #scrate::traits::QueryIdPrefix>::PREFIX => { + < #scrate::traits::PalletQueryId<#pallet_name> as #scrate::traits::QueryIdPrefix>::PREFIX => { < #pallet_name as #scrate::traits::DispatchQuery>::dispatch_query(id, input, output) } } @@ -47,8 +69,9 @@ pub fn expand_outer_query( pub enum #runtime_query {} const _: () = { - impl #scrate::traits::DispatchQuery for #runtime_query - { + #( #query_id_prefix_impls )* + + impl #scrate::traits::DispatchQuery for #runtime_query { #[deny(unreachable_patterns)] // todo: [AJ] should error if identical prefixes fn dispatch_query( id: & #scrate::traits::QueryId, 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 fff1d78d28ce..c335221e72a8 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -63,7 +63,7 @@ fn expand_view_function( let query_id_suffix_bytes = view_fn .query_id_suffix_bytes() - .map(|byte| syn::LitInt::new(&format!("0x{:X}_u8", byte), proc_macro2::Span::call_site())); + .map(|byte| syn::LitInt::new(&format!("0x{:X}_u8", byte), Span::call_site())); quote::quote! { #( #[doc = #docs] )* From db616f56f8538d83d5d3ed5947d447bb000dde89 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 3 Jun 2024 14:55:57 +0100 Subject: [PATCH 22/45] Use pallet name hash as query id prefix --- .../examples/view-functions/src/tests.rs | 5 ++- .../src/construct_runtime/expand/query.rs | 43 +++++-------------- .../src/pallet/expand/view_functions.rs | 40 ++++++++++++++--- substrate/frame/support/src/traits/query.rs | 13 +++--- substrate/frame/system/src/lib.rs | 3 +- 5 files changed, 55 insertions(+), 49 deletions(-) diff --git a/substrate/frame/examples/view-functions/src/tests.rs b/substrate/frame/examples/view-functions/src/tests.rs index 1561a5627f8f..0c31105f07a2 100644 --- a/substrate/frame/examples/view-functions/src/tests.rs +++ b/substrate/frame/examples/view-functions/src/tests.rs @@ -36,8 +36,9 @@ fn pallet_get_value_query() { let input = query.encode(); let mut output = Vec::new(); + let _ = ::RuntimeQuery::dispatch_query::>( - & as Query>::ID, + & as Query>::id(), &mut &input[..], &mut output, ) @@ -62,7 +63,7 @@ fn pallet_get_value_with_arg_query() { let mut output = Vec::new(); let _ = as DispatchQuery>::dispatch_query::>( - & as Query>::ID, + & as Query>::id(), &mut &input[..], &mut output, ) diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs index 187cc4e045bb..e488e73f6fb8 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs @@ -26,33 +26,16 @@ pub fn expand_outer_query( ) -> TokenStream2 { let runtime_query = syn::Ident::new("RuntimeQuery", Span::call_site()); - let query_id_prefix_impls = pallet_decls.iter().map(|pallet| { - let pallet_path = &pallet.path; + let prefix_conditionals = pallet_decls.iter().map(|pallet| { let pallet_name = &pallet.name; - - let mut output = [0u8; 16]; - let pallet_signature = format!( - "{path}::{pallet}", - path = quote::quote!(#pallet_path).to_string(), - pallet = quote::quote!(#pallet_name).to_string() - ); - let hash = sp_crypto_hashing::blake2_128(pallet_signature.as_bytes()); - output.copy_from_slice(&hash); - let query_id_prefix_bytes = - output.map(|byte| syn::LitInt::new(&format!("0x{:X}_u8", byte), Span::call_site())); - + // let instance = pallet.instance.as_ref().into_iter(); + // let path = &pallet.path; + // let pallet_concrete = quote::quote! { + // #pallet_name::<#runtime_name #(, #path::#instance)*> + // }; quote::quote! { - impl #scrate::traits::QueryIdPrefix for #scrate::traits::PalletQueryId<#pallet_name> { - const PREFIX: [::core::primitive::u8; 16usize] = [ #( #query_id_prefix_bytes ),* ]; - } - } - }); - - let query_match_arms = pallet_decls.iter().map(|pallet| { - let pallet_name = &pallet.name; - quote::quote! { - < #scrate::traits::PalletQueryId<#pallet_name> as #scrate::traits::QueryIdPrefix>::PREFIX => { - < #pallet_name as #scrate::traits::DispatchQuery>::dispatch_query(id, input, output) + if id.prefix == <#pallet_name as #scrate::traits::QueryIdPrefix>::prefix() { + return <#pallet_name as #scrate::traits::DispatchQuery>::dispatch_query(id, input, output) } } }); @@ -69,21 +52,15 @@ pub fn expand_outer_query( pub enum #runtime_query {} const _: () = { - #( #query_id_prefix_impls )* - impl #scrate::traits::DispatchQuery for #runtime_query { - #[deny(unreachable_patterns)] // todo: [AJ] should error if identical prefixes fn dispatch_query( id: & #scrate::traits::QueryId, input: &mut &[u8], output: &mut O ) -> Result<(), #scrate::__private::codec::Error> { - // let y = 1; // todo: [AJ] why is unused variable error not triggered here - unused functions? - match id.suffix { - #( #query_match_arms )* - _ => Err(#scrate::__private::codec::Error::from("DispatchQuery not implemented")), // todo: [AJ] - } + #( #prefix_conditionals )* + Err(#scrate::__private::codec::Error::from("todo: no prefix")) } } }; 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 c335221e72a8..2623b0e516d9 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -29,17 +29,44 @@ pub fn expand_view_functions(def: &Def) -> TokenStream { None => (def.item.span(), def.config.where_clause.clone(), Vec::new()), }; + let query_prefix_impl = expand_query_prefix_impl(def, span, where_clause.as_ref()); + let view_fn_impls = view_fns .iter() .map(|view_fn| expand_view_function(def, span, where_clause.as_ref(), view_fn)); let impl_dispatch_query = impl_dispatch_query(def, span, where_clause.as_ref(), &view_fns); quote::quote! { + #query_prefix_impl #( #view_fn_impls )* #impl_dispatch_query } } +fn expand_query_prefix_impl( + def: &Def, + span: Span, + where_clause: Option<&syn::WhereClause>, +) -> TokenStream { + let pallet_ident = &def.pallet_struct.pallet; + let frame_support = &def.frame_support; + let frame_system = &def.frame_system; + let type_impl_gen = &def.type_impl_generics(span); + let type_use_gen = &def.type_use_generics(span); + + quote::quote! { + impl<#type_impl_gen> #frame_support::traits::QueryIdPrefix for #pallet_ident<#type_use_gen> #where_clause { + fn prefix() -> [::core::primitive::u8; 16usize] { + < + ::PalletInfo + as #frame_support::traits::PalletInfo + >::name_hash::>() + .expect("No name_hash found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.") + } + } + } +} + fn expand_view_function( def: &Def, span: Span, @@ -47,12 +74,10 @@ fn expand_view_function( view_fn: &ViewFunctionDef, ) -> TokenStream { let frame_support = &def.frame_support; - let frame_system = &def.frame_system; let pallet_ident = &def.pallet_struct.pallet; let type_impl_gen = &def.type_impl_generics(span); let type_decl_bounded_gen = &def.type_decl_bounded_generics(span); let type_use_gen = &def.type_use_generics(span); - let trait_use_gen = &def.trait_use_generics(span); let capture_docs = if cfg!(feature = "no-metadata-docs") { "never" } else { "always" }; let query_struct_ident = view_fn.query_struct_ident(); @@ -102,10 +127,13 @@ fn expand_view_function( } impl<#type_impl_gen> #frame_support::traits::Query for #query_struct_ident<#type_use_gen> #where_clause { - const ID: #frame_support::traits::QueryId = #frame_support::traits::QueryId { - prefix: <::RuntimeQuery as #frame_support::traits::QueryIdPrefix>::PREFIX, - suffix: ::SUFFIX, // todo: [AJ] handle instantiatable pallet suffix - }; + fn id() -> #frame_support::traits::QueryId { + #frame_support::traits::QueryId { + prefix: <#pallet_ident<#type_use_gen> as #frame_support::traits::QueryIdPrefix>::prefix(), + suffix: ::SUFFIX, + } + } + type ReturnType = #return_type; fn query(self) -> Self::ReturnType { diff --git a/substrate/frame/support/src/traits/query.rs b/substrate/frame/support/src/traits/query.rs index 91ab37d5d4c6..665fc64d989f 100644 --- a/substrate/frame/support/src/traits/query.rs +++ b/substrate/frame/support/src/traits/query.rs @@ -18,6 +18,7 @@ //! Traits for querying pallet view functions. use codec::{Decode, Encode, Output}; +use sp_runtime::RuntimeDebug; /// implemented by the runtime dispatching by prefix and then the pallet dispatching by suffix pub trait DispatchQuery { @@ -38,19 +39,19 @@ impl DispatchQuery for () { } } -impl QueryIdPrefix for () { - const PREFIX: [u8; 16] = [0u8; 16]; -} +// impl QueryIdPrefix for () { +// const PREFIX: [u8; 16] = [0u8; 16]; +// } pub trait QueryIdPrefix { - const PREFIX: [u8; 16]; // same as `PalletInfo::name_hash` twox_128 + fn prefix() -> [u8; 16]; } pub trait QueryIdSuffix { const SUFFIX: [u8; 16]; } -#[derive(Encode, Decode)] +#[derive(Encode, Decode, RuntimeDebug)] pub struct QueryId { pub prefix: [u8; 16], pub suffix: [u8; 16], @@ -58,7 +59,7 @@ pub struct QueryId { /// implemented for each pallet view function method pub trait Query { - const ID: QueryId; + fn id() -> QueryId; type ReturnType: codec::Codec; fn query(self) -> Self::ReturnType; diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs index d0f9bacac82a..165a5e8c7c74 100644 --- a/substrate/frame/system/src/lib.rs +++ b/substrate/frame/system/src/lib.rs @@ -496,8 +496,7 @@ pub mod pallet { /// Type for dispatching queries. #[pallet::no_default_bounds] - type RuntimeQuery: frame_support::traits::QueryIdPrefix - + frame_support::traits::DispatchQuery; + type RuntimeQuery: frame_support::traits::DispatchQuery; /// This stores the number of previous transactions associated with a sender account. type Nonce: Parameter From fd3318b8335ff6b4697ba08cbd72915de820f6f0 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 3 Jun 2024 14:56:15 +0100 Subject: [PATCH 23/45] Commented out code --- .../examples/view-functions/src/tests.rs | 56 +------------------ 1 file changed, 1 insertion(+), 55 deletions(-) diff --git a/substrate/frame/examples/view-functions/src/tests.rs b/substrate/frame/examples/view-functions/src/tests.rs index 0c31105f07a2..3a74f10c78dc 100644 --- a/substrate/frame/examples/view-functions/src/tests.rs +++ b/substrate/frame/examples/view-functions/src/tests.rs @@ -73,58 +73,4 @@ fn pallet_get_value_with_arg_query() { assert_eq!(some_value, query_result,); }); -} - -// pub struct Test(PhantomData); -// -// impl DispatchQuery for Test -// where -// T::AccountId: From + crate::SomeAssociation1, -// { -// #[automatically_derived] -// // #[deny(unreachable_patterns)] -// fn dispatch_query( -// id: &frame_support::traits::QueryId, -// input: &mut &[u8], -// output: &mut O, -// ) -> Result<(), codec::Error> { -// match id.suffix { -// as frame_support::traits::QueryIdSuffix>::SUFFIX => { -// let query = as codec::DecodeAll>::decode_all(input)?; -// let result = as frame_support::traits::Query>::query(query); -// let output = codec::Encode::encode_to( -// &result, -// output, -// ); -// ::core::result::Result::Ok(output) -// } -// as frame_support::traits::QueryIdSuffix>::SUFFIX => { -// let query = as codec::DecodeAll>::decode_all(input)?; -// let result = as frame_support::traits::Query>::query(query); -// let output = codec::Encode::encode_to( -// &result, -// output, -// ); -// ::core::result::Result::Ok(output) -// } -// _ => { -// Err( -// codec::Error::from( -// "DispatchQuery not implemented", -// ), -// ) -// } -// } -// } -// -// } +} \ No newline at end of file From a49e5f3e79eab3399321950cbbafd6152f9ea632 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 3 Jun 2024 15:25:58 +0100 Subject: [PATCH 24/45] Inject runtime type --- substrate/frame/examples/view-functions/src/tests.rs | 10 +++++++++- .../procedural/src/construct_runtime/expand/query.rs | 6 +----- substrate/frame/system/src/lib.rs | 1 + 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/substrate/frame/examples/view-functions/src/tests.rs b/substrate/frame/examples/view-functions/src/tests.rs index 3a74f10c78dc..a9b9f8acad4a 100644 --- a/substrate/frame/examples/view-functions/src/tests.rs +++ b/substrate/frame/examples/view-functions/src/tests.rs @@ -36,9 +36,17 @@ fn pallet_get_value_query() { let input = query.encode(); let mut output = Vec::new(); + let id = as Query>::id(); + println!("{id:?}"); + + // let _ = as DispatchQuery>::dispatch_query::>( + // &id, + // &mut &input[..], + // &mut output, + // ).unwrap(); let _ = ::RuntimeQuery::dispatch_query::>( - & as Query>::id(), + &id, &mut &input[..], &mut output, ) diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs index e488e73f6fb8..72b42d6362a3 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs @@ -28,11 +28,6 @@ pub fn expand_outer_query( let prefix_conditionals = pallet_decls.iter().map(|pallet| { let pallet_name = &pallet.name; - // let instance = pallet.instance.as_ref().into_iter(); - // let path = &pallet.path; - // let pallet_concrete = quote::quote! { - // #pallet_name::<#runtime_name #(, #path::#instance)*> - // }; quote::quote! { if id.prefix == <#pallet_name as #scrate::traits::QueryIdPrefix>::prefix() { return <#pallet_name as #scrate::traits::DispatchQuery>::dispatch_query(id, input, output) @@ -59,6 +54,7 @@ pub fn expand_outer_query( output: &mut O ) -> Result<(), #scrate::__private::codec::Error> { + println!("dispatch_query {id:?}"); #( #prefix_conditionals )* Err(#scrate::__private::codec::Error::from("todo: no prefix")) } diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs index 165a5e8c7c74..76b5fddae93b 100644 --- a/substrate/frame/system/src/lib.rs +++ b/substrate/frame/system/src/lib.rs @@ -311,6 +311,7 @@ pub mod pallet { type PalletInfo = (); #[inject_runtime_type] type RuntimeTask = (); + #[inject_runtime_type] type RuntimeQuery = (); type BaseCallFilter = frame_support::traits::Everything; type BlockHashCount = TestBlockHashCount>; From dd651acb009ccc7b212767ea3b3062028a0609f6 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 3 Jun 2024 15:28:59 +0100 Subject: [PATCH 25/45] tidy --- substrate/frame/support/src/traits/query.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/substrate/frame/support/src/traits/query.rs b/substrate/frame/support/src/traits/query.rs index 665fc64d989f..a67942eabb61 100644 --- a/substrate/frame/support/src/traits/query.rs +++ b/substrate/frame/support/src/traits/query.rs @@ -39,10 +39,6 @@ impl DispatchQuery for () { } } -// impl QueryIdPrefix for () { -// const PREFIX: [u8; 16] = [0u8; 16]; -// } - pub trait QueryIdPrefix { fn prefix() -> [u8; 16]; } From c7ff6c997db1d860fdf2ffbae3476b1f4360ec1b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 3 Jun 2024 20:42:58 +0100 Subject: [PATCH 26/45] Add pallet with instances --- .../frame/examples/view-functions/src/lib.rs | 41 +++++++++++++++++-- .../frame/examples/view-functions/src/mock.rs | 11 +++-- .../examples/view-functions/src/tests.rs | 9 +--- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/substrate/frame/examples/view-functions/src/lib.rs b/substrate/frame/examples/view-functions/src/lib.rs index d94e60e2d913..924dcca98df8 100644 --- a/substrate/frame/examples/view-functions/src/lib.rs +++ b/substrate/frame/examples/view-functions/src/lib.rs @@ -24,9 +24,6 @@ pub mod tests; use frame_support::Parameter; use scale_info::TypeInfo; -// Re-export pallet items so that they can be accessed from the crate namespace. -pub use pallet::*; - pub struct SomeType1; impl From for u64 { fn from(_t: SomeType1) -> Self { @@ -77,3 +74,41 @@ pub mod pallet { } } } + +#[frame_support::pallet] +pub mod pallet2 { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::error] + pub enum Error {} + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(PhantomData<(T, I)>); + + #[pallet::storage] + pub type SomeValue, I: 'static = ()> = StorageValue<_, u32>; + + #[pallet::storage] + pub type SomeMap, I: 'static = ()> = + StorageMap<_, Twox64Concat, u32, u32, OptionQuery>; + + #[pallet::view_functions] + impl, I: 'static> Pallet + where + T::AccountId: From + SomeAssociation1, + { + /// Query value no args. + pub fn get_value() -> Option { + SomeValue::::get() + } + + /// Query value with args. + pub fn get_value_with_arg(key: u32) -> Option { + SomeMap::::get(key) + } + } +} diff --git a/substrate/frame/examples/view-functions/src/mock.rs b/substrate/frame/examples/view-functions/src/mock.rs index d128c619598a..4df30553097e 100644 --- a/substrate/frame/examples/view-functions/src/mock.rs +++ b/substrate/frame/examples/view-functions/src/mock.rs @@ -18,7 +18,7 @@ //! Mock runtime for `view-functions-example` tests. #![cfg(test)] -use crate::{self as view_functions_example}; +use crate::{pallet, pallet2}; use frame_support::derive_impl; use sp_runtime::testing::TestXt; @@ -29,7 +29,9 @@ type Block = frame_system::mocking::MockBlock; frame_support::construct_runtime!( pub enum Runtime { System: frame_system, - ViewFunctionsExample: view_functions_example, + ViewFunctionsExample: pallet, + ViewFunctionsInstance: pallet2, + // ViewFunctionsInstance: pallet2::, } ); @@ -40,7 +42,10 @@ impl frame_system::Config for Runtime { type Block = Block; } -impl view_functions_example::Config for Runtime {} +impl pallet::Config for Runtime {} +impl pallet2::Config for Runtime {} + +impl pallet2::Config for Runtime {} pub fn new_test_ext() -> sp_io::TestExternalities { use sp_runtime::BuildStorage; diff --git a/substrate/frame/examples/view-functions/src/tests.rs b/substrate/frame/examples/view-functions/src/tests.rs index a9b9f8acad4a..753a30584f5e 100644 --- a/substrate/frame/examples/view-functions/src/tests.rs +++ b/substrate/frame/examples/view-functions/src/tests.rs @@ -37,13 +37,6 @@ fn pallet_get_value_query() { let mut output = Vec::new(); let id = as Query>::id(); - println!("{id:?}"); - - // let _ = as DispatchQuery>::dispatch_query::>( - // &id, - // &mut &input[..], - // &mut output, - // ).unwrap(); let _ = ::RuntimeQuery::dispatch_query::>( &id, @@ -81,4 +74,4 @@ fn pallet_get_value_with_arg_query() { assert_eq!(some_value, query_result,); }); -} \ No newline at end of file +} From 5a8e559082c0942d3120491ef0e8629acfafcdff Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 3 Jun 2024 21:21:16 +0100 Subject: [PATCH 27/45] Pallet instances tests --- .../frame/examples/view-functions/src/lib.rs | 2 +- .../frame/examples/view-functions/src/mock.rs | 2 +- .../examples/view-functions/src/tests.rs | 44 ++++++++++++++++++- .../src/construct_runtime/expand/query.rs | 1 - 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/substrate/frame/examples/view-functions/src/lib.rs b/substrate/frame/examples/view-functions/src/lib.rs index 924dcca98df8..0dffcf73f9c7 100644 --- a/substrate/frame/examples/view-functions/src/lib.rs +++ b/substrate/frame/examples/view-functions/src/lib.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! This pallet demonstrates the use of the `pallet::task` api for service work. +//! This pallet demonstrates the use of the `pallet::view_functions` api for service work. #![cfg_attr(not(feature = "std"), no_std)] pub mod mock; diff --git a/substrate/frame/examples/view-functions/src/mock.rs b/substrate/frame/examples/view-functions/src/mock.rs index 4df30553097e..549c613cb944 100644 --- a/substrate/frame/examples/view-functions/src/mock.rs +++ b/substrate/frame/examples/view-functions/src/mock.rs @@ -31,7 +31,7 @@ frame_support::construct_runtime!( System: frame_system, ViewFunctionsExample: pallet, ViewFunctionsInstance: pallet2, - // ViewFunctionsInstance: pallet2::, + ViewFunctionsInstance1: pallet2::, } ); diff --git a/substrate/frame/examples/view-functions/src/tests.rs b/substrate/frame/examples/view-functions/src/tests.rs index 753a30584f5e..ad3840bbcd43 100644 --- a/substrate/frame/examples/view-functions/src/tests.rs +++ b/substrate/frame/examples/view-functions/src/tests.rs @@ -15,12 +15,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Tests for `pallet-example-tasks`. +//! Tests for `pallet-example-view-functions`. #![cfg(test)] use crate::{ mock::*, pallet::{self, Pallet}, + pallet2, }; use codec::{Decode, Encode}; use frame_support::traits::{DispatchQuery, Query}; @@ -75,3 +76,44 @@ fn pallet_get_value_with_arg_query() { assert_eq!(some_value, query_result,); }); } + +#[test] +fn pallet_instances() { + use pallet2::Instance1; + + new_test_ext().execute_with(|| { + let instance_value = Some(123); + let instance1_value = Some(456); + + pallet2::SomeValue::::set(instance_value); + pallet2::SomeValue::::set(instance1_value); + + let query = pallet2::GetValueQuery::::new(); + test_dispatch_query::<::RuntimeQuery, _, _>( + query, + instance_value, + ); + + let query_instance1 = pallet2::GetValueQuery::::new(); + test_dispatch_query::<::RuntimeQuery, _, _>( + query_instance1, + instance1_value, + ); + }); +} + +fn test_dispatch_query(query: Q, expected: V) +where + D: DispatchQuery, + Q: Query + Encode, + V: Decode + Eq + PartialEq + std::fmt::Debug, +{ + let input = query.encode(); + let mut output = Vec::new(); + + D::dispatch_query::>(&Q::id(), &mut &input[..], &mut output).unwrap(); + + let query_result = V::decode(&mut &output[..]).unwrap(); + + assert_eq!(expected, query_result,); +} diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs index 72b42d6362a3..437213bcd32d 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs @@ -54,7 +54,6 @@ pub fn expand_outer_query( output: &mut O ) -> Result<(), #scrate::__private::codec::Error> { - println!("dispatch_query {id:?}"); #( #prefix_conditionals )* Err(#scrate::__private::codec::Error::from("todo: no prefix")) } From e71b9de3afe0ad8019055b40f86b2da87b30aa35 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 3 Jun 2024 21:38:45 +0100 Subject: [PATCH 28/45] Refactor tests --- .../examples/view-functions/src/tests.rs | 52 +++++-------------- 1 file changed, 12 insertions(+), 40 deletions(-) diff --git a/substrate/frame/examples/view-functions/src/tests.rs b/substrate/frame/examples/view-functions/src/tests.rs index ad3840bbcd43..f7a61c767ffe 100644 --- a/substrate/frame/examples/view-functions/src/tests.rs +++ b/substrate/frame/examples/view-functions/src/tests.rs @@ -34,21 +34,7 @@ fn pallet_get_value_query() { assert_eq!(some_value, Pallet::::get_value()); let query = pallet::GetValueQuery::::new(); - let input = query.encode(); - let mut output = Vec::new(); - - let id = as Query>::id(); - - let _ = ::RuntimeQuery::dispatch_query::>( - &id, - &mut &input[..], - &mut output, - ) - .unwrap(); - - let query_result = >::decode(&mut &output[..]).unwrap(); - - assert_eq!(some_value, query_result,); + test_dispatch_query(&query, some_value); }); } @@ -61,24 +47,12 @@ fn pallet_get_value_with_arg_query() { assert_eq!(some_value, Pallet::::get_value_with_arg(some_key)); let query = pallet::GetValueWithArgQuery::::new(some_key); - let input = query.encode(); - let mut output = Vec::new(); - - let _ = as DispatchQuery>::dispatch_query::>( - & as Query>::id(), - &mut &input[..], - &mut output, - ) - .unwrap(); - - let query_result = >::decode(&mut &output[..]).unwrap(); - - assert_eq!(some_value, query_result,); + test_dispatch_query(&query, some_value); }); } #[test] -fn pallet_instances() { +fn pallet_multiple_instances() { use pallet2::Instance1; new_test_ext().execute_with(|| { @@ -89,29 +63,27 @@ fn pallet_instances() { pallet2::SomeValue::::set(instance1_value); let query = pallet2::GetValueQuery::::new(); - test_dispatch_query::<::RuntimeQuery, _, _>( - query, - instance_value, - ); + test_dispatch_query(&query, instance_value); let query_instance1 = pallet2::GetValueQuery::::new(); - test_dispatch_query::<::RuntimeQuery, _, _>( - query_instance1, - instance1_value, - ); + test_dispatch_query(&query_instance1, instance1_value); }); } -fn test_dispatch_query(query: Q, expected: V) +fn test_dispatch_query(query: &Q, expected: V) where - D: DispatchQuery, Q: Query + Encode, V: Decode + Eq + PartialEq + std::fmt::Debug, { let input = query.encode(); let mut output = Vec::new(); - D::dispatch_query::>(&Q::id(), &mut &input[..], &mut output).unwrap(); + ::RuntimeQuery::dispatch_query::>( + &Q::id(), + &mut &input[..], + &mut output, + ) + .unwrap(); let query_result = V::decode(&mut &output[..]).unwrap(); From 22dd94b3e1fa3a4976b488d350005b85adb9cddd Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 4 Jun 2024 09:59:47 +0100 Subject: [PATCH 29/45] Move execute from codegen to trait --- .../procedural/src/pallet/expand/view_functions.rs | 5 +---- substrate/frame/support/src/traits/query.rs | 13 ++++++++++--- 2 files changed, 11 insertions(+), 7 deletions(-) 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 2623b0e516d9..416cbdd365bc 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -159,10 +159,7 @@ fn impl_dispatch_query( let query_struct_ident = view_fn.query_struct_ident(); quote::quote! { <#query_struct_ident<#type_use_gen> as #frame_support::traits::QueryIdSuffix>::SUFFIX => { - let query = <#query_struct_ident<#type_use_gen> as #frame_support::__private::codec::DecodeAll>::decode_all(input)?; - let result = <#query_struct_ident<#type_use_gen> as #frame_support::traits::Query>::query(query); - let output = #frame_support::__private::codec::Encode::encode_to(&result, output); - ::core::result::Result::Ok(output) + <#query_struct_ident<#type_use_gen> as #frame_support::traits::Query>::execute(input, output) } } }); diff --git a/substrate/frame/support/src/traits/query.rs b/substrate/frame/support/src/traits/query.rs index a67942eabb61..69ab4abea319 100644 --- a/substrate/frame/support/src/traits/query.rs +++ b/substrate/frame/support/src/traits/query.rs @@ -17,7 +17,7 @@ //! Traits for querying pallet view functions. -use codec::{Decode, Encode, Output}; +use codec::{Decode, DecodeAll, Encode, Output}; use sp_runtime::RuntimeDebug; /// implemented by the runtime dispatching by prefix and then the pallet dispatching by suffix @@ -54,9 +54,16 @@ pub struct QueryId { } /// implemented for each pallet view function method -pub trait Query { +pub trait Query: DecodeAll { fn id() -> QueryId; - type ReturnType: codec::Codec; + type ReturnType: Encode; fn query(self) -> Self::ReturnType; + + fn execute(input: &mut &[u8], output: &mut O) -> Result<(), codec::Error> { + let query = Self::decode_all(input)?; + let result = query.query(); + Encode::encode_to(&result, output); + Ok(()) + } } From 117ac87e87bf098068e2a7cd44e7f2e4eb5da288 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 4 Jun 2024 15:00:12 +0100 Subject: [PATCH 30/45] WIP query runtime api --- .../src/construct_runtime/expand/query.rs | 4 ++-- .../src/pallet/expand/view_functions.rs | 4 ++-- substrate/frame/support/src/traits.rs | 2 +- substrate/frame/support/src/traits/query.rs | 24 +++++++++++++++---- .../frame/system/rpc/runtime-api/src/lib.rs | 11 +++++++++ 5 files changed, 35 insertions(+), 10 deletions(-) diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs index 437213bcd32d..e981e3095ed6 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs @@ -52,10 +52,10 @@ pub fn expand_outer_query( id: & #scrate::traits::QueryId, input: &mut &[u8], output: &mut O - ) -> Result<(), #scrate::__private::codec::Error> + ) -> Result<(), #scrate::traits::QueryDispatchError> { #( #prefix_conditionals )* - Err(#scrate::__private::codec::Error::from("todo: no prefix")) + Err(#scrate::traits::QueryDispatchError::NotFound(id.clone())) } } }; 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 416cbdd365bc..64f9d822484a 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -173,12 +173,12 @@ fn impl_dispatch_query( fn dispatch_query< O: #frame_support::__private::codec::Output, > - (id: & #frame_support::traits::QueryId, input: &mut &[u8], output: &mut O) -> Result<(), #frame_support::__private::codec::Error> + (id: & #frame_support::traits::QueryId, input: &mut &[u8], output: &mut O) -> Result<(), #frame_support::traits::QueryDispatchError> { // let y = 1; // todo: [AJ] why is unused variable error not triggered here - unused functions? match id.suffix { #( #query_match_arms )* - _ => Err(#frame_support::__private::codec::Error::from("DispatchQuery not implemented")), // todo: [AJ] + _ => Err(#frame_support::traits::QueryDispatchError::NotFound(id.clone())), } } } diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 40a2e954539b..df6bcb615846 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -134,7 +134,7 @@ pub use tasks::Task; mod try_runtime; mod query; -pub use query::{DispatchQuery, Query, QueryId, QueryIdPrefix, QueryIdSuffix}; +pub use query::{DispatchQuery, Query, QueryDispatchError, QueryId, QueryIdPrefix, QueryIdSuffix}; #[cfg(feature = "try-runtime")] pub use try_runtime::{ diff --git a/substrate/frame/support/src/traits/query.rs b/substrate/frame/support/src/traits/query.rs index 69ab4abea319..ce753994b2ba 100644 --- a/substrate/frame/support/src/traits/query.rs +++ b/substrate/frame/support/src/traits/query.rs @@ -26,7 +26,7 @@ pub trait DispatchQuery { id: &QueryId, input: &mut &[u8], output: &mut O, - ) -> Result<(), codec::Error>; + ) -> Result<(), QueryDispatchError>; } impl DispatchQuery for () { @@ -34,8 +34,8 @@ impl DispatchQuery for () { _id: &QueryId, _input: &mut &[u8], _output: &mut O, - ) -> Result<(), codec::Error> { - Err(codec::Error::from("DispatchQuery not implemented")) // todo: return "query not found" error? + ) -> Result<(), QueryDispatchError> { + Err(QueryDispatchError::NotImplemented) } } @@ -47,12 +47,26 @@ pub trait QueryIdSuffix { const SUFFIX: [u8; 16]; } -#[derive(Encode, Decode, RuntimeDebug)] +#[derive(Clone, Encode, Decode, RuntimeDebug)] pub struct QueryId { pub prefix: [u8; 16], pub suffix: [u8; 16], } +#[derive(Encode, Decode, RuntimeDebug)] + +pub enum QueryDispatchError { + NotImplemented, + NotFound(QueryId), + Codec(String), +} + +impl From for QueryDispatchError { + fn from(e: codec::Error) -> Self { + QueryDispatchError::Codec(codec::Error::to_string(&e)) + } +} + /// implemented for each pallet view function method pub trait Query: DecodeAll { fn id() -> QueryId; @@ -60,7 +74,7 @@ pub trait Query: DecodeAll { fn query(self) -> Self::ReturnType; - fn execute(input: &mut &[u8], output: &mut O) -> Result<(), codec::Error> { + fn execute(input: &mut &[u8], output: &mut O) -> Result<(), QueryDispatchError> { let query = Self::decode_all(input)?; let result = query.query(); Encode::encode_to(&result, output); diff --git a/substrate/frame/system/rpc/runtime-api/src/lib.rs b/substrate/frame/system/rpc/runtime-api/src/lib.rs index f59988d818f0..8257980dc408 100644 --- a/substrate/frame/system/rpc/runtime-api/src/lib.rs +++ b/substrate/frame/system/rpc/runtime-api/src/lib.rs @@ -32,4 +32,15 @@ sp_api::decl_runtime_apis! { /// Get current account nonce of given `AccountId`. fn account_nonce(account: AccountId) -> Nonce; } + + /// API for executing view function queries + pub trait ViewFunctionsApi where + QueryId: codec::Codec, + Query: codec::Codec, + QueryResult: codec::Codec, + Error: codec::Codec, + { + /// Execute a view function query. + fn execute_query(query_id: QueryId, query: Query) -> Result; + } } From def7807da09eec2e39eda96c2e4a48c309068316 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 5 Jun 2024 17:52:53 +0100 Subject: [PATCH 31/45] WIP query metadata --- .../src/construct_runtime/expand/metadata.rs | 16 +++- .../src/pallet/expand/view_functions.rs | 87 +++++++++++++++---- .../src/pallet/parse/view_functions.rs | 18 ++-- substrate/frame/support/src/traits/query.rs | 9 ++ substrate/primitives/metadata-ir/src/types.rs | 74 ++++++++++++++++ 5 files changed, 174 insertions(+), 30 deletions(-) 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 0e76f9a92469..37ee684b0f8b 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs @@ -75,6 +75,18 @@ pub fn expand_runtime_metadata( }) .collect::>(); + let queries = pallet_declarations.iter().map(|decl| { + let name = &decl.name; + let path = &decl.path; + let instance = decl.instance.as_ref().into_iter(); + + quote! { + #path::Pallet::<#runtime #(, #path::#instance)*>::pallet_queries_metadata( + ::core::stringify!(#name) + ) + } + }); + quote! { impl #runtime { fn metadata_ir() -> #scrate::__private::metadata_ir::MetadataIR { @@ -140,7 +152,9 @@ pub fn expand_runtime_metadata( >(), event_enum_ty: #scrate::__private::scale_info::meta_type::(), error_enum_ty: #scrate::__private::scale_info::meta_type::(), - } + }, + queries: #scrate::__private::sp_std::vec![], + // queries: #scrate::__private::sp_std::vec![ #(#queries),* ], } } 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 64f9d822484a..df246cf2514a 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -20,13 +20,14 @@ use proc_macro2::{Span, TokenStream}; use syn::spanned::Spanned; pub fn expand_view_functions(def: &Def) -> TokenStream { - let (span, where_clause, view_fns) = match def.view_functions.as_ref() { + let (span, where_clause, view_fns, docs) = match def.view_functions.as_ref() { Some(view_fns) => ( view_fns.attr_span.clone(), 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()), + None => (def.item.span(), def.config.where_clause.clone(), Vec::new(), Vec::new()), }; let query_prefix_impl = expand_query_prefix_impl(def, span, where_clause.as_ref()); @@ -35,11 +36,14 @@ pub fn expand_view_functions(def: &Def) -> TokenStream { .iter() .map(|view_fn| expand_view_function(def, span, where_clause.as_ref(), view_fn)); let impl_dispatch_query = impl_dispatch_query(def, span, where_clause.as_ref(), &view_fns); + let impl_query_metadata = + impl_query_metadata(def, span, where_clause.as_ref(), &view_fns, &docs); quote::quote! { #query_prefix_impl #( #view_fn_impls )* #impl_dispatch_query + // #impl_query_metadata } } @@ -165,23 +169,72 @@ fn impl_dispatch_query( }); quote::quote! { - const _: () = { - impl<#type_impl_gen> #frame_support::traits::DispatchQuery - for #pallet_ident<#type_use_gen> #where_clause + impl<#type_impl_gen> #frame_support::traits::DispatchQuery + for #pallet_ident<#type_use_gen> #where_clause + { + #[deny(unreachable_patterns)] + fn dispatch_query< + O: #frame_support::__private::codec::Output, + > + (id: & #frame_support::traits::QueryId, input: &mut &[u8], output: &mut O) -> Result<(), #frame_support::traits::QueryDispatchError> { - #[deny(unreachable_patterns)] // todo: [AJ] should error if identical suffixes, does not atm - fn dispatch_query< - O: #frame_support::__private::codec::Output, - > - (id: & #frame_support::traits::QueryId, input: &mut &[u8], output: &mut O) -> Result<(), #frame_support::traits::QueryDispatchError> - { - // let y = 1; // todo: [AJ] why is unused variable error not triggered here - unused functions? - match id.suffix { - #( #query_match_arms )* - _ => Err(#frame_support::traits::QueryDispatchError::NotFound(id.clone())), - } + match id.suffix { + #( #query_match_arms )* + _ => Err(#frame_support::traits::QueryDispatchError::NotFound(id.clone())), } } - }; + } + } +} + +fn impl_query_metadata( + def: &Def, + 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; + let type_impl_gen = &def.type_impl_generics(span); + let type_use_gen = &def.type_use_generics(span); + + let queries = view_fns.iter().map(|view_fn| { + let query_struct_ident = view_fn.query_struct_ident(); + let name = &view_fn.name; + let args: Vec = vec![]; // todo + + let no_docs = vec![]; + let doc = if cfg!(feature = "no-metadata-docs") { &no_docs } else { &view_fn.docs }; + + quote::quote! { + #frame_support::__private::metadata_ir::QueryMetadataIR { + name: #name, + id: <#query_struct_ident<#type_use_gen> as #frame_support::traits::Query>::id().into(), + args: #frame_support::__private::sp_std::vec![ #( #args ),* ], + output: #frame_support::__private::scale_info::meta_type::< + <#query_struct_ident<#type_use_gen> as #frame_support::traits::Query>::ReturnType + >(), + docs: #frame_support::__private::sp_std::vec![ #( #doc ),* ], + } + } + }); + + 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_queries_metadata(name: &'static ::core::primitive::str) + -> #frame_support::__private::metadata_ir::QueryInterfaceIR + { + #frame_support::__private::metadata_ir::QueryInterfaceIR { + name, + queries: #frame_support::__private::sp_std::vec![ #( #queries ),* ], + docs: #frame_support::__private::sp_std::vec![ #( #doc ),* ], + } + } + } } } 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 fa8657c57bac..b21f05ea9f54 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs @@ -12,29 +12,22 @@ // 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 +// See the License for the specific language governsing permissions and // limitations under the License. use frame_support_procedural_tools::get_doc_literals; use inflector::Inflector; use syn::spanned::Spanned; -/// Definition of dispatchables typically `impl Pallet { ... }` +/// todo: docs pub struct ViewFunctionsImplDef { /// The where_clause used. pub where_clause: Option, - // /// A set of usage of instance, must be check for consistency with trait. - // pub instances: Vec, - // /// The index of call item in pallet module. - // pub index: usize, - // /// Information on methods (used for expansion). - // pub methods: Vec, /// The span of the pallet::view_functions attribute. pub attr_span: proc_macro2::Span, - // /// Docs, specified on the impl Block. - // pub docs: Vec, - // /// The optional `weight` attribute on the `pallet::call`. - // pub inherited_call_weight: Option, + /// Docs, specified on the impl Block. + pub docs: Vec, + /// The view function query definitions. pub view_functions: Vec, } @@ -71,6 +64,7 @@ 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/traits/query.rs b/substrate/frame/support/src/traits/query.rs index ce753994b2ba..19d75a24dd3c 100644 --- a/substrate/frame/support/src/traits/query.rs +++ b/substrate/frame/support/src/traits/query.rs @@ -53,6 +53,15 @@ pub struct QueryId { pub suffix: [u8; 16], } +impl From for [u8; 32] { + fn from(value: QueryId) -> Self { + let mut output = [0u8; 32]; + output[..16].copy_from_slice(&value.prefix); + output[16..].copy_from_slice(&value.suffix); + output + } +} + #[derive(Encode, Decode, RuntimeDebug)] pub enum QueryDispatchError { diff --git a/substrate/primitives/metadata-ir/src/types.rs b/substrate/primitives/metadata-ir/src/types.rs index b05f26ff55d4..ddb939e42523 100644 --- a/substrate/primitives/metadata-ir/src/types.rs +++ b/substrate/primitives/metadata-ir/src/types.rs @@ -41,6 +41,8 @@ pub struct MetadataIR { pub apis: Vec>, /// The outer enums types as found in the runtime. pub outer_enums: OuterEnumsIR, + /// Metadata of view function queries + pub queries: Vec>, } /// Metadata of a runtime trait. @@ -112,6 +114,78 @@ impl IntoPortable for RuntimeApiMethodParamMetadataIR { } } +/// Metadata of a runtime query interface. +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub struct QueryInterfaceIR { + /// Name of the query interface. + pub name: T::String, + /// Queries belonging to the query interface. + pub queries: Vec>, + /// Query interface documentation. + pub docs: Vec, +} + +impl IntoPortable for QueryInterfaceIR { + type Output = QueryInterfaceIR; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + QueryInterfaceIR { + name: self.name.into_portable(registry), + queries: registry.map_into_portable(self.queries), + docs: registry.map_into_portable(self.docs), + } + } +} + +/// Metadata of a runtime method. +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub struct QueryMetadataIR { + /// Query name. + pub name: T::String, + /// Query id. + pub id: [u8; 32], + /// Query args. + pub args: Vec>, + /// Query output. + pub output: T::Type, + /// Query documentation. + pub docs: Vec, +} + +impl IntoPortable for QueryMetadataIR { + type Output = QueryMetadataIR; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + QueryMetadataIR { + name: self.name.into_portable(registry), + id: self.id, + args: registry.map_into_portable(self.args), + output: registry.register_type(&self.output), + docs: registry.map_into_portable(self.docs), + } + } +} + +/// Metadata of a runtime method argument. +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub struct QueryArgMetadataIR { + /// Query argument name. + pub name: T::String, + /// Query argument type. + pub ty: T::Type, +} + +impl IntoPortable for QueryArgMetadataIR { + type Output = QueryArgMetadataIR; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + QueryArgMetadataIR { + name: self.name.into_portable(registry), + ty: registry.register_type(&self.ty), + } + } +} + /// The intermediate representation for a pallet metadata. #[derive(Clone, PartialEq, Eq, Encode, Debug)] pub struct PalletMetadataIR { From fbd4d3af792582d26ca86663a5ac9ec388cca04f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 5 Jun 2024 18:21:29 +0100 Subject: [PATCH 32/45] Fix up metadata generation --- .../procedural/src/construct_runtime/expand/metadata.rs | 3 +-- .../support/procedural/src/pallet/expand/view_functions.rs | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) 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 37ee684b0f8b..be47540fc47d 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs @@ -153,8 +153,7 @@ pub fn expand_runtime_metadata( event_enum_ty: #scrate::__private::scale_info::meta_type::(), error_enum_ty: #scrate::__private::scale_info::meta_type::(), }, - queries: #scrate::__private::sp_std::vec![], - // queries: #scrate::__private::sp_std::vec![ #(#queries),* ], + queries: #scrate::__private::sp_std::vec![ #(#queries),* ], } } 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 df246cf2514a..106db12590c4 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -43,7 +43,7 @@ pub fn expand_view_functions(def: &Def) -> TokenStream { #query_prefix_impl #( #view_fn_impls )* #impl_dispatch_query - // #impl_query_metadata + #impl_query_metadata } } @@ -209,7 +209,7 @@ fn impl_query_metadata( quote::quote! { #frame_support::__private::metadata_ir::QueryMetadataIR { - name: #name, + name: ::core::stringify!(#name), id: <#query_struct_ident<#type_use_gen> as #frame_support::traits::Query>::id().into(), args: #frame_support::__private::sp_std::vec![ #( #args ),* ], output: #frame_support::__private::scale_info::meta_type::< From 04d763e79e08f3c365a690f8d087e8cef1da8b6b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 6 Jun 2024 11:56:46 +0100 Subject: [PATCH 33/45] Add queries section to custom metadata --- .../src/construct_runtime/expand/metadata.rs | 7 ++- substrate/primitives/metadata-ir/src/types.rs | 11 +++- substrate/primitives/metadata-ir/src/v15.rs | 52 +++++++++++++------ 3 files changed, 52 insertions(+), 18 deletions(-) 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 be47540fc47d..200651e2614f 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs @@ -153,7 +153,12 @@ pub fn expand_runtime_metadata( event_enum_ty: #scrate::__private::scale_info::meta_type::(), error_enum_ty: #scrate::__private::scale_info::meta_type::(), }, - queries: #scrate::__private::sp_std::vec![ #(#queries),* ], + query: #scrate::__private::metadata_ir::RuntimeQueryIR { + ty: #scrate::__private::scale_info::meta_type::< + <#runtime as #system_path::Config>::RuntimeQuery + >(), + interfaces: #scrate::__private::sp_std::vec![ #(#queries),* ], + } } } diff --git a/substrate/primitives/metadata-ir/src/types.rs b/substrate/primitives/metadata-ir/src/types.rs index ddb939e42523..79855d452d0c 100644 --- a/substrate/primitives/metadata-ir/src/types.rs +++ b/substrate/primitives/metadata-ir/src/types.rs @@ -42,7 +42,7 @@ pub struct MetadataIR { /// The outer enums types as found in the runtime. pub outer_enums: OuterEnumsIR, /// Metadata of view function queries - pub queries: Vec>, + pub query: RuntimeQueryIR, } /// Metadata of a runtime trait. @@ -114,6 +114,15 @@ impl IntoPortable for RuntimeApiMethodParamMetadataIR { } } +/// Metadata of the the runtime query dispatch. +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub struct RuntimeQueryIR { + /// The type implementing the runtime query dispatch. + pub ty: T::Type, + /// The query interfaces metadata. + pub interfaces: Vec>, +} + /// Metadata of a runtime query interface. #[derive(Clone, PartialEq, Eq, Encode, Debug)] pub struct QueryInterfaceIR { diff --git a/substrate/primitives/metadata-ir/src/v15.rs b/substrate/primitives/metadata-ir/src/v15.rs index a942eb73223b..71fe16384d6f 100644 --- a/substrate/primitives/metadata-ir/src/v15.rs +++ b/substrate/primitives/metadata-ir/src/v15.rs @@ -17,31 +17,51 @@ //! Convert the IR to V15 metadata. -use crate::OuterEnumsIR; - use super::types::{ - ExtrinsicMetadataIR, MetadataIR, PalletMetadataIR, RuntimeApiMetadataIR, + ExtrinsicMetadataIR, MetadataIR, OuterEnumsIR, PalletMetadataIR, RuntimeApiMetadataIR, RuntimeApiMethodMetadataIR, RuntimeApiMethodParamMetadataIR, SignedExtensionMetadataIR, }; use frame_metadata::v15::{ - CustomMetadata, ExtrinsicMetadata, OuterEnums, PalletMetadata, RuntimeApiMetadata, - RuntimeApiMethodMetadata, RuntimeApiMethodParamMetadata, RuntimeMetadataV15, - SignedExtensionMetadata, + CustomMetadata, CustomValueMetadata, ExtrinsicMetadata, OuterEnums, PalletMetadata, + RuntimeApiMetadata, RuntimeApiMethodMetadata, RuntimeApiMethodParamMetadata, + RuntimeMetadataV15, SignedExtensionMetadata, }; +use scale_info::{IntoPortable, Registry}; impl From for RuntimeMetadataV15 { fn from(ir: MetadataIR) -> Self { - RuntimeMetadataV15::new( - ir.pallets.into_iter().map(Into::into).collect(), - ir.extrinsic.into(), - ir.ty, - ir.apis.into_iter().map(Into::into).collect(), - ir.outer_enums.into(), - // Substrate does not collect yet the custom metadata fields. - // This allows us to extend the V15 easily. - CustomMetadata { map: Default::default() }, - ) + let mut registry = Registry::new(); + let pallets = + registry.map_into_portable(ir.pallets.into_iter().map(Into::::into)); + let extrinsic = Into::::into(ir.extrinsic).into_portable(&mut registry); + let ty = registry.register_type(&ir.ty); + let apis = + registry.map_into_portable(ir.apis.into_iter().map(Into::::into)); + let outer_enums = Into::::into(ir.outer_enums).into_portable(&mut registry); + + // todo: serialize queries into custom, add tests. + let query_interfaces = registry.map_into_portable(ir.query.interfaces.into_iter()); + let queries_custom_metadata = CustomValueMetadata { + ty: ir.query.ty, + value: codec::Encode::encode(&query_interfaces), + } + .into_portable(&mut registry); + let mut custom_map = std::collections::BTreeMap::new(); + custom_map.insert("queries".to_string(), queries_custom_metadata); + let custom = CustomMetadata { map: custom_map }; + + Self { types: registry.into(), pallets, extrinsic, ty, apis, outer_enums, custom } + // RuntimeMetadataV15::new( + // ir.pallets.into_iter().map(Into::into).collect(), + // ir.extrinsic.into(), + // ir.ty, + // ir.apis.into_iter().map(Into::into).collect(), + // ir.outer_enums.into(), + // // Substrate does not collect yet the custom metadata fields. + // // This allows us to extend the V15 easily. + // CustomMetadata { map: Default::default() }, + // ) } } From 86f35eb120fec7835b445de7e22da34b76e5540f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 6 Jun 2024 11:57:24 +0100 Subject: [PATCH 34/45] Comment --- substrate/primitives/metadata-ir/src/v15.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/substrate/primitives/metadata-ir/src/v15.rs b/substrate/primitives/metadata-ir/src/v15.rs index 71fe16384d6f..5c26d1152c64 100644 --- a/substrate/primitives/metadata-ir/src/v15.rs +++ b/substrate/primitives/metadata-ir/src/v15.rs @@ -40,7 +40,7 @@ impl From for RuntimeMetadataV15 { registry.map_into_portable(ir.apis.into_iter().map(Into::::into)); let outer_enums = Into::::into(ir.outer_enums).into_portable(&mut registry); - // todo: serialize queries into custom, add tests. + // todo: add tests. let query_interfaces = registry.map_into_portable(ir.query.interfaces.into_iter()); let queries_custom_metadata = CustomValueMetadata { ty: ir.query.ty, @@ -52,16 +52,6 @@ impl From for RuntimeMetadataV15 { let custom = CustomMetadata { map: custom_map }; Self { types: registry.into(), pallets, extrinsic, ty, apis, outer_enums, custom } - // RuntimeMetadataV15::new( - // ir.pallets.into_iter().map(Into::into).collect(), - // ir.extrinsic.into(), - // ir.ty, - // ir.apis.into_iter().map(Into::into).collect(), - // ir.outer_enums.into(), - // // Substrate does not collect yet the custom metadata fields. - // // This allows us to extend the V15 easily. - // CustomMetadata { map: Default::default() }, - // ) } } From 885fd3ab4f5b6e2caf94f66604cdc5cda1f0512c Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 6 Jun 2024 15:09:59 +0100 Subject: [PATCH 35/45] fix metadata gen --- substrate/primitives/metadata-ir/src/v15.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/substrate/primitives/metadata-ir/src/v15.rs b/substrate/primitives/metadata-ir/src/v15.rs index 5c26d1152c64..d6ff6cb93845 100644 --- a/substrate/primitives/metadata-ir/src/v15.rs +++ b/substrate/primitives/metadata-ir/src/v15.rs @@ -27,7 +27,9 @@ use frame_metadata::v15::{ RuntimeApiMetadata, RuntimeApiMethodMetadata, RuntimeApiMethodParamMetadata, RuntimeMetadataV15, SignedExtensionMetadata, }; -use scale_info::{IntoPortable, Registry}; +use scale_info::{ + IntoPortable, Registry +}; impl From for RuntimeMetadataV15 { fn from(ir: MetadataIR) -> Self { @@ -45,11 +47,10 @@ impl From for RuntimeMetadataV15 { let queries_custom_metadata = CustomValueMetadata { ty: ir.query.ty, value: codec::Encode::encode(&query_interfaces), - } - .into_portable(&mut registry); - let mut custom_map = std::collections::BTreeMap::new(); - custom_map.insert("queries".to_string(), queries_custom_metadata); - let custom = CustomMetadata { map: custom_map }; + }; + let mut custom_map = scale_info::prelude::collections::BTreeMap::new(); + custom_map.insert("queries", queries_custom_metadata); + let custom = CustomMetadata { map: custom_map }.into_portable(&mut registry); Self { types: registry.into(), pallets, extrinsic, ty, apis, outer_enums, custom } } From 3b563fbb7f690f6e7290df573f6fc64307cf3160 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 6 Jun 2024 17:40:40 +0100 Subject: [PATCH 36/45] move runtime api and core types to primitives --- substrate/bin/node/runtime/src/lib.rs | 8 ++++- .../src/construct_runtime/expand/query.rs | 6 ++-- .../src/pallet/expand/view_functions.rs | 8 ++--- substrate/frame/support/src/lib.rs | 2 +- substrate/frame/support/src/traits.rs | 2 +- substrate/frame/support/src/traits/query.rs | 33 ++----------------- .../frame/system/rpc/runtime-api/src/lib.rs | 11 ------- substrate/primitives/api/src/lib.rs | 9 ++++- substrate/primitives/core/src/lib.rs | 31 +++++++++++++++++ substrate/primitives/metadata-ir/src/v15.rs | 4 +-- 10 files changed, 58 insertions(+), 56 deletions(-) diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 7d9128bb940a..218d0ac1164c 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -86,7 +86,7 @@ use sp_consensus_beefy::{ mmr::MmrLeafVersion, }; use sp_consensus_grandpa::AuthorityId as GrandpaId; -use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; +use sp_core::{crypto::KeyTypeId, OpaqueMetadata, QueryDispatchError, QueryId}; use sp_inherents::{CheckInherentsResult, InherentData}; use sp_runtime::{ create_runtime_str, @@ -2683,6 +2683,12 @@ impl_runtime_apis! { } } + impl sp_api::RuntimeQuery for Runtime { + fn execute_query(query_id: QueryId, query: Vec) -> Result, QueryDispatchError> { + todo!() + } + } + impl sp_block_builder::BlockBuilder for Runtime { fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { Executive::apply_extrinsic(extrinsic) diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs index e981e3095ed6..4de6adfd0fa7 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs @@ -49,13 +49,13 @@ pub fn expand_outer_query( const _: () = { impl #scrate::traits::DispatchQuery for #runtime_query { fn dispatch_query( - id: & #scrate::traits::QueryId, + id: & #scrate::__private::QueryId, input: &mut &[u8], output: &mut O - ) -> Result<(), #scrate::traits::QueryDispatchError> + ) -> Result<(), #scrate::__private::QueryDispatchError> { #( #prefix_conditionals )* - Err(#scrate::traits::QueryDispatchError::NotFound(id.clone())) + Err(#scrate::__private::QueryDispatchError::NotFound(id.clone())) } } }; 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 106db12590c4..7e8cf5f52bce 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/view_functions.rs @@ -131,8 +131,8 @@ fn expand_view_function( } impl<#type_impl_gen> #frame_support::traits::Query for #query_struct_ident<#type_use_gen> #where_clause { - fn id() -> #frame_support::traits::QueryId { - #frame_support::traits::QueryId { + fn id() -> #frame_support::__private::QueryId { + #frame_support::__private::QueryId { prefix: <#pallet_ident<#type_use_gen> as #frame_support::traits::QueryIdPrefix>::prefix(), suffix: ::SUFFIX, } @@ -176,11 +176,11 @@ fn impl_dispatch_query( fn dispatch_query< O: #frame_support::__private::codec::Output, > - (id: & #frame_support::traits::QueryId, input: &mut &[u8], output: &mut O) -> Result<(), #frame_support::traits::QueryDispatchError> + (id: & #frame_support::__private::QueryId, input: &mut &[u8], output: &mut O) -> Result<(), #frame_support::__private::QueryDispatchError> { match id.suffix { #( #query_match_arms )* - _ => Err(#frame_support::traits::QueryDispatchError::NotFound(id.clone())), + _ => Err(#frame_support::__private::QueryDispatchError::NotFound(id.clone())), } } } diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 8ae1f56b4d68..377e7730c7cd 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -44,7 +44,7 @@ pub mod __private { pub use paste; pub use scale_info; pub use serde; - pub use sp_core::{Get, OpaqueMetadata, Void}; + pub use sp_core::{Get, OpaqueMetadata, QueryDispatchError, QueryId, Void}; pub use sp_crypto_hashing_proc_macro; pub use sp_inherents; #[cfg(feature = "std")] diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index df6bcb615846..e18679c0fd92 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -134,7 +134,7 @@ pub use tasks::Task; mod try_runtime; mod query; -pub use query::{DispatchQuery, Query, QueryDispatchError, QueryId, QueryIdPrefix, QueryIdSuffix}; +pub use query::{DispatchQuery, Query, QueryIdPrefix, QueryIdSuffix}; #[cfg(feature = "try-runtime")] pub use try_runtime::{ diff --git a/substrate/frame/support/src/traits/query.rs b/substrate/frame/support/src/traits/query.rs index 19d75a24dd3c..a07d04103703 100644 --- a/substrate/frame/support/src/traits/query.rs +++ b/substrate/frame/support/src/traits/query.rs @@ -17,8 +17,8 @@ //! Traits for querying pallet view functions. -use codec::{Decode, DecodeAll, Encode, Output}; -use sp_runtime::RuntimeDebug; +use codec::{DecodeAll, Encode, Output}; +use sp_core::{QueryDispatchError, QueryId}; /// implemented by the runtime dispatching by prefix and then the pallet dispatching by suffix pub trait DispatchQuery { @@ -47,35 +47,6 @@ pub trait QueryIdSuffix { const SUFFIX: [u8; 16]; } -#[derive(Clone, Encode, Decode, RuntimeDebug)] -pub struct QueryId { - pub prefix: [u8; 16], - pub suffix: [u8; 16], -} - -impl From for [u8; 32] { - fn from(value: QueryId) -> Self { - let mut output = [0u8; 32]; - output[..16].copy_from_slice(&value.prefix); - output[16..].copy_from_slice(&value.suffix); - output - } -} - -#[derive(Encode, Decode, RuntimeDebug)] - -pub enum QueryDispatchError { - NotImplemented, - NotFound(QueryId), - Codec(String), -} - -impl From for QueryDispatchError { - fn from(e: codec::Error) -> Self { - QueryDispatchError::Codec(codec::Error::to_string(&e)) - } -} - /// implemented for each pallet view function method pub trait Query: DecodeAll { fn id() -> QueryId; diff --git a/substrate/frame/system/rpc/runtime-api/src/lib.rs b/substrate/frame/system/rpc/runtime-api/src/lib.rs index 8257980dc408..f59988d818f0 100644 --- a/substrate/frame/system/rpc/runtime-api/src/lib.rs +++ b/substrate/frame/system/rpc/runtime-api/src/lib.rs @@ -32,15 +32,4 @@ sp_api::decl_runtime_apis! { /// Get current account nonce of given `AccountId`. fn account_nonce(account: AccountId) -> Nonce; } - - /// API for executing view function queries - pub trait ViewFunctionsApi where - QueryId: codec::Codec, - Query: codec::Codec, - QueryResult: codec::Codec, - Error: codec::Codec, - { - /// Execute a view function query. - fn execute_query(query_id: QueryId, query: Query) -> Result; - } } diff --git a/substrate/primitives/api/src/lib.rs b/substrate/primitives/api/src/lib.rs index 20f989c4882e..595f00de1d3e 100644 --- a/substrate/primitives/api/src/lib.rs +++ b/substrate/primitives/api/src/lib.rs @@ -112,7 +112,7 @@ pub mod __private { #[cfg(feature = "std")] pub use sp_core::traits::CallContext; -use sp_core::OpaqueMetadata; +use sp_core::{OpaqueMetadata, QueryDispatchError, QueryId}; #[cfg(feature = "std")] use sp_externalities::{Extension, Extensions}; #[cfg(feature = "std")] @@ -124,6 +124,7 @@ use sp_runtime::{traits::Block as BlockT, ExtrinsicInclusionMode}; pub use sp_state_machine::StorageProof; #[cfg(feature = "std")] use sp_state_machine::{backend::AsTrieBackend, Backend as StateBackend, OverlayedChanges}; +use sp_std::vec::Vec; use sp_version::RuntimeVersion; #[cfg(feature = "std")] use std::cell::RefCell; @@ -834,6 +835,12 @@ decl_runtime_apis! { /// This can be used to call `metadata_at_version`. fn metadata_versions() -> sp_std::vec::Vec; } + + /// API for executing view function queriess + pub trait RuntimeQuery where { + /// Execute a view function query. + fn execute_query(query_id: QueryId, query: Vec) -> Result, QueryDispatchError>; + } } sp_core::generate_feature_enabled_macro!(std_enabled, feature = "std", $); diff --git a/substrate/primitives/core/src/lib.rs b/substrate/primitives/core/src/lib.rs index 098bd135bfeb..6df0fb4058b9 100644 --- a/substrate/primitives/core/src/lib.rs +++ b/substrate/primitives/core/src/lib.rs @@ -323,6 +323,37 @@ pub fn to_substrate_wasm_fn_return_value(value: &impl Encode) -> u64 { #[derive(Clone, Decode, Encode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum Void {} +/// todo: [AJ] docs +#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] + +pub enum QueryDispatchError { + NotImplemented, + NotFound(QueryId), + Codec, +} + +impl From for QueryDispatchError { + fn from(_: codec::Error) -> Self { + QueryDispatchError::Codec + } +} + +/// todo: [AJ] docs +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct QueryId { + pub prefix: [u8; 16], + pub suffix: [u8; 16], +} + +impl From for [u8; 32] { + fn from(value: QueryId) -> Self { + let mut output = [0u8; 32]; + output[..16].copy_from_slice(&value.prefix); + output[16..].copy_from_slice(&value.suffix); + output + } +} + /// Macro for creating `Maybe*` marker traits. /// /// Such a maybe-marker trait requires the given bound when `feature = std` and doesn't require diff --git a/substrate/primitives/metadata-ir/src/v15.rs b/substrate/primitives/metadata-ir/src/v15.rs index d6ff6cb93845..55c43204c8b8 100644 --- a/substrate/primitives/metadata-ir/src/v15.rs +++ b/substrate/primitives/metadata-ir/src/v15.rs @@ -27,9 +27,7 @@ use frame_metadata::v15::{ RuntimeApiMetadata, RuntimeApiMethodMetadata, RuntimeApiMethodParamMetadata, RuntimeMetadataV15, SignedExtensionMetadata, }; -use scale_info::{ - IntoPortable, Registry -}; +use scale_info::{IntoPortable, Registry}; impl From for RuntimeMetadataV15 { fn from(ir: MetadataIR) -> Self { From 43de84102c78afbb3714f4975a8d4156b32156c0 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 7 Jun 2024 11:06:44 +0100 Subject: [PATCH 37/45] Add some RuntimeQuery types --- substrate/frame/support/src/dispatch.rs | 2 ++ substrate/frame/support/src/storage/generator/mod.rs | 2 ++ substrate/frame/support/src/tests/mod.rs | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index 4a313551aca6..718bdbfa863a 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -696,6 +696,7 @@ mod weight_tests { type RuntimeOrigin; type RuntimeCall; type RuntimeTask; + type RuntimeQuery; type PalletInfo: crate::traits::PalletInfo; type DbWeight: Get; } @@ -793,6 +794,7 @@ mod weight_tests { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type RuntimeTask = RuntimeTask; + type RuntimeQuery = RuntimeQuery; type DbWeight = DbWeight; type PalletInfo = PalletInfo; } diff --git a/substrate/frame/support/src/storage/generator/mod.rs b/substrate/frame/support/src/storage/generator/mod.rs index dd6d622852db..5a0bd1e59377 100644 --- a/substrate/frame/support/src/storage/generator/mod.rs +++ b/substrate/frame/support/src/storage/generator/mod.rs @@ -64,6 +64,7 @@ mod tests { type RuntimeOrigin; type RuntimeCall; type RuntimeTask; + type RuntimeQuery; type PalletInfo: crate::traits::PalletInfo; type DbWeight: Get; } @@ -131,6 +132,7 @@ mod tests { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type RuntimeTask = RuntimeTask; + type RuntimeQuery = RuntimeQuery; type PalletInfo = PalletInfo; type DbWeight = (); } diff --git a/substrate/frame/support/src/tests/mod.rs b/substrate/frame/support/src/tests/mod.rs index 88afa243f093..26a5fb4685e0 100644 --- a/substrate/frame/support/src/tests/mod.rs +++ b/substrate/frame/support/src/tests/mod.rs @@ -54,6 +54,8 @@ pub mod frame_system { type PalletInfo = (); #[inject_runtime_type] type RuntimeTask = (); + #[inject_runtime_type] + type RuntimeQuery = (); type DbWeight = (); } } @@ -76,6 +78,8 @@ pub mod frame_system { #[pallet::no_default_bounds] type RuntimeTask: crate::traits::tasks::Task; #[pallet::no_default_bounds] + type RuntimeQuery: crate::traits::DispatchQuery; + #[pallet::no_default_bounds] type PalletInfo: crate::traits::PalletInfo; type DbWeight: Get; } From ebcf28304b274d7367a2671a6010a442ba132169 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 7 Jun 2024 14:10:45 +0100 Subject: [PATCH 38/45] Fix up westend runtime --- polkadot/runtime/westend/src/lib.rs | 3 ++- substrate/bin/node/runtime/src/lib.rs | 3 ++- .../frame/support/procedural/src/runtime/expand/mod.rs | 6 ++++++ .../support/procedural/src/runtime/parse/runtime_types.rs | 4 ++++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index e6790329959e..dee5107333e4 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1429,7 +1429,8 @@ mod runtime { RuntimeHoldReason, RuntimeSlashReason, RuntimeLockId, - RuntimeTask + RuntimeTask, + RuntimeQuery, )] pub struct Runtime; diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 218d0ac1164c..978e30f8ece7 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -2243,7 +2243,8 @@ mod runtime { RuntimeHoldReason, RuntimeSlashReason, RuntimeLockId, - RuntimeTask + RuntimeTask, + RuntimeQuery, )] pub struct Runtime; diff --git a/substrate/frame/support/procedural/src/runtime/expand/mod.rs b/substrate/frame/support/procedural/src/runtime/expand/mod.rs index 43f11896808c..549ce8b7b858 100644 --- a/substrate/frame/support/procedural/src/runtime/expand/mod.rs +++ b/substrate/frame/support/procedural/src/runtime/expand/mod.rs @@ -176,6 +176,7 @@ fn construct_runtime_final_expansion( let mut slash_reason = None; let mut lock_id = None; let mut task = None; + let mut query = None; for runtime_type in runtime_types.iter() { match runtime_type { @@ -218,6 +219,9 @@ fn construct_runtime_final_expansion( RuntimeType::RuntimeTask(_) => { task = Some(expand::expand_outer_task(&name, &pallets, &scrate)); }, + RuntimeType::RuntimeQuery(_) => { + query = Some(expand::expand_outer_query(&name, &pallets, &scrate)); + }, } } @@ -295,6 +299,8 @@ fn construct_runtime_final_expansion( #task + #query + #metadata #outer_config diff --git a/substrate/frame/support/procedural/src/runtime/parse/runtime_types.rs b/substrate/frame/support/procedural/src/runtime/parse/runtime_types.rs index a4480e2a1fd3..7e779aff9080 100644 --- a/substrate/frame/support/procedural/src/runtime/parse/runtime_types.rs +++ b/substrate/frame/support/procedural/src/runtime/parse/runtime_types.rs @@ -32,6 +32,7 @@ mod keyword { custom_keyword!(RuntimeSlashReason); custom_keyword!(RuntimeLockId); custom_keyword!(RuntimeTask); + custom_keyword!(RuntimeQuery); } #[derive(Debug, Clone, PartialEq)] @@ -45,6 +46,7 @@ pub enum RuntimeType { RuntimeSlashReason(keyword::RuntimeSlashReason), RuntimeLockId(keyword::RuntimeLockId), RuntimeTask(keyword::RuntimeTask), + RuntimeQuery(keyword::RuntimeQuery), } impl Parse for RuntimeType { @@ -69,6 +71,8 @@ impl Parse for RuntimeType { Ok(Self::RuntimeLockId(input.parse()?)) } else if lookahead.peek(keyword::RuntimeTask) { Ok(Self::RuntimeTask(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeQuery) { + Ok(Self::RuntimeQuery(input.parse()?)) } else { Err(lookahead.error()) } From f0b1f3655e21d7dac8f596a404c587250c8837f6 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 7 Jun 2024 14:13:00 +0100 Subject: [PATCH 39/45] Add RuntimeQuery derives --- substrate/frame/support/procedural/src/lib.rs | 1 + substrate/frame/support/test/tests/runtime_ui/pass/basic.rs | 2 +- templates/minimal/runtime/src/lib.rs | 3 ++- templates/solochain/runtime/src/lib.rs | 3 ++- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index 9985ded06514..63b6fc75f8d6 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -1209,6 +1209,7 @@ pub fn import_section(attr: TokenStream, tokens: TokenStream) -> TokenStream { /// RuntimeSlashReason, /// RuntimeLockId, /// RuntimeTask, +/// RuntimeQuery, /// )] /// pub struct Runtime; /// diff --git a/substrate/frame/support/test/tests/runtime_ui/pass/basic.rs b/substrate/frame/support/test/tests/runtime_ui/pass/basic.rs index 514f15018015..110799b584c6 100644 --- a/substrate/frame/support/test/tests/runtime_ui/pass/basic.rs +++ b/substrate/frame/support/test/tests/runtime_ui/pass/basic.rs @@ -27,7 +27,7 @@ impl frame_system::Config for Runtime { #[frame_support::runtime] mod runtime { #[runtime::runtime] - #[runtime::derive(RuntimeCall, RuntimeEvent, RuntimeOrigin, RuntimeError, RuntimeTask)] + #[runtime::derive(RuntimeCall, RuntimeEvent, RuntimeOrigin, RuntimeError, RuntimeTask, RuntimeQuery)] pub struct Runtime; #[runtime::pallet_index(0)] diff --git a/templates/minimal/runtime/src/lib.rs b/templates/minimal/runtime/src/lib.rs index d2debbf5689f..f6eb014219ff 100644 --- a/templates/minimal/runtime/src/lib.rs +++ b/templates/minimal/runtime/src/lib.rs @@ -93,7 +93,8 @@ mod runtime { RuntimeHoldReason, RuntimeSlashReason, RuntimeLockId, - RuntimeTask + RuntimeTask, + RuntimeQuery, )] pub struct Runtime; diff --git a/templates/solochain/runtime/src/lib.rs b/templates/solochain/runtime/src/lib.rs index 93a56fb0ad78..7a589bb24fec 100644 --- a/templates/solochain/runtime/src/lib.rs +++ b/templates/solochain/runtime/src/lib.rs @@ -262,7 +262,8 @@ mod runtime { RuntimeHoldReason, RuntimeSlashReason, RuntimeLockId, - RuntimeTask + RuntimeTask, + RuntimeQuery, )] pub struct Runtime; From c6dd8a5d4c31cfd416fc3502c2e3e91c2d47cb57 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 7 Jun 2024 14:57:02 +0100 Subject: [PATCH 40/45] Wire up runtime API query methods --- substrate/bin/node/runtime/src/lib.rs | 2 +- .../src/construct_runtime/expand/query.rs | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 978e30f8ece7..bac9eb5cf6b2 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -2686,7 +2686,7 @@ impl_runtime_apis! { impl sp_api::RuntimeQuery for Runtime { fn execute_query(query_id: QueryId, query: Vec) -> Result, QueryDispatchError> { - todo!() + Runtime::execute_query(query_id, query) } } diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs index 4de6adfd0fa7..d3384879cf2e 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/query.rs @@ -20,7 +20,7 @@ use proc_macro2::{Ident, Span, TokenStream as TokenStream2}; /// Expands implementation of runtime level `DispatchQuery`. pub fn expand_outer_query( - _runtime_name: &Ident, + runtime_name: &Ident, pallet_decls: &[Pallet], scrate: &TokenStream2, ) -> TokenStream2 { @@ -58,6 +58,19 @@ pub fn expand_outer_query( Err(#scrate::__private::QueryDispatchError::NotFound(id.clone())) } } + + impl #runtime_name { + /// Convenience function for query execution from the runtime API. + pub fn execute_query( + id: #scrate::__private::QueryId, + input: #scrate::__private::sp_std::vec::Vec<::core::primitive::u8>, + ) -> Result<#scrate::__private::sp_std::vec::Vec<::core::primitive::u8>, #scrate::__private::QueryDispatchError> + { + let mut output = #scrate::__private::sp_std::vec![]; + <#runtime_query as #scrate::traits::DispatchQuery>::dispatch_query(&id, &mut &input[..], &mut output)?; + Ok(output) + } + } }; } } From 81150baf83f8b093c0281396ce4088eea4b3957f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 7 Jun 2024 15:08:08 +0100 Subject: [PATCH 41/45] Use Runtime::execute_query generated method --- substrate/frame/examples/view-functions/src/tests.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/substrate/frame/examples/view-functions/src/tests.rs b/substrate/frame/examples/view-functions/src/tests.rs index f7a61c767ffe..0e7a146ac82e 100644 --- a/substrate/frame/examples/view-functions/src/tests.rs +++ b/substrate/frame/examples/view-functions/src/tests.rs @@ -76,15 +76,7 @@ where V: Decode + Eq + PartialEq + std::fmt::Debug, { let input = query.encode(); - let mut output = Vec::new(); - - ::RuntimeQuery::dispatch_query::>( - &Q::id(), - &mut &input[..], - &mut output, - ) - .unwrap(); - + let output = Runtime::execute_query(Q::id(), input).unwrap(); let query_result = V::decode(&mut &output[..]).unwrap(); assert_eq!(expected, query_result,); From 11cb3dbabe291067d3f74c232879ba573cb67efc Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 7 Jun 2024 15:08:38 +0100 Subject: [PATCH 42/45] Fmt --- polkadot/runtime/westend/src/lib.rs | 2 +- substrate/bin/node/runtime/src/lib.rs | 2 +- templates/minimal/runtime/src/lib.rs | 2 +- templates/solochain/runtime/src/lib.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index dee5107333e4..e57b7dad9214 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1430,7 +1430,7 @@ mod runtime { RuntimeSlashReason, RuntimeLockId, RuntimeTask, - RuntimeQuery, + RuntimeQuery )] pub struct Runtime; diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index bac9eb5cf6b2..e62c287b47ac 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -2244,7 +2244,7 @@ mod runtime { RuntimeSlashReason, RuntimeLockId, RuntimeTask, - RuntimeQuery, + RuntimeQuery )] pub struct Runtime; diff --git a/templates/minimal/runtime/src/lib.rs b/templates/minimal/runtime/src/lib.rs index f6eb014219ff..55f44c44e542 100644 --- a/templates/minimal/runtime/src/lib.rs +++ b/templates/minimal/runtime/src/lib.rs @@ -94,7 +94,7 @@ mod runtime { RuntimeSlashReason, RuntimeLockId, RuntimeTask, - RuntimeQuery, + RuntimeQuery )] pub struct Runtime; diff --git a/templates/solochain/runtime/src/lib.rs b/templates/solochain/runtime/src/lib.rs index 7a589bb24fec..830adcdeb68f 100644 --- a/templates/solochain/runtime/src/lib.rs +++ b/templates/solochain/runtime/src/lib.rs @@ -263,7 +263,7 @@ mod runtime { RuntimeSlashReason, RuntimeLockId, RuntimeTask, - RuntimeQuery, + RuntimeQuery )] pub struct Runtime; From 7c71b8a2942dd7a38e712eec9ab97cb9b2fb1e06 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 8 Nov 2024 12:16:36 +0000 Subject: [PATCH 43/45] Rename `view_functions` to `view_functions_experimental` --- substrate/frame/examples/view-functions/src/lib.rs | 6 +++--- substrate/frame/support/procedural/src/pallet/parse/mod.rs | 6 +++--- .../support/procedural/src/pallet/parse/view_functions.rs | 6 +++--- substrate/frame/support/test/tests/pallet.rs | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/substrate/frame/examples/view-functions/src/lib.rs b/substrate/frame/examples/view-functions/src/lib.rs index 0dffcf73f9c7..089d618dd73b 100644 --- a/substrate/frame/examples/view-functions/src/lib.rs +++ b/substrate/frame/examples/view-functions/src/lib.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! This pallet demonstrates the use of the `pallet::view_functions` api for service work. +//! This pallet demonstrates the use of the `pallet::view_functions_experimental` api for service work. #![cfg_attr(not(feature = "std"), no_std)] pub mod mock; @@ -58,7 +58,7 @@ pub mod pallet { #[pallet::storage] pub type SomeMap = StorageMap<_, Twox64Concat, u32, u32, OptionQuery>; - #[pallet::view_functions] + #[pallet::view_functions_experimental] impl Pallet where T::AccountId: From + SomeAssociation1, @@ -96,7 +96,7 @@ pub mod pallet2 { pub type SomeMap, I: 'static = ()> = StorageMap<_, Twox64Concat, u32, u32, OptionQuery>; - #[pallet::view_functions] + #[pallet::view_functions_experimental] impl, I: 'static> Pallet where T::AccountId: From + SomeAssociation1, diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index 1eaeb92ff526..ef8057770fc8 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -570,7 +570,7 @@ mod keyword { syn::custom_keyword!(pallet); syn::custom_keyword!(extra_constants); syn::custom_keyword!(composite_enum); - syn::custom_keyword!(view_functions); + syn::custom_keyword!(view_functions_experimental); } /// The possible values for the `#[pallet::config]` attribute. @@ -788,8 +788,8 @@ impl syn::parse::Parse for PalletAttr { Ok(PalletAttr::ExtraConstants(content.parse::()?.span())) } else if lookahead.peek(keyword::composite_enum) { Ok(PalletAttr::Composite(content.parse::()?.span())) - } else if lookahead.peek(keyword::view_functions) { - Ok(PalletAttr::ViewFunctions(content.parse::()?.span())) + } else if lookahead.peek(keyword::view_functions_experimental) { + Ok(PalletAttr::ViewFunctions(content.parse::()?.span())) } else { Err(lookahead.error()) } 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 b21f05ea9f54..2c24c875569b 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/view_functions.rs @@ -23,7 +23,7 @@ use syn::spanned::Spanned; pub struct ViewFunctionsImplDef { /// The where_clause used. pub where_clause: Option, - /// The span of the pallet::view_functions attribute. + /// The span of the pallet::view_functions_experimental attribute. pub attr_span: proc_macro2::Span, /// Docs, specified on the impl Block. pub docs: Vec, @@ -38,14 +38,14 @@ impl ViewFunctionsImplDef { } else { return Err(syn::Error::new( item.span(), - "Invalid pallet::view_functions, expected item impl", + "Invalid pallet::view_functions_experimental, expected item impl", )) }; let mut view_functions = Vec::new(); for item in &mut item_impl.items { if let syn::ImplItem::Fn(method) = item { if !matches!(method.vis, syn::Visibility::Public(_)) { - let msg = "Invalid pallet::view_functions, view function must be public: \ + let msg = "Invalid pallet::view_functions_experimental, view function must be public: \ `pub fn`"; let span = match method.vis { diff --git a/substrate/frame/support/test/tests/pallet.rs b/substrate/frame/support/test/tests/pallet.rs index 88ed5ad433b2..58d2e1d57b17 100644 --- a/substrate/frame/support/test/tests/pallet.rs +++ b/substrate/frame/support/test/tests/pallet.rs @@ -458,7 +458,7 @@ pub mod pallet { _myfield: u32, } - #[pallet::view_functions] + #[pallet::view_functions_experimental] impl Pallet where T::AccountId: From + SomeAssociation1, From 60d78fc933b5bc35eda7ee59ffaec8379468ad25 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 8 Nov 2024 12:22:14 +0000 Subject: [PATCH 44/45] Remove Vec import --- substrate/primitives/api/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/substrate/primitives/api/src/lib.rs b/substrate/primitives/api/src/lib.rs index 19d88c278543..d08eda1b5579 100644 --- a/substrate/primitives/api/src/lib.rs +++ b/substrate/primitives/api/src/lib.rs @@ -127,7 +127,6 @@ use sp_runtime::{traits::Block as BlockT, ExtrinsicInclusionMode}; pub use sp_state_machine::StorageProof; #[cfg(feature = "std")] use sp_state_machine::{backend::AsTrieBackend, Backend as StateBackend, OverlayedChanges}; -use sp_std::vec::Vec; use sp_version::RuntimeVersion; #[cfg(feature = "std")] use std::cell::RefCell; From 19d6f655f8155b6e2121ef0350abf76e66dd0a81 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 8 Nov 2024 12:42:26 +0000 Subject: [PATCH 45/45] Resore Vec import --- Cargo.lock | 1 + substrate/primitives/api/Cargo.toml | 2 ++ substrate/primitives/api/src/lib.rs | 1 + 3 files changed, 4 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index e298eb0ee4f2..d2a1a5b2b0ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21589,6 +21589,7 @@ dependencies = [ "sp-runtime 31.0.1", "sp-runtime-interface 24.0.0", "sp-state-machine 0.35.0", + "sp-std 14.0.0", "sp-test-primitives", "sp-trie 29.0.0", "sp-version 29.0.0", diff --git a/substrate/primitives/api/Cargo.toml b/substrate/primitives/api/Cargo.toml index e0a4d06b2d81..3e6e10e63bec 100644 --- a/substrate/primitives/api/Cargo.toml +++ b/substrate/primitives/api/Cargo.toml @@ -24,6 +24,7 @@ sp-runtime-interface = { workspace = true } sp-externalities = { optional = true, workspace = true } sp-version = { workspace = true } sp-state-machine = { optional = true, workspace = true } +sp-std = { workspace = true } sp-trie = { optional = true, workspace = true } hash-db = { optional = true, workspace = true, default-features = true } thiserror = { optional = true, workspace = true } @@ -52,6 +53,7 @@ std = [ "sp-runtime-interface/std", "sp-runtime/std", "sp-state-machine/std", + "sp-std/std", "sp-test-primitives/std", "sp-trie/std", "sp-version/std", diff --git a/substrate/primitives/api/src/lib.rs b/substrate/primitives/api/src/lib.rs index d08eda1b5579..19d88c278543 100644 --- a/substrate/primitives/api/src/lib.rs +++ b/substrate/primitives/api/src/lib.rs @@ -127,6 +127,7 @@ use sp_runtime::{traits::Block as BlockT, ExtrinsicInclusionMode}; pub use sp_state_machine::StorageProof; #[cfg(feature = "std")] use sp_state_machine::{backend::AsTrieBackend, Backend as StateBackend, OverlayedChanges}; +use sp_std::vec::Vec; use sp_version::RuntimeVersion; #[cfg(feature = "std")] use std::cell::RefCell;