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