frame_decode/methods/
runtime_api_decoder.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::runtime_api_type_info::{RuntimeApiInfo, RuntimeApiInfoError, RuntimeApiTypeInfo};
17use crate::utils::{DecodeErrorTrace, decode_with_error_tracing};
18use scale_type_resolver::TypeResolver;
19
20/// An error returned trying to decode a Runtime API responses.
21#[non_exhaustive]
22#[allow(missing_docs)]
23#[derive(Clone, Debug, thiserror::Error)]
24pub enum RuntimeApiDecodeError<TypeId> {
25    #[error("Cannot get Runtime API info: {0}")]
26    CannotGetInfo(RuntimeApiInfoError<'static>),
27    #[error("Cannot decode Runtime API response: {reason}")]
28    CannotDecodeValue {
29        ty: TypeId,
30        reason: DecodeErrorTrace,
31    },
32}
33
34/// Decode a runtime API response.
35pub fn decode_runtime_api_response<'scale, 'resolver, Info, Resolver, V>(
36    trait_name: &str,
37    method_name: &str,
38    cursor: &mut &'scale [u8],
39    info: &Info,
40    type_resolver: &'resolver Resolver,
41    visitor: V,
42) -> Result<V::Value<'scale, 'resolver>, RuntimeApiDecodeError<Info::TypeId>>
43where
44    Info: RuntimeApiTypeInfo,
45    Info::TypeId: Clone + core::fmt::Debug,
46    Resolver: TypeResolver<TypeId = Info::TypeId>,
47    V: scale_decode::Visitor<TypeResolver = Resolver>,
48    V::Error: core::fmt::Debug,
49{
50    let runtime_api_info = info
51        .runtime_api_info(trait_name, method_name)
52        .map_err(|e| RuntimeApiDecodeError::CannotGetInfo(e.into_owned()))?;
53
54    decode_runtime_api_response_with_info(cursor, &runtime_api_info, type_resolver, visitor)
55}
56
57/// Decode a runtime API response.
58///
59/// Unlike [`decode_runtime_api_response`], which obtains the Runtime API information internally given the trait and
60/// method names, this function takes the Runtime API info as an argument. This is useful if you already have the
61/// Runtime API info available, for exampel if you are making multiple calls to the same API and wish to decode each one.
62pub fn decode_runtime_api_response_with_info<'scale, 'resolver, V>(
63    cursor: &mut &'scale [u8],
64    runtime_api_info: &RuntimeApiInfo<<V::TypeResolver as TypeResolver>::TypeId>,
65    type_resolver: &'resolver V::TypeResolver,
66    visitor: V,
67) -> Result<
68    V::Value<'scale, 'resolver>,
69    RuntimeApiDecodeError<<V::TypeResolver as TypeResolver>::TypeId>,
70>
71where
72    V: scale_decode::Visitor,
73    V::Error: core::fmt::Debug,
74{
75    let response_id = runtime_api_info.output_id.clone();
76
77    decode_with_error_tracing(cursor, response_id.clone(), type_resolver, visitor).map_err(|e| {
78        RuntimeApiDecodeError::CannotDecodeValue {
79            ty: response_id,
80            reason: e,
81        }
82    })
83}