gcore/exec.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//! Utility functions related to the current execution context or program
20//! execution flow.
21//!
22//! This module also provides API for low-level async implementation.
23
24use crate::{
25 ActorId, EnvVars, MessageId,
26 errors::{Result, SyscallError},
27 utils::AsRawPtr,
28};
29use core::mem::MaybeUninit;
30use gsys::BlockNumberWithHash;
31#[cfg(not(feature = "ethexe"))]
32use {
33 crate::ReservationId,
34 gsys::{ErrorWithGas, ErrorWithHash},
35};
36
37/// Get current version of environment variables.
38pub fn env_vars() -> EnvVars {
39 let mut vars = MaybeUninit::<EnvVars>::uninit();
40 unsafe {
41 gsys::gr_env_vars(1, vars.as_mut_ptr() as *mut u8);
42 vars.assume_init()
43 }
44}
45
46/// Get the current block height.
47///
48/// The block height serves to identify a particular block.
49/// This information can be used to enable many scenarios, like restricting or
50/// allowing some functions until a particular block height is reached.
51///
52/// # Examples
53///
54/// Send a reply after the block height reaches the number 1000:
55///
56/// ```
57/// use gcore::{exec, msg};
58///
59/// #[unsafe(no_mangle)]
60/// extern "C" fn handle() {
61/// if exec::block_height() >= 1000 {
62/// msg::reply(b"Block #1000 reached", 0).unwrap();
63/// }
64/// }
65/// ```
66pub fn block_height() -> u32 {
67 let mut bn = 0u32;
68 unsafe { gsys::gr_block_height(&mut bn as *mut u32) };
69 bn
70}
71
72/// Get the current block timestamp.
73///
74/// The timestamp is the number of milliseconds elapsed since the Unix epoch.
75///
76/// # Examples
77///
78/// Send a reply after the block timestamp reaches February 22, 2022:
79///
80/// ```
81/// use gcore::{exec, msg};
82///
83/// #[unsafe(no_mangle)]
84/// extern "C" fn handle() {
85/// if exec::block_timestamp() >= 1645488000000 {
86/// msg::reply(b"The current block is generated after February 22, 2022", 0)
87/// .expect("Unable to reply");
88/// }
89/// }
90/// ```
91pub fn block_timestamp() -> u64 {
92 let mut timestamp = 0u64;
93 unsafe { gsys::gr_block_timestamp(&mut timestamp as *mut u64) };
94 timestamp
95}
96
97/// Provide gas deposit from current message to handle reply message on given
98/// message id.
99///
100/// This message id should be sent within the execution. Once destination actor
101/// or system sends reply on it, the gas limit ignores, if the program gave
102/// deposit - the only it will be used for execution of `handle_reply`.
103///
104/// # Examples
105///
106/// ```
107/// use gcore::{exec, msg};
108///
109/// #[unsafe(no_mangle)]
110/// extern "C" fn handle() {
111/// let message_id =
112/// msg::send(msg::source(), b"Outgoing message", 0).expect("Failed to send message");
113///
114/// exec::reply_deposit(message_id, 100_000).expect("Failed to deposit reply");
115/// }
116///
117/// #[unsafe(no_mangle)]
118/// extern "C" fn handle_reply() {
119/// // I will be executed for pre-defined (deposited) 100_000 of gas!
120/// }
121/// ```
122#[cfg(not(feature = "ethexe"))]
123pub fn reply_deposit(message_id: MessageId, amount: u64) -> Result<()> {
124 let mut error_code = 0u32;
125 unsafe { gsys::gr_reply_deposit(message_id.as_ptr(), amount, &mut error_code) };
126 SyscallError(error_code).into_result()
127}
128
129/// Terminate the execution of a program.
130///
131/// The program and all corresponding data are removed from the storage. It may
132/// be called in the `init` method as well. One can consider this function as
133/// some analog of `std::process::exit`.
134///
135/// `inheritor_id` specifies the address to which all available program value
136/// should be transferred.
137///
138/// Note: All registered global destructors
139/// (via `gcore::dtor!()`/`gcore::ctor::atexit`) are invoked before termination.
140///
141/// # Examples
142///
143/// Terminate the program and transfer the available value to the message
144/// sender:
145///
146/// ```
147/// use gcore::{exec, msg};
148///
149/// #[unsafe(no_mangle)]
150/// extern "C" fn handle() {
151/// // ...
152/// exec::exit(msg::source());
153/// }
154/// ```
155pub fn exit(inheritor_id: ActorId) -> ! {
156 #[cfg(target_arch = "wasm32")]
157 unsafe {
158 crate::ctor::dtors()
159 }
160 unsafe { gsys::gr_exit(inheritor_id.as_ptr()) }
161}
162
163/// Reserve the `amount` of gas for further usage.
164///
165/// `duration` is the block count within which the reserve must be used.
166///
167/// This function returns [`ReservationId`], which one can use for gas
168/// unreserving.
169///
170/// # Examples
171///
172/// Reserve 50 million of gas for seven blocks:
173///
174/// ```
175/// use gcore::{ReservationId, exec};
176///
177/// static mut RESERVED: ReservationId = ReservationId::zero();
178///
179/// #[unsafe(no_mangle)]
180/// extern "C" fn init() {
181/// unsafe { RESERVED = exec::reserve_gas(50_000_000, 7).unwrap() };
182/// }
183///
184/// #[unsafe(no_mangle)]
185/// extern "C" fn handle() {
186/// exec::unreserve_gas(unsafe { RESERVED }).expect("Unable to unreserve");
187/// }
188/// ```
189///
190/// # See also
191///
192/// - [`unreserve_gas`] function unreserves gas identified by [`ReservationId`].
193/// - [`system_reserve_gas`] function reserves gas for system usage.
194#[cfg(not(feature = "ethexe"))]
195pub fn reserve_gas(amount: u64, duration: u32) -> Result<ReservationId> {
196 let mut res: ErrorWithHash = Default::default();
197
198 unsafe { gsys::gr_reserve_gas(amount, duration, res.as_mut_ptr()) };
199 SyscallError(res.error_code).into_result()?;
200
201 Ok(res.hash.into())
202}
203
204/// Reserve the `amount` of gas for system usage.
205///
206/// # Examples
207///
208/// ```
209/// use gcore::exec;
210///
211/// #[unsafe(no_mangle)]
212/// extern "C" fn handle() {
213/// exec::system_reserve_gas(1_000_000).expect("Unable to reserve");
214/// exec::wait();
215/// }
216///
217/// #[unsafe(no_mangle)]
218/// extern "C" fn handle_signal() {
219/// // Message removed from waitlist!
220/// }
221/// ```
222///
223/// # See also
224///
225/// - [`reserve_gas`] function reserves gas for further usage.
226#[cfg(not(feature = "ethexe"))]
227pub fn system_reserve_gas(amount: u64) -> Result<()> {
228 let mut error_code = 0u32;
229 unsafe { gsys::gr_system_reserve_gas(amount, &mut error_code) };
230 SyscallError(error_code).into_result()
231}
232
233/// Unreserve gas identified by [`ReservationId`].
234///
235/// If successful, it returns the reserved amount of gas.
236///
237/// # Examples
238///
239/// See [`reserve_gas`] examples.
240///
241/// # See also
242///
243/// - [`reserve_gas`] function reserves gas for further usage.
244#[cfg(not(feature = "ethexe"))]
245pub fn unreserve_gas(id: ReservationId) -> Result<u64> {
246 let mut res: ErrorWithGas = Default::default();
247
248 unsafe { gsys::gr_unreserve_gas(id.as_ptr(), res.as_mut_ptr()) };
249 SyscallError(res.error_code).into_result()?;
250
251 Ok(res.gas)
252}
253
254/// Get the current amount of gas available for execution.
255///
256/// Each message processing consumes gas on instructions execution and memory
257/// allocations. This function returns a value of the gas available for spending
258/// during the current execution. Its use may help avoid unexpected behaviors
259/// during the program execution in case insufficient gas is available.
260///
261/// # Examples
262///
263/// Do the job while the amount of available gas is more than 1000:
264///
265/// ```
266/// use gcore::exec;
267///
268/// #[unsafe(no_mangle)]
269/// extern "C" fn handle() {
270/// while exec::gas_available() > 1000 {
271/// // ...
272/// }
273/// }
274/// ```
275pub fn gas_available() -> u64 {
276 let mut gas = 0u64;
277 unsafe { gsys::gr_gas_available(&mut gas as *mut u64) };
278 gas
279}
280
281/// Break the current execution.
282///
283/// Use this function to break the current message processing and save the
284/// state.
285///
286/// Note: All registered global destructors
287/// (via `gcore::dtor!()`/`gcore::ctor::atexit`) are invoked before leaving.
288///
289/// # Examples
290///
291/// ```
292/// use gcore::exec;
293///
294/// #[unsafe(no_mangle)]
295/// extern "C" fn handle() {
296/// if exec::gas_available() < 1_000_000 {
297/// exec::leave();
298/// }
299/// }
300/// ```
301pub fn leave() -> ! {
302 #[cfg(target_arch = "wasm32")]
303 unsafe {
304 crate::ctor::dtors()
305 }
306 unsafe { gsys::gr_leave() }
307}
308
309/// Get the total available value amount.
310///
311/// Note that this balance already includes the value received with the current
312/// message.
313///
314/// # Examples
315///
316/// Get self's value balance in the program:
317///
318/// ```
319/// use gcore::exec;
320///
321/// #[unsafe(no_mangle)]
322/// extern "C" fn handle() {
323/// let my_balance = exec::value_available();
324/// }
325/// ```
326pub fn value_available() -> u128 {
327 let mut value = 0u128;
328 unsafe { gsys::gr_value_available(&mut value as *mut u128) }
329 value
330}
331
332/// Pause the current message handling.
333///
334/// If the message handling needs to be paused, e.g., to wait for another
335/// execution to finish, one should use this function. [`wait`] completes the
336/// current message handles execution with a special result and puts this
337/// message into the *waiting queue* to be awakened using the correspondent
338/// [`wake`] function later. All gas that hasn't yet been spent is attributed to
339/// the message in the *waiting queue*.
340///
341/// This call delays message execution for a maximum amount of blocks that could
342/// be paid.
343///
344/// # Examples
345///
346/// ```
347/// use gcore::exec;
348///
349/// #[unsafe(no_mangle)]
350/// extern "C" fn handle() {
351/// // ...
352/// exec::wait();
353/// }
354/// ```
355pub fn wait() -> ! {
356 unsafe { gsys::gr_wait() }
357}
358
359/// Same as [`wait`], but delays handling for a specific number of blocks.
360///
361/// # Panics
362///
363/// Panics if it is impossible to pay the given `duration`.
364pub fn wait_for(duration: u32) -> ! {
365 unsafe { gsys::gr_wait_for(duration) }
366}
367
368/// Same as [`wait`], but delays handling for the maximum number of blocks that
369/// can be paid for and doesn't exceed the given `duration`.
370pub fn wait_up_to(duration: u32) -> ! {
371 unsafe { gsys::gr_wait_up_to(duration) }
372}
373
374/// Resume previously paused message handling.
375///
376/// Suppose a message has been paused using the [`wait`] function. In that case,
377/// it is possible to continue its execution by calling this function.
378///
379/// `message_id` specifies a particular message to be taken out of the *waiting
380/// queue* and put into the *processing queue*.
381///
382/// # Examples
383///
384/// ```
385/// use gcore::{MessageId, exec, msg};
386///
387/// static mut MSG_ID: MessageId = MessageId::zero();
388///
389/// #[unsafe(no_mangle)]
390/// extern "C" fn init() {
391/// unsafe { MSG_ID = msg::id() };
392/// exec::wait();
393/// }
394///
395/// #[unsafe(no_mangle)]
396/// extern "C" fn handle() {
397/// exec::wake(unsafe { MSG_ID }).expect("Unable to wake");
398/// }
399/// ```
400pub fn wake(message_id: MessageId) -> Result<()> {
401 wake_delayed(message_id, 0)
402}
403
404/// Same as [`wake`], but executes after the `delay` expressed in block count.
405pub fn wake_delayed(message_id: MessageId, delay: u32) -> Result<()> {
406 let mut error_code = 0u32;
407 unsafe { gsys::gr_wake(message_id.as_ptr(), delay, &mut error_code) };
408 SyscallError(error_code).into_result()
409}
410
411/// Return the identifier of the current program.
412///
413/// # Examples
414///
415/// ```
416/// use gcore::exec;
417///
418/// #[unsafe(no_mangle)]
419/// extern "C" fn handle() {
420/// let whoami = exec::program_id();
421/// }
422/// ```
423pub fn program_id() -> ActorId {
424 let mut program_id = ActorId::default();
425 unsafe { gsys::gr_program_id(program_id.as_mut_ptr()) }
426 program_id
427}
428
429/// Get the random seed, along with the block number from which it is
430/// determinable by chain observers.
431///
432/// `subject` is a context identifier that allows you to get different results
433/// within the execution.
434///
435/// # Security
436///
437/// This **must NOT** be used for gambling, as it can be influenced by a
438/// malicious validator in the short term. It **MAY** be used in many
439/// cryptographic protocols, however, so long as one remembers that this (like
440/// everything else on-chain) is public. For example, it can be used when a
441/// number is needed that an adversary cannot choose for such purposes as
442/// public-coin zero-knowledge proofs.
443///
444/// # Examples
445///
446/// ```
447/// use core::array;
448/// use gcore::exec;
449///
450/// #[unsafe(no_mangle)]
451/// extern "C" fn handle() {
452/// let subject: [u8; 32] = array::from_fn(|i| i as u8 + 1);
453/// let (seed, block_number) = exec::random(subject).expect("Error in random");
454/// }
455/// ```
456pub fn random(subject: [u8; 32]) -> Result<([u8; 32], u32)> {
457 let mut res: BlockNumberWithHash = Default::default();
458
459 unsafe { gsys::gr_random(&subject, res.as_mut_ptr()) };
460
461 Ok((res.hash, res.bn))
462}