gear_core/message/
mod.rs

1// This file is part of Gear.
2
3// Copyright (C) 2022-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//! Message processing module.
20
21mod common;
22mod context;
23mod handle;
24mod incoming;
25mod init;
26mod reply;
27mod signal;
28mod stored;
29mod user;
30
31pub use common::{Dispatch, Message, MessageDetails, ReplyDetails, SignalDetails};
32pub use context::{
33    ContextOutcome, ContextOutcomeDrain, ContextSettings, ContextStore, MessageContext,
34};
35pub use gear_core_errors::{ErrorReplyReason, ReplyCode, SuccessReplyReason};
36pub use handle::{HandleMessage, HandlePacket};
37pub use incoming::{IncomingDispatch, IncomingMessage};
38pub use init::{InitMessage, InitPacket};
39pub use reply::{ReplyMessage, ReplyPacket};
40pub use signal::SignalMessage;
41pub use stored::{StoredDelayedDispatch, StoredDispatch, StoredMessage};
42pub use user::{UserMessage, UserStoredMessage};
43
44use super::buffer::LimitedVec;
45use alloc::{collections::BTreeSet, string::String, vec::Vec};
46use core::fmt::Display;
47use gear_wasm_instrument::syscalls::SyscallName;
48use scale_info::{
49    scale::{Decode, Encode},
50    TypeInfo,
51};
52
53/// Max payload size which one message can have (8 MiB).
54pub const MAX_PAYLOAD_SIZE: usize = 8 * 1024 * 1024;
55
56// **WARNING**: do not remove this check
57const _: () = assert!(MAX_PAYLOAD_SIZE <= u32::MAX as usize);
58
59/// Payload size exceed error
60#[derive(
61    Clone, Copy, Default, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Decode, Encode, TypeInfo,
62)]
63#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
64pub struct PayloadSizeError;
65
66impl From<PayloadSizeError> for &str {
67    fn from(_: PayloadSizeError) -> Self {
68        "Payload size limit exceeded"
69    }
70}
71
72impl Display for PayloadSizeError {
73    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
74        f.write_str((*self).into())
75    }
76}
77
78/// Payload type for message.
79pub type Payload = LimitedVec<u8, PayloadSizeError, MAX_PAYLOAD_SIZE>;
80
81impl Payload {
82    /// Get payload length as u32.
83    pub fn len_u32(&self) -> u32 {
84        // Safe, cause it's guarantied: `MAX_PAYLOAD_SIZE` <= u32::MAX
85        self.inner().len() as u32
86    }
87}
88
89/// Gas limit type for message.
90pub type GasLimit = u64;
91
92/// Value type for message.
93pub type Value = u128;
94
95/// Salt type for init message.
96pub type Salt = LimitedVec<u8, PayloadSizeError, MAX_PAYLOAD_SIZE>;
97
98/// Composite wait type for messages waiting.
99#[derive(Debug, Encode, Decode, Clone, PartialEq, Eq, PartialOrd, Ord, TypeInfo)]
100pub enum MessageWaitedType {
101    /// Program called `gr_wait` while executing message.
102    Wait,
103    /// Program called `gr_wait_for` while executing message.
104    WaitFor,
105    /// Program called `gr_wait_up_to` with insufficient gas for full
106    /// duration while executing message.
107    WaitUpTo,
108    /// Program called `gr_wait_up_to` with enough gas for full duration
109    /// storing while executing message.
110    WaitUpToFull,
111}
112
113/// Entry point for dispatch processing.
114#[derive(
115    Copy, Clone, Default, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Decode, Encode, TypeInfo,
116)]
117#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
118pub enum DispatchKind {
119    /// Initialization.
120    Init,
121    /// Common handle.
122    #[default]
123    Handle,
124    /// Handle reply.
125    Reply,
126    /// System signal.
127    Signal,
128}
129
130/// Trait defining type could be used as entry point for a wasm module.
131pub trait WasmEntryPoint: Sized {
132    /// Converting self into entry point name.
133    fn as_entry(&self) -> &str;
134
135    /// Converting entry point name into self object, if possible.
136    fn try_from_entry(entry: &str) -> Option<Self>;
137
138    /// Tries to convert self into `DispatchKind`.
139    fn try_into_kind(&self) -> Option<DispatchKind> {
140        <DispatchKind as WasmEntryPoint>::try_from_entry(self.as_entry())
141    }
142}
143
144impl WasmEntryPoint for String {
145    fn as_entry(&self) -> &str {
146        self
147    }
148
149    fn try_from_entry(entry: &str) -> Option<Self> {
150        Some(entry.into())
151    }
152}
153
154impl WasmEntryPoint for DispatchKind {
155    fn as_entry(&self) -> &str {
156        match self {
157            Self::Init => "init",
158            Self::Handle => "handle",
159            Self::Reply => "handle_reply",
160            Self::Signal => "handle_signal",
161        }
162    }
163
164    fn try_from_entry(entry: &str) -> Option<Self> {
165        let kind = match entry {
166            "init" => Self::Init,
167            "handle" => Self::Handle,
168            "handle_reply" => Self::Reply,
169            "handle_signal" => Self::Signal,
170            _ => return None,
171        };
172
173        Some(kind)
174    }
175}
176
177impl DispatchKind {
178    /// Check if kind is init.
179    pub fn is_init(&self) -> bool {
180        matches!(self, Self::Init)
181    }
182
183    /// Check if kind is handle.
184    pub fn is_handle(&self) -> bool {
185        matches!(self, Self::Handle)
186    }
187
188    /// Check if kind is reply.
189    pub fn is_reply(&self) -> bool {
190        matches!(self, Self::Reply)
191    }
192
193    /// Check if kind is signal.
194    pub fn is_signal(&self) -> bool {
195        matches!(self, Self::Signal)
196    }
197
198    /// Syscalls that are not allowed to be called for the dispatch kind.
199    pub fn forbidden_funcs(&self) -> BTreeSet<SyscallName> {
200        match self {
201            DispatchKind::Signal => [
202                SyscallName::Source,
203                SyscallName::Reply,
204                SyscallName::ReplyPush,
205                SyscallName::ReplyCommit,
206                SyscallName::ReplyCommitWGas,
207                SyscallName::ReplyInput,
208                SyscallName::ReplyInputWGas,
209                SyscallName::ReservationReply,
210                SyscallName::ReservationReplyCommit,
211                SyscallName::SystemReserveGas,
212            ]
213            .into(),
214            _ => Default::default(),
215        }
216    }
217}
218
219/// Message packet.
220///
221/// Provides common behavior for any message's packet: accessing to payload, gas limit and value.
222pub trait Packet {
223    /// Packet payload bytes.
224    fn payload_bytes(&self) -> &[u8];
225
226    /// Payload len
227    fn payload_len(&self) -> u32;
228
229    /// Packet optional gas limit.
230    fn gas_limit(&self) -> Option<GasLimit>;
231
232    /// Packet value.
233    fn value(&self) -> Value;
234
235    /// A dispatch kind the will be generated from the packet.
236    fn kind() -> DispatchKind;
237}
238
239/// The struct contains results of read only send message RPC call.
240#[derive(Clone, Debug, Decode, Encode, PartialEq, Eq, TypeInfo)]
241#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
242pub struct ReplyInfo {
243    /// Payload of the reply.
244    #[cfg_attr(feature = "std", serde(with = "impl_serde::serialize"))]
245    pub payload: Vec<u8>,
246    /// Value sent with reply.
247    pub value: u128,
248    /// Reply code of the reply.
249    pub code: ReplyCode,
250}