gear_core/
rpc.rs

1// This file is part of Gear.
2
3// Copyright (C) 2021-2025 Gear Technologies Inc.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! This module contains types commonly used as output in RPC calls.
20
21use alloc::vec::Vec;
22use gear_core_errors::ReplyCode;
23use parity_scale_codec::{Decode, Encode};
24use scale_decode::DecodeAsType;
25use scale_encode::EncodeAsType;
26use scale_info::TypeInfo;
27
28/// Pre-calculated gas consumption estimate for a message.
29///
30/// Intended to be used as a result in `calculateGasFor*` RPC calls.
31#[derive(
32    Clone, Debug, Default, PartialEq, Eq, Encode, EncodeAsType, Decode, DecodeAsType, TypeInfo,
33)]
34#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
35pub struct GasInfo {
36    /// The minimum amount of gas required for successful execution.
37    pub min_limit: u64,
38    /// The amount of gas that would be reserved.
39    pub reserved: u64,
40    /// The amount of gas that would be burned.
41    pub burned: u64,
42    /// The amount of gas that may be returned.
43    pub may_be_returned: u64,
44    /// Indicates whether the message was placed into the waitlist.
45    ///
46    /// This flag signifies that `min_limit` guarantees apply only to the first execution attempt.
47    pub waited: bool,
48}
49
50/// Pre-calculated reply information.
51///
52/// Intended to be used as a result in `calculateReplyFor*` RPC calls.
53#[derive(
54    Clone, Debug, PartialEq, Eq, Encode, EncodeAsType, Decode, DecodeAsType, TypeInfo, Hash,
55)]
56#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
57pub struct ReplyInfo {
58    /// Payload of the reply.
59    #[cfg_attr(feature = "std", serde(with = "impl_serde::serialize"))]
60    pub payload: Vec<u8>,
61    /// Value attached to the reply.
62    pub value: u128,
63    /// Reply code of the reply.
64    pub code: ReplyCode,
65}
66
67/// `u128` value wrapper intended for usage in RPC calls due to serialization specifications.
68#[derive(
69    Clone,
70    Copy,
71    Debug,
72    Default,
73    PartialEq,
74    Eq,
75    Encode,
76    EncodeAsType,
77    Decode,
78    DecodeAsType,
79    TypeInfo,
80    derive_more::From,
81    derive_more::Into,
82)]
83pub struct RpcValue(pub u128);
84
85#[cfg(feature = "std")]
86impl<'de> serde::Deserialize<'de> for RpcValue {
87    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
88    where
89        D: serde::Deserializer<'de>,
90    {
91        use alloc::format;
92        use core::fmt;
93        use serde::de::{self, Visitor};
94
95        struct RpcValueVisitor;
96
97        impl<'de> Visitor<'de> for RpcValueVisitor {
98            type Value = RpcValue;
99
100            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
101                f.write_str("a numeric literal, a 0x-prefixed string with big-endian bytes, or a numeric string representing a u128; for large integer literals, consider using string options for clarity and to avoid potential parsing issues")
102            }
103
104            fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E> {
105                Ok(RpcValue(v))
106            }
107
108            fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> {
109                Ok(RpcValue(v as u128))
110            }
111
112            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
113            where
114                E: de::Error,
115            {
116                if let Some(hex) = v.strip_prefix("0x") {
117                    let bytes = hex::decode(hex)
118                        .map_err(|e| E::custom(format!("invalid hex string: {e}")))?;
119
120                    if bytes.len() > 16 {
121                        return Err(E::custom("invalid hex string: too long for u128"));
122                    }
123
124                    // left pad to 16 bytes (big-endian)
125                    let mut padded = [0u8; 16];
126                    padded[16 - bytes.len()..].copy_from_slice(&bytes);
127
128                    Ok(RpcValue(u128::from_be_bytes(padded)))
129                } else {
130                    v.parse::<u128>()
131                        .map(RpcValue)
132                        .map_err(|e| E::custom(format!("invalid numeric string: {e}")))
133                }
134            }
135        }
136
137        deserializer.deserialize_any(RpcValueVisitor)
138    }
139}