gear_core/
env.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//! Environment for running a module.
20
21use crate::{
22    buffer::PayloadSlice,
23    env_vars::EnvVars,
24    ids::{ActorId, MessageId, ReservationId},
25    memory::Memory,
26    message::{DispatchKind, HandlePacket, InitPacket, MessageContext, ReplyPacket},
27    pages::WasmPage,
28};
29use alloc::{collections::BTreeSet, string::String};
30use core::fmt::Display;
31use gear_core_errors::{ReplyCode, SignalCode};
32use gear_wasm_instrument::syscalls::SyscallName;
33use parity_scale_codec::{Decode, Encode};
34use scale_info::TypeInfo;
35
36/// External api and data for managing memory and messages,
37/// use by an executing program to trigger state transition
38/// in runtime.
39pub trait Externalities {
40    /// An error issued in infallible syscall.
41    type UnrecoverableError;
42
43    /// An error issued in fallible syscall.
44    type FallibleError;
45
46    /// An error issued during allocation.
47    type AllocError: Display;
48
49    /// Allocate number of pages.
50    ///
51    /// The resulting page number should point to `pages` consecutive memory pages.
52    fn alloc<Context>(
53        &mut self,
54        ctx: &mut Context,
55        mem: &mut impl Memory<Context>,
56        pages_num: u32,
57    ) -> Result<WasmPage, Self::AllocError>;
58
59    /// Free specific page.
60    fn free(&mut self, page: WasmPage) -> Result<(), Self::AllocError>;
61
62    /// Free specific memory range.
63    fn free_range(&mut self, start: WasmPage, end: WasmPage) -> Result<(), Self::AllocError>;
64
65    /// Get environment variables currently set in the system and in the form
66    /// corresponded to the requested version.
67    fn env_vars(&self, version: u32) -> Result<EnvVars, Self::UnrecoverableError>;
68
69    /// Get the current block height.
70    fn block_height(&self) -> Result<u32, Self::UnrecoverableError>;
71
72    /// Get the current block timestamp.
73    fn block_timestamp(&self) -> Result<u64, Self::UnrecoverableError>;
74
75    /// Initialize a new incomplete message for another program and return its handle.
76    fn send_init(&mut self) -> Result<u32, Self::FallibleError>;
77
78    /// Push an extra buffer into message payload by handle.
79    fn send_push(&mut self, handle: u32, buffer: &[u8]) -> Result<(), Self::FallibleError>;
80
81    /// Complete message and send it to another program.
82    fn send_commit(
83        &mut self,
84        handle: u32,
85        msg: HandlePacket,
86        delay: u32,
87    ) -> Result<MessageId, Self::FallibleError>;
88
89    /// Send message to another program.
90    fn send(&mut self, msg: HandlePacket, delay: u32) -> Result<MessageId, Self::FallibleError> {
91        let handle = self.send_init()?;
92        self.send_commit(handle, msg, delay)
93    }
94
95    /// Push the incoming message buffer into message payload by handle.
96    fn send_push_input(
97        &mut self,
98        handle: u32,
99        offset: u32,
100        len: u32,
101    ) -> Result<(), Self::FallibleError>;
102
103    /// Complete message and send it to another program using gas from reservation.
104    fn reservation_send_commit(
105        &mut self,
106        id: ReservationId,
107        handle: u32,
108        msg: HandlePacket,
109        delay: u32,
110    ) -> Result<MessageId, Self::FallibleError>;
111
112    /// Send message to another program using gas from reservation.
113    fn reservation_send(
114        &mut self,
115        id: ReservationId,
116        msg: HandlePacket,
117        delay: u32,
118    ) -> Result<MessageId, Self::FallibleError> {
119        let handle = self.send_init()?;
120        self.reservation_send_commit(id, handle, msg, delay)
121    }
122
123    /// Push an extra buffer into reply message.
124    fn reply_push(&mut self, buffer: &[u8]) -> Result<(), Self::FallibleError>;
125
126    /// Complete reply message and send it to source program.
127    fn reply_commit(&mut self, msg: ReplyPacket) -> Result<MessageId, Self::FallibleError>;
128
129    /// Complete reply message and send it to source program from reservation.
130    fn reservation_reply_commit(
131        &mut self,
132        id: ReservationId,
133        msg: ReplyPacket,
134    ) -> Result<MessageId, Self::FallibleError>;
135
136    /// Produce reply to the current message.
137    fn reply(&mut self, msg: ReplyPacket) -> Result<MessageId, Self::FallibleError> {
138        self.reply_commit(msg)
139    }
140
141    /// Produce reply to the current message from reservation.
142    fn reservation_reply(
143        &mut self,
144        id: ReservationId,
145        msg: ReplyPacket,
146    ) -> Result<MessageId, Self::FallibleError> {
147        self.reservation_reply_commit(id, msg)
148    }
149
150    /// Get the message id of the initial message.
151    fn reply_to(&self) -> Result<MessageId, Self::FallibleError>;
152
153    /// Get the message id which signal issues from.
154    fn signal_from(&self) -> Result<MessageId, Self::FallibleError>;
155
156    /// Push the incoming message buffer into reply message.
157    fn reply_push_input(&mut self, offset: u32, len: u32) -> Result<(), Self::FallibleError>;
158
159    /// Get the source of the message currently being handled.
160    fn source(&self) -> Result<ActorId, Self::UnrecoverableError>;
161
162    /// Get the reply code if the message being processed.
163    fn reply_code(&self) -> Result<ReplyCode, Self::FallibleError>;
164
165    /// Get the signal code if the message being processed.
166    fn signal_code(&self) -> Result<SignalCode, Self::FallibleError>;
167
168    /// Get the id of the message currently being handled.
169    fn message_id(&self) -> Result<MessageId, Self::UnrecoverableError>;
170
171    /// Get the id of program itself
172    fn program_id(&self) -> Result<ActorId, Self::UnrecoverableError>;
173
174    /// Send debug message.
175    ///
176    /// This should be no-op in release builds.
177    fn debug(&self, data: &str) -> Result<(), Self::UnrecoverableError>;
178
179    /// Get the currently handled message payload slice.
180    fn payload_slice(&mut self, at: u32, len: u32) -> Result<PayloadSlice, Self::FallibleError>;
181
182    /// Size of currently handled message payload.
183    fn size(&self) -> Result<usize, Self::UnrecoverableError>;
184
185    /// Returns a random seed for the current block with message id as a subject, along with the time in the past since when it was determinable by chain observers.
186    fn random(&self) -> Result<(&[u8], u32), Self::UnrecoverableError>;
187
188    /// Reserve some gas for a few blocks.
189    fn reserve_gas(
190        &mut self,
191        amount: u64,
192        duration: u32,
193    ) -> Result<ReservationId, Self::FallibleError>;
194
195    /// Unreserve gas using reservation ID.
196    fn unreserve_gas(&mut self, id: ReservationId) -> Result<u64, Self::FallibleError>;
197
198    /// Do system reservation.
199    fn system_reserve_gas(&mut self, amount: u64) -> Result<(), Self::FallibleError>;
200
201    /// Tell how much gas is left in running context.
202    fn gas_available(&self) -> Result<u64, Self::UnrecoverableError>;
203
204    /// Value associated with message.
205    fn value(&self) -> Result<u128, Self::UnrecoverableError>;
206
207    /// Tell how much value is left in running context.
208    fn value_available(&self) -> Result<u128, Self::UnrecoverableError>;
209
210    /// Interrupt the program and reschedule execution for maximum.
211    fn wait(&mut self) -> Result<(), Self::UnrecoverableError>;
212
213    /// Interrupt the program and reschedule execution in duration.
214    fn wait_for(&mut self, duration: u32) -> Result<(), Self::UnrecoverableError>;
215
216    /// Interrupt the program and reschedule execution for maximum,
217    /// but not more than duration.
218    fn wait_up_to(&mut self, duration: u32) -> Result<bool, Self::UnrecoverableError>;
219
220    /// Wake the waiting message and move it to the processing queue.
221    fn wake(&mut self, waker_id: MessageId, delay: u32) -> Result<(), Self::FallibleError>;
222
223    /// Send init message to create a new program.
224    fn create_program(
225        &mut self,
226        packet: InitPacket,
227        delay: u32,
228    ) -> Result<(MessageId, ActorId), Self::FallibleError>;
229
230    /// Create deposit to handle reply on given message.
231    fn reply_deposit(
232        &mut self,
233        message_id: MessageId,
234        amount: u64,
235    ) -> Result<(), Self::FallibleError>;
236
237    /// Return the set of functions that are forbidden to be called.
238    fn forbidden_funcs(&self) -> &BTreeSet<SyscallName>;
239
240    /// Return the current message context.
241    fn msg_ctx(&self) -> &MessageContext;
242}
243
244/// Composite wait type for messages waiting.
245#[derive(Debug, Encode, Decode, Clone, PartialEq, Eq, PartialOrd, Ord, TypeInfo)]
246pub enum MessageWaitedType {
247    /// Program called `gr_wait` while executing message.
248    Wait,
249    /// Program called `gr_wait_for` while executing message.
250    WaitFor,
251    /// Program called `gr_wait_up_to` with insufficient gas for full
252    /// duration while executing message.
253    WaitUpTo,
254    /// Program called `gr_wait_up_to` with enough gas for full duration
255    /// storing while executing message.
256    WaitUpToFull,
257}
258
259/// Trait defining type could be used as entry point for a wasm module.
260pub trait WasmEntryPoint: Sized {
261    /// Converting self into entry point name.
262    fn as_entry(&self) -> &str;
263
264    /// Converting entry point name into self object, if possible.
265    fn try_from_entry(entry: &str) -> Option<Self>;
266
267    /// Tries to convert self into `DispatchKind`.
268    fn try_into_kind(&self) -> Option<DispatchKind> {
269        <DispatchKind as WasmEntryPoint>::try_from_entry(self.as_entry())
270    }
271}
272
273impl WasmEntryPoint for String {
274    fn as_entry(&self) -> &str {
275        self
276    }
277
278    fn try_from_entry(entry: &str) -> Option<Self> {
279        Some(entry.into())
280    }
281}
282
283impl WasmEntryPoint for DispatchKind {
284    fn as_entry(&self) -> &str {
285        match self {
286            Self::Init => "init",
287            Self::Handle => "handle",
288            Self::Reply => "handle_reply",
289            Self::Signal => "handle_signal",
290        }
291    }
292
293    fn try_from_entry(entry: &str) -> Option<Self> {
294        let kind = match entry {
295            "init" => Self::Init,
296            "handle" => Self::Handle,
297            "handle_reply" => Self::Reply,
298            "handle_signal" => Self::Signal,
299            _ => return None,
300        };
301
302        Some(kind)
303    }
304}