Skip to main content

gear_core/
env.rs

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