-
Notifications
You must be signed in to change notification settings - Fork 808
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement pallet view function queries (#4722)
Closes #216. This PR allows pallets to define a `view_functions` impl like so: ```rust #[pallet::view_functions] impl<T: Config> Pallet<T> where T::AccountId: From<SomeType1> + SomeAssociation1, { /// Query value no args. pub fn get_value() -> Option<u32> { SomeValue::<T>::get() } /// Query value with args. pub fn get_value_with_arg(key: u32) -> Option<u32> { SomeMap::<T>::get(key) } } ``` ### `QueryId` Each view function is uniquely identified by a `QueryId`, which for this implementation is generated by: ```twox_128(pallet_name) ++ twox_128("fn_name(fnarg_types) -> return_ty")``` The prefix `twox_128(pallet_name)` is the same as the storage prefix for pallets and take into account multiple instances of the same pallet. The suffix is generated from the fn type signature so is guaranteed to be unique for that pallet impl. For one of the view fns in the example above it would be `twox_128("get_value_with_arg(u32) -> Option<u32>")`. It is a known limitation that only the type names themselves are taken into account: in the case of type aliases the signature may have the same underlying types but a different id; for generics the concrete types may be different but the signatures will remain the same. The existing Runtime `Call` dispatchables are addressed by their concatenated indices `pallet_index ++ call_index`, and the dispatching is handled by the SCALE decoding of the `RuntimeCallEnum::PalletVariant(PalletCallEnum::dispatchable_variant(payload))`. For `view_functions` the runtime/pallet generated enum structure is replaced by implementing the `DispatchQuery` trait on the outer (runtime) scope, dispatching to a pallet based on the id prefix, and the inner (pallet) scope dispatching to the specific function based on the id suffix. Future implementations could also modify/extend this scheme and routing to pallet agnostic queries. ### Executing externally These view functions can be executed externally via the system runtime api: ```rust pub trait ViewFunctionsApi<QueryId, Query, QueryResult, Error> 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<QueryResult, Error>; } ``` ### `XCQ` Currently there is work going on by @xlc to implement [`XCQ`](https://github.com/open-web3-stack/XCQ/) which may eventually supersede this work. It may be that we still need the fixed function local query dispatching in addition to XCQ, in the same way that we have chain specific runtime dispatchables and XCM. I have kept this in mind and the high level query API is agnostic to the underlying query dispatch and execution. I am just providing the implementation for the `view_function` definition. ### Metadata Currently I am utilizing the `custom` section of the frame metadata, to avoid modifying the official metadata format until this is standardized. ### vs `runtime_api` There are similarities with `runtime_apis`, some differences being: - queries can be defined directly on pallets, so no need for boilerplate declarations and implementations - no versioning, the `QueryId` will change if the signature changes. - possibility for queries to be executed from smart contracts (see below) ### Calling from contracts Future work would be to add `weight` annotations to the view function queries, and a host function to `pallet_contracts` to allow executing these queries from contracts. ### TODO - [x] Consistent naming (view functions pallet impl, queries, high level api?) - [ ] End to end tests via `runtime_api` - [ ] UI tests - [x] Mertadata tests - [ ] Docs --------- Co-authored-by: kianenigma <kian@parity.io> Co-authored-by: James Wilson <james@jsdw.me> Co-authored-by: Giuseppe Re <giuseppe.re@parity.io> Co-authored-by: Guillaume Thiolliere <guillaume.thiolliere@parity.io>
- Loading branch information
1 parent
4302f74
commit 0b8d744
Showing
54 changed files
with
1,349 additions
and
135 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 | ||
# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json | ||
|
||
title: Implement pallet view functions | ||
|
||
doc: | ||
- audience: Runtime Dev | ||
description: | | ||
Read-only view functions can now be defined on pallets. These functions provide an interface for querying state, | ||
from both outside and inside the runtime. Common queries can be defined on pallets, without users having to | ||
access the storage directly. | ||
|
||
- audience: Runtime User | ||
description: | | ||
Querying the runtime state is now easier with the introduction of pallet view functions. Clients can call commonly | ||
defined view functions rather than accessing the storage directly. These are similar to the Runtime APIs, but | ||
are defined within the runtime itself. | ||
|
||
crates: | ||
- name: frame-support | ||
bump: minor | ||
- name: sp-metadata-ir | ||
bump: major | ||
- name: frame-support-procedural | ||
bump: patch | ||
- name: pallet-example-view-functions | ||
bump: patch | ||
- name: cumulus-pov-validator | ||
bump: none | ||
- name: cumulus-pallet-weight-reclaim | ||
bump: patch | ||
- name: westend-runtime | ||
bump: minor |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
[package] | ||
name = "pallet-example-view-functions" | ||
version = "1.0.0" | ||
authors.workspace = true | ||
edition.workspace = true | ||
license.workspace = true | ||
homepage.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, workspace = true } | ||
frame-metadata = { features = ["current"], workspace = true } | ||
log = { workspace = true } | ||
scale-info = { version = "2.11.1", default-features = false, features = ["derive"], workspace = true } | ||
|
||
frame-support = { path = "../../support", default-features = false, workspace = true } | ||
frame-system = { path = "../../system", default-features = false, workspace = true } | ||
|
||
sp-core = { default-features = false, path = "../../../primitives/core", workspace = true } | ||
sp-io = { path = "../../../primitives/io", default-features = false, workspace = true } | ||
sp-metadata-ir = { path = "../../../primitives/metadata-ir", default-features = false, workspace = true } | ||
sp-runtime = { path = "../../../primitives/runtime", default-features = false, workspace = true } | ||
|
||
frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true, workspace = true } | ||
|
||
[dev-dependencies] | ||
pretty_assertions = { version = "1.3.0" } | ||
|
||
[features] | ||
default = ["std"] | ||
std = [ | ||
"codec/std", | ||
"frame-benchmarking?/std", | ||
"frame-metadata/std", | ||
"frame-support/std", | ||
"frame-system/std", | ||
"log/std", | ||
"scale-info/std", | ||
"sp-core/std", | ||
"sp-io/std", | ||
"sp-metadata-ir/std", | ||
"sp-runtime/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", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
// 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::view_functions_experimental` api for service | ||
//! work. | ||
#![cfg_attr(not(feature = "std"), no_std)] | ||
|
||
pub mod tests; | ||
|
||
use frame_support::Parameter; | ||
use scale_info::TypeInfo; | ||
|
||
pub struct SomeType1; | ||
impl From<SomeType1> 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::*; | ||
|
||
#[pallet::error] | ||
pub enum Error<T> {} | ||
|
||
#[pallet::config] | ||
pub trait Config: frame_system::Config {} | ||
|
||
#[pallet::pallet] | ||
pub struct Pallet<T>(_); | ||
|
||
#[pallet::storage] | ||
pub type SomeValue<T: Config> = StorageValue<_, u32>; | ||
|
||
#[pallet::storage] | ||
pub type SomeMap<T: Config> = StorageMap<_, Twox64Concat, u32, u32, OptionQuery>; | ||
|
||
#[pallet::view_functions_experimental] | ||
impl<T: Config> Pallet<T> | ||
where | ||
T::AccountId: From<SomeType1> + SomeAssociation1, | ||
{ | ||
/// Query value no args. | ||
pub fn get_value() -> Option<u32> { | ||
SomeValue::<T>::get() | ||
} | ||
|
||
/// Query value with args. | ||
pub fn get_value_with_arg(key: u32) -> Option<u32> { | ||
SomeMap::<T>::get(key) | ||
} | ||
} | ||
} | ||
|
||
#[frame_support::pallet] | ||
pub mod pallet2 { | ||
use super::*; | ||
use frame_support::pallet_prelude::*; | ||
|
||
#[pallet::error] | ||
pub enum Error<T, I = ()> {} | ||
|
||
#[pallet::config] | ||
pub trait Config<I: 'static = ()>: frame_system::Config {} | ||
|
||
#[pallet::pallet] | ||
pub struct Pallet<T, I = ()>(PhantomData<(T, I)>); | ||
|
||
#[pallet::storage] | ||
pub type SomeValue<T: Config<I>, I: 'static = ()> = StorageValue<_, u32>; | ||
|
||
#[pallet::storage] | ||
pub type SomeMap<T: Config<I>, I: 'static = ()> = | ||
StorageMap<_, Twox64Concat, u32, u32, OptionQuery>; | ||
|
||
#[pallet::view_functions_experimental] | ||
impl<T: Config<I>, I: 'static> Pallet<T, I> | ||
where | ||
T::AccountId: From<SomeType1> + SomeAssociation1, | ||
{ | ||
/// Query value no args. | ||
pub fn get_value() -> Option<u32> { | ||
SomeValue::<T, I>::get() | ||
} | ||
|
||
/// Query value with args. | ||
pub fn get_value_with_arg(key: u32) -> Option<u32> { | ||
SomeMap::<T, I>::get(key) | ||
} | ||
} | ||
} |
Oops, something went wrong.