frame_decode/methods/
view_function_encoder.rs

1// Copyright (C) 2022-2025 Parity Technologies (UK) Ltd. (admin@parity.io)
2// This file is a part of the frame-decode crate.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//         http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::view_function_type_info::{
17    ViewFunctionInfo, ViewFunctionInfoError, ViewFunctionTypeInfo,
18};
19use crate::utils::{EncodableValues, IntoEncodableValues};
20use alloc::vec::Vec;
21use scale_type_resolver::TypeResolver;
22
23/// An error returned trying to encode View Function inputs.
24#[non_exhaustive]
25#[allow(missing_docs)]
26#[derive(Debug, thiserror::Error)]
27pub enum ViewFunctionInputsEncodeError {
28    #[error("Cannot get View Function info: {0}")]
29    CannotGetInfo(ViewFunctionInfoError<'static>),
30    #[error("Failed to encode View Function info: {0}")]
31    EncodeError(#[from] scale_encode::Error),
32    #[error("Wrong number of inputs provided; expected {num_inputs_expected}")]
33    WrongNumberOfInputsProvided {
34        /// The number of input parameters that were expected.
35        num_inputs_expected: usize,
36    },
37}
38
39/// The default name of the Runtime API that you must call to query a View Function, where
40/// the arguments to this Runtime API can be encoded using [`encode_view_function_inputs`].
41pub const RUNTIME_API_NAME: &str = "RuntimeViewFunction_execute_view_function";
42
43/// Encode the Runtime API input data necessary to call a View Function.
44pub fn encode_view_function_inputs<Info, Resolver, Inputs>(
45    pallet_name: &str,
46    function_name: &str,
47    inputs: Inputs,
48    info: &Info,
49    type_resolver: &Resolver,
50) -> Result<Vec<u8>, ViewFunctionInputsEncodeError>
51where
52    Inputs: IntoEncodableValues,
53    Info: ViewFunctionTypeInfo,
54    Info::TypeId: Clone + core::fmt::Debug,
55    Resolver: TypeResolver<TypeId = Info::TypeId>,
56{
57    // We'll need at least enough space to encode the query ID for the view function
58    let mut out = Vec::with_capacity(32);
59    encode_view_function_inputs_to(
60        pallet_name,
61        function_name,
62        inputs,
63        info,
64        type_resolver,
65        &mut out,
66    )?;
67    Ok(out)
68}
69
70/// Encode to a provided output Vec the Runtime API input data necessary to call a View Function.
71pub fn encode_view_function_inputs_to<Info, Resolver, Inputs>(
72    pallet_name: &str,
73    function_name: &str,
74    inputs: Inputs,
75    info: &Info,
76    type_resolver: &Resolver,
77    out: &mut Vec<u8>,
78) -> Result<(), ViewFunctionInputsEncodeError>
79where
80    Inputs: IntoEncodableValues,
81    Info: ViewFunctionTypeInfo,
82    Info::TypeId: Clone + core::fmt::Debug,
83    Resolver: TypeResolver<TypeId = Info::TypeId>,
84{
85    let view_function_api_info = info
86        .view_function_info(pallet_name, function_name)
87        .map_err(|e| ViewFunctionInputsEncodeError::CannotGetInfo(e.into_owned()))?;
88
89    encode_view_function_inputs_with_info_to(inputs, &view_function_api_info, type_resolver, out)
90}
91
92/// Encode to a provided output Vec the Runtime API input data necessary to call a View Function.
93///
94/// Unlike [`encode_view_function_inputs_to`], which obtains the View Function info internally given trait and method names,
95/// this function takes the View Function info as an argument. This is useful if you already have the info available,
96/// for example if you are encoding multiple inputs for a given View Function.
97pub fn encode_view_function_inputs_with_info_to<Resolver, Inputs>(
98    inputs: Inputs,
99    view_function_api_info: &ViewFunctionInfo<<Resolver as TypeResolver>::TypeId>,
100    type_resolver: &Resolver,
101    out: &mut Vec<u8>,
102) -> Result<(), ViewFunctionInputsEncodeError>
103where
104    Inputs: IntoEncodableValues,
105    Resolver: TypeResolver,
106    <Resolver as TypeResolver>::TypeId: Clone + core::fmt::Debug,
107{
108    // If wrong number of inputs provided, bail early.
109    if view_function_api_info.inputs.len() != inputs.num_encodable_values() {
110        return Err(ViewFunctionInputsEncodeError::WrongNumberOfInputsProvided {
111            num_inputs_expected: view_function_api_info.inputs.len(),
112        });
113    }
114
115    // Encode the query ID first.
116    out.extend_from_slice(&view_function_api_info.query_id);
117
118    // Then encode each input next.
119    let mut inputs = inputs.into_encodable_values();
120    for input in &*view_function_api_info.inputs {
121        inputs
122            .encode_next_value_to(input.id.clone(), type_resolver, out)
123            .map_err(ViewFunctionInputsEncodeError::EncodeError)?;
124    }
125
126    Ok(())
127}