Skip to main content

topsoil_core/
view_functions.rs

1// This file is part of Soil.
2
3// Copyright (C) Soil contributors.
4// Copyright (C) Parity Technologies (UK) Ltd.
5// SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later WITH Classpath-exception-2.0
6
7//! Traits for querying pallet view functions.
8
9use alloc::vec::Vec;
10use codec::{Decode, DecodeAll, Encode, Output};
11use scale_info::TypeInfo;
12use Debug;
13
14/// The unique identifier for a view function.
15#[derive(Clone, Encode, Decode, Debug, TypeInfo)]
16pub struct ViewFunctionId {
17	/// The part of the id for dispatching view functions from the top level of the runtime.
18	///
19	/// Specifies which view function grouping this view function belongs to. This could be a group
20	/// of view functions associated with a pallet, or a pallet agnostic group of view functions.
21	pub prefix: [u8; 16],
22	/// The part of the id for dispatching to a view function within a group.
23	pub suffix: [u8; 16],
24}
25
26impl From<ViewFunctionId> for [u8; 32] {
27	fn from(value: ViewFunctionId) -> Self {
28		let mut output = [0u8; 32];
29		output[..16].copy_from_slice(&value.prefix);
30		output[16..].copy_from_slice(&value.suffix);
31		output
32	}
33}
34
35/// Error type for view function dispatching.
36#[derive(Encode, Decode, Debug, TypeInfo)]
37pub enum ViewFunctionDispatchError {
38	/// View functions are not implemented for this runtime.
39	NotImplemented,
40	/// A view function with the given `ViewFunctionId` was not found
41	NotFound(ViewFunctionId),
42	/// Failed to decode the view function input.
43	Codec,
44}
45
46impl From<codec::Error> for ViewFunctionDispatchError {
47	fn from(_: codec::Error) -> Self {
48		ViewFunctionDispatchError::Codec
49	}
50}
51
52/// Implemented by both pallets and the runtime. The runtime is dispatching by prefix using the
53/// pallet implementation of `ViewFunctionIdPrefix` then the pallet is dispatching by suffix using
54/// the methods implementation of `ViewFunctionIdSuffix`.
55///
56/// In more details, `ViewFunctionId` = `ViewFunctionIdPrefix` ++ `ViewFunctionIdSuffix`, where
57/// `ViewFunctionIdPrefix=twox_128(pallet_name)` and
58/// `ViewFunctionIdSuffix=twox_128("fn_name(fnarg_types) -> return_ty")`. The prefix is the same as
59/// the storage prefix for pallets. The suffix is generated from the view function method type
60/// signature, so is guaranteed to be unique for that pallet implementation.
61pub trait DispatchViewFunction {
62	fn dispatch_view_function<O: Output>(
63		id: &ViewFunctionId,
64		input: &mut &[u8],
65		output: &mut O,
66	) -> Result<(), ViewFunctionDispatchError>;
67}
68
69impl DispatchViewFunction for () {
70	fn dispatch_view_function<O: Output>(
71		_id: &ViewFunctionId,
72		_input: &mut &[u8],
73		_output: &mut O,
74	) -> Result<(), ViewFunctionDispatchError> {
75		Err(ViewFunctionDispatchError::NotImplemented)
76	}
77}
78
79/// Automatically implemented for each pallet by the macro [`pallet`](crate::pallet).
80pub trait ViewFunctionIdPrefix {
81	fn prefix() -> [u8; 16];
82}
83
84/// Automatically implemented for each pallet view function method by the macro
85/// [`pallet`](crate::pallet).
86pub trait ViewFunctionIdSuffix {
87	const SUFFIX: [u8; 16];
88}
89
90/// Automatically implemented for each pallet view function method by the macro
91/// [`pallet`](crate::pallet).
92pub trait ViewFunction: DecodeAll {
93	fn id() -> ViewFunctionId;
94	type ReturnType: Encode;
95
96	fn invoke(self) -> Self::ReturnType;
97
98	fn execute<O: Output>(
99		input: &mut &[u8],
100		output: &mut O,
101	) -> Result<(), ViewFunctionDispatchError> {
102		let view_function = Self::decode_all(input)?;
103		let result = view_function.invoke();
104		Encode::encode_to(&result, output);
105		Ok(())
106	}
107}
108
109pub mod runtime_api {
110	use super::*;
111
112	subsoil::api::decl_runtime_apis! {
113		#[api_version(1)]
114		/// Runtime API for executing view functions
115		pub trait RuntimeViewFunction {
116			/// Execute a view function query.
117			fn execute_view_function(
118				query_id: ViewFunctionId,
119				input: Vec<u8>,
120			) -> Result<Vec<u8>, ViewFunctionDispatchError>;
121		}
122	}
123}