gcore/
msg.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//! Messaging API for Gear programs.
20//!
21//! This module contains an API to process incoming messages and synchronously
22//! send outgoing ones. Messages are the primary communication interface
23//! between actors (users and programs).
24//!
25//! Every Gear program has code that handles messages. During message
26//! processing, a program can send messages to other programs and users,
27//! including a reply to the initial message.
28//!
29//! When some actor (user or program) sends a message to the program, it invokes
30//! this program by executing the `handle` function. The invoked program can
31//! obtain details of incoming messages by using this module's API ([`source`],
32//! [`size`], [`read`], [`id`], [`value`], etc.).
33//!
34//! Optionally the program can send one or more messages to other actors. Also,
35//! it can send a reply that differs from a regular message in two ways:
36//! - There can be no more than one reply;
37//! - It is impossible to choose the reply's destination, as it is always sent
38//!   to the program invoker.
39//!
40//! Note that messages and a reply are not sent immediately but collected during
41//! the program execution and enqueued after the execution successfully ends.
42
43use crate::{
44    ActorId, MessageHandle, MessageId,
45    errors::{Error, Result, SyscallError},
46    stack_buffer,
47    utils::AsRawPtr,
48};
49use gear_core_errors::ReplyCode;
50use gsys::{ErrorWithHandle, ErrorWithHash, ErrorWithReplyCode, HashWithValue};
51#[cfg(not(feature = "ethexe"))]
52use {
53    crate::ReservationId,
54    gear_core_errors::SignalCode,
55    gsys::{ErrorWithSignalCode, TwoHashesWithValue},
56};
57
58const PTR_SPECIAL: *const u128 = u32::MAX as *const u128;
59
60fn value_ptr(value: &u128) -> *const u128 {
61    if *value == 0 {
62        PTR_SPECIAL
63    } else {
64        value as *const u128
65    }
66}
67
68/// Get the reply code of the message being processed.
69///
70/// This function is used in the reply handler to check whether the message was
71/// processed successfully or not.
72///
73/// # Examples
74///
75/// ```
76/// use gcore::msg;
77///
78/// #[unsafe(no_mangle)]
79/// extern "C" fn handle_reply() {
80///     let reply_code = msg::reply_code().expect("Unable to get reply code");
81/// }
82/// ```
83pub fn reply_code() -> Result<ReplyCode> {
84    let mut res: ErrorWithReplyCode = Default::default();
85
86    unsafe { gsys::gr_reply_code(res.as_mut_ptr()) }
87    SyscallError(res.error_code).into_result()?;
88
89    Ok(ReplyCode::from_bytes(res.reply_code))
90}
91
92/// Get the reply code of the message being processed.
93///
94/// This function is used in the reply handler to check whether the message was
95/// processed successfully or not.
96///
97/// # Examples
98///
99/// ```
100/// use gcore::msg;
101///
102/// #[unsafe(no_mangle)]
103/// extern "C" fn handle_signal() {
104///     let signal_code = msg::signal_code().expect("Unable to get signal code");
105/// }
106/// ```
107#[cfg(not(feature = "ethexe"))]
108pub fn signal_code() -> Result<Option<SignalCode>> {
109    let mut res: ErrorWithSignalCode = Default::default();
110
111    unsafe { gsys::gr_signal_code(res.as_mut_ptr()) }
112    SyscallError(res.error_code).into_result()?;
113
114    Ok(SignalCode::from_u32(res.signal_code))
115}
116
117/// Get an identifier of the message that is currently being processed.
118///
119/// One can get an identifier for the currently processing message; each send
120/// and reply function also returns a message identifier.
121///
122/// # Examples
123///
124/// ```
125/// use gcore::{MessageId, msg};
126///
127/// #[unsafe(no_mangle)]
128/// extern "C" fn handle() {
129///     let current_message_id = msg::id();
130///     if current_message_id != MessageId::zero() {
131///         msg::reply(b"Real message", 0).expect("Unable to reply");
132///     }
133/// }
134/// ```
135pub fn id() -> MessageId {
136    let mut message_id = MessageId::default();
137    unsafe { gsys::gr_message_id(message_id.as_mut_ptr()) }
138    message_id
139}
140
141// TODO: issue #1859
142/// Get a payload of the message that is currently being processed.
143///
144/// This function loads the message's payload into buffer with at least
145/// message size (that can be obtained using the [`size`] function). Note
146/// that part of a buffer can be left untouched by this function, if message
147/// payload does not have enough data.
148///
149/// # Examples
150///
151/// ```
152/// use gcore::msg;
153///
154/// #[unsafe(no_mangle)]
155/// extern "C" fn handle() {
156///     let mut payload = vec![0u8; msg::size()];
157///     msg::read(&mut payload).expect("Unable to read");
158/// }
159/// ```
160pub fn read(buffer: &mut [u8]) -> Result<()> {
161    let size = size();
162
163    if size > buffer.len() {
164        return Err(Error::SyscallUsage);
165    }
166
167    if size > 0 {
168        let mut error_code = 0u32;
169        unsafe { gsys::gr_read(0, size as u32, buffer.as_mut_ptr(), &mut error_code) }
170        SyscallError(error_code).into_result()?;
171    }
172
173    Ok(())
174}
175
176/// Executes function `f` with provided message payload allocated on stack.
177/// If payload size is bigger than [stack_buffer::MAX_BUFFER_SIZE], then
178/// allocation will be on heap.
179///
180/// Returns function `f` call result `T`.
181///
182/// # Examples
183///
184/// ```
185/// use gcore::msg;
186///
187/// #[unsafe(no_mangle)]
188/// extern "C" fn handle() {
189///     msg::with_read_on_stack_or_heap(|read_res| {
190///         let payload: &mut [u8] = read_res.expect("Unable to read");
191///         // do something with `payload`
192///     });
193/// }
194/// ```
195pub fn with_read_on_stack_or_heap<T>(f: impl FnOnce(Result<&mut [u8]>) -> T) -> T {
196    let size = size();
197    stack_buffer::with_byte_buffer(size, |buffer| {
198        let mut len = 0u32;
199
200        if size > 0 {
201            unsafe {
202                gsys::gr_read(
203                    0,
204                    size as u32,
205                    buffer.as_mut_ptr() as *mut u8,
206                    &mut len as *mut u32,
207                )
208            }
209        }
210
211        // SAFETY: same as `MaybeUninit::slice_assume_init_mut(&mut buffer[..size])`.
212        // It takes the slice `&mut buffer[..size]` and says that it was
213        // previously initialized with the `gr_read` system call.
214        f(SyscallError(len)
215            .into_result()
216            .map(|_| unsafe { &mut *(&mut buffer[..size] as *mut _ as *mut [u8]) }))
217    })
218}
219
220// TODO: issue #1859
221/// Get a payload of the message that is currently being processed, starting
222/// from some particular offset.
223///
224/// Note that part of a buffer can be left untouched by this function, if
225/// message payload does not have enough data.
226///
227/// # Examples
228///
229/// ```
230/// use gcore::msg;
231///
232/// #[unsafe(no_mangle)]
233/// extern "C" fn handle() {
234///     let mut payload = vec![0u8; msg::size() - 16];
235///     msg::read_at(16, &mut payload).expect("Unable to read");
236/// }
237/// ```
238pub fn read_at(offset: usize, buffer: &mut [u8]) -> Result<()> {
239    if buffer.is_empty() {
240        return SyscallError(0).into_result();
241    }
242
243    let size = size();
244
245    if size > buffer.len() + offset {
246        return Err(Error::SyscallUsage);
247    }
248
249    unsafe {
250        let mut error_code = 0u32;
251        gsys::gr_read(
252            offset as u32,
253            buffer.len() as u32,
254            buffer.as_mut_ptr(),
255            &mut error_code,
256        );
257        SyscallError(error_code).into_result()?;
258    }
259
260    Ok(())
261}
262
263/// Send a new message as a reply to the message that is currently being
264/// processed.
265///
266/// Some programs can reply to other programs, e.g., check another program's
267/// state and use it as a parameter for its business logic.
268///
269/// This function allows sending such replies, which are similar to standard
270/// messages in terms of payload and different only in how the message
271/// processing is handled by a dedicated program function called `handle_reply`.
272///
273/// The first argument is the payload buffer. The second argument is the value
274/// to be transferred from the current program account to the reply message
275/// target account.
276///
277/// Reply message transactions will be posted after processing is finished,
278/// similar to the standard message [`send`].
279///
280/// # Examples
281///
282/// ```
283/// use gcore::{exec, msg};
284///
285/// #[unsafe(no_mangle)]
286/// extern "C" fn handle() {
287///     msg::reply(b"PING", exec::value_available()).expect("Unable to reply");
288/// }
289/// ```
290///
291/// # See also
292///
293/// - [`reply_push`] function allows forming a reply message in parts.
294/// - [`send`] function sends a new message to the program or user.
295pub fn reply(payload: &[u8], value: u128) -> Result<MessageId> {
296    let mut res: ErrorWithHash = Default::default();
297
298    let payload_len = payload.len().try_into().map_err(|_| Error::SyscallUsage)?;
299
300    let value_ptr = value_ptr(&value);
301
302    unsafe { gsys::gr_reply(payload.as_ptr(), payload_len, value_ptr, res.as_mut_ptr()) };
303    SyscallError(res.error_code).into_result()?;
304
305    Ok(res.hash.into())
306}
307
308/// Same as [`reply`], but it spends gas from a reservation instead of borrowing
309/// it from the gas limit provided with the incoming message.
310///
311/// The first argument is the reservation identifier [`ReservationId`] obtained
312/// by calling the corresponding API. The second argument is the payload buffer.
313/// The last argument is the value to be transferred from the current program
314/// account to the reply message target account.
315///
316/// # Examples
317///
318/// ```
319/// use gcore::{exec, msg};
320///
321/// #[unsafe(no_mangle)]
322/// extern "C" fn handle() {
323///     let reservation_id = exec::reserve_gas(5_000_000, 100).expect("Unable to reserve");
324///     msg::reply_from_reservation(reservation_id, b"PING", 0).unwrap();
325/// }
326/// ```
327///
328/// # See also
329///
330/// - [`send_from_reservation`] function sends a new message to the program or
331///   user by using gas from a reservation.
332#[cfg(not(feature = "ethexe"))]
333pub fn reply_from_reservation(id: ReservationId, payload: &[u8], value: u128) -> Result<MessageId> {
334    let rid_value = HashWithValue {
335        hash: id.into(),
336        value,
337    };
338
339    let mut res: ErrorWithHash = Default::default();
340
341    let payload_len = payload.len().try_into().map_err(|_| Error::SyscallUsage)?;
342
343    unsafe {
344        gsys::gr_reservation_reply(
345            rid_value.as_ptr(),
346            payload.as_ptr(),
347            payload_len,
348            res.as_mut_ptr(),
349        )
350    };
351    SyscallError(res.error_code).into_result()?;
352
353    Ok(res.hash.into())
354}
355
356/// Same as [`reply`], but with an explicit gas limit.
357///
358/// # Examples
359///
360/// ```
361/// use gcore::{exec, msg};
362///
363/// #[unsafe(no_mangle)]
364/// extern "C" fn handle() {
365///     msg::reply_with_gas(b"PING", exec::gas_available() / 2, 0).expect("Unable to reply");
366/// }
367/// ```
368///
369/// # See also
370///
371/// - [`reply_push`] function allows forming a reply message in parts.
372#[cfg(not(feature = "ethexe"))]
373pub fn reply_with_gas(payload: &[u8], gas_limit: u64, value: u128) -> Result<MessageId> {
374    let mut res: ErrorWithHash = Default::default();
375
376    let payload_len = payload.len().try_into().map_err(|_| Error::SyscallUsage)?;
377
378    let value_ptr = value_ptr(&value);
379
380    unsafe {
381        gsys::gr_reply_wgas(
382            payload.as_ptr(),
383            payload_len,
384            gas_limit,
385            value_ptr,
386            res.as_mut_ptr(),
387        )
388    };
389    SyscallError(res.error_code).into_result()?;
390
391    Ok(res.hash.into())
392}
393
394/// Finalize and send the current reply message.
395///
396/// Some programs can rely on their messages to other programs, i.e., check
397/// another program's state and use it as a parameter for its own business
398/// logic. The basic implementation is covered in [`reply`]
399/// function.
400///
401/// This function allows sending a reply message filled with payload parts via
402/// [`reply_push`] during the message handling. The [`reply_commit`] function
403/// finalizes the reply message and sends it to the program invoker.
404///
405/// The only argument is the value to be transferred from the current program
406/// account to the reply message target account.
407///
408/// Note that an incomplete reply message will be dropped if the
409/// [`reply_commit`] function has not been called before the current execution
410/// ends.
411///
412/// # Examples
413///
414/// ```
415/// use gcore::msg;
416///
417/// #[unsafe(no_mangle)]
418/// extern "C" fn handle() {
419///     msg::reply_push(b"Hello,").expect("Unable to push");
420///     msg::reply_push(b" world!").expect("Unable to push");
421///     msg::reply_commit(42).expect("Unable to commit");
422/// }
423/// ```
424///
425/// # See also
426///
427/// - [`reply_push`] function allows forming a reply message in parts.
428/// - [`send_commit`] function finalizes and sends a message formed in parts.
429pub fn reply_commit(value: u128) -> Result<MessageId> {
430    let mut res: ErrorWithHash = Default::default();
431
432    let value_ptr = value_ptr(&value);
433
434    unsafe { gsys::gr_reply_commit(value_ptr, res.as_mut_ptr()) }
435    SyscallError(res.error_code).into_result()?;
436
437    Ok(res.hash.into())
438}
439
440/// Same as [`reply_commit`], but with an explicit gas limit.
441///
442/// # Examples
443///
444/// ```
445/// use gcore::{exec, msg};
446///
447/// #[unsafe(no_mangle)]
448/// extern "C" fn handle() {
449///     msg::reply_push(b"Hello, ").expect("Unable to push");
450///     msg::reply_push(b", world!").expect("Unable to push");
451///     msg::reply_commit_with_gas(exec::gas_available() / 2, 0).expect("Unable to commit");
452/// }
453/// ```
454///
455/// # See also
456///
457/// - [`reply_push`] function allows forming a reply message in parts.
458#[cfg(not(feature = "ethexe"))]
459pub fn reply_commit_with_gas(gas_limit: u64, value: u128) -> Result<MessageId> {
460    let mut res: ErrorWithHash = Default::default();
461
462    let value_ptr = value_ptr(&value);
463
464    unsafe { gsys::gr_reply_commit_wgas(gas_limit, value_ptr, res.as_mut_ptr()) }
465    SyscallError(res.error_code).into_result()?;
466
467    Ok(res.hash.into())
468}
469
470/// Same as [`reply_commit`], but it spends gas from a reservation instead of
471/// borrowing it from the gas limit provided with the incoming message.
472///
473/// # Examples
474///
475/// ```
476/// use gcore::{exec, msg};
477///
478/// #[unsafe(no_mangle)]
479/// extern "C" fn handle() {
480///     msg::reply_push(b"Hello,").expect("Unable to push");
481///     msg::reply_push(b" world!").expect("Unable to push");
482///     let reservation_id = exec::reserve_gas(5_000_000, 100).expect("Unable to reserves");
483///     msg::reply_commit_from_reservation(reservation_id, 42).expect("Unable to commit");
484/// }
485/// ```
486///
487/// # See also
488///
489/// - [`reply_push`] function allows forming a reply message in parts.
490#[cfg(not(feature = "ethexe"))]
491pub fn reply_commit_from_reservation(id: ReservationId, value: u128) -> Result<MessageId> {
492    let rid_value = HashWithValue {
493        hash: id.into(),
494        value,
495    };
496
497    let mut res: ErrorWithHash = Default::default();
498
499    unsafe { gsys::gr_reservation_reply_commit(rid_value.as_ptr(), res.as_mut_ptr()) };
500    SyscallError(res.error_code).into_result()?;
501
502    Ok(res.hash.into())
503}
504
505/// Push a payload part to the current reply message.
506///
507/// Some programs can rely on their messages to other programs, i.e., check
508/// another program's state and use it as a parameter for its own business
509/// logic. The basic implementation is covered in the [`reply`] function.
510///
511/// This function allows filling the reply `payload` parts via [`reply_push`]
512/// during the message handling. The payload can consist of several parts.
513///
514/// Note that an incomplete reply message will be dropped if the
515/// [`reply_commit`] function has not been called before the current execution
516/// ends.
517///
518/// # Examples
519///
520/// See the [`reply_commit`] examples.
521///
522/// # See also
523///
524/// - [`reply_commit`] function finalizes and sends the current reply message.
525pub fn reply_push(payload: &[u8]) -> Result<()> {
526    let payload_len = payload.len().try_into().map_err(|_| Error::SyscallUsage)?;
527
528    let mut error_code = 0u32;
529    unsafe { gsys::gr_reply_push(payload.as_ptr(), payload_len, &mut error_code) };
530    SyscallError(error_code).into_result()
531}
532
533/// Get an identifier of the initial message on which the current `handle_reply`
534/// function is called.
535///
536/// The Gear program processes the reply to the message using the `handle_reply`
537/// function. Therefore, a program should call this function to obtain the
538/// original message identifier on which the reply has been posted.
539///
540/// # Examples
541///
542/// ```
543/// use gcore::msg;
544///
545/// #[unsafe(no_mangle)]
546/// extern "C" fn handle_reply() {
547///     let original_message_id = msg::reply_to().unwrap();
548/// }
549/// ```
550pub fn reply_to() -> Result<MessageId> {
551    let mut res: ErrorWithHash = Default::default();
552
553    unsafe { gsys::gr_reply_to(res.as_mut_ptr()) };
554    SyscallError(res.error_code).into_result()?;
555
556    Ok(res.hash.into())
557}
558
559/// Get an identifier of the message which issued a signal.
560///
561/// The Gear program processes the signal using the `handle_signal`
562/// function. Therefore, a program should call this function to obtain the
563/// original message identifier which issued a signal.
564///
565/// # Examples
566///
567/// ```
568/// use gcore::msg;
569///
570/// #[unsafe(no_mangle)]
571/// extern "C" fn handle_signal() {
572///     let erroneous_message = msg::signal_from().unwrap();
573/// }
574/// ```
575#[cfg(not(feature = "ethexe"))]
576pub fn signal_from() -> Result<MessageId> {
577    let mut res: ErrorWithHash = Default::default();
578
579    unsafe { gsys::gr_signal_from(res.as_mut_ptr()) };
580    SyscallError(res.error_code).into_result()?;
581
582    Ok(res.hash.into())
583}
584
585/// Same as [`reply`], but relays the incoming message payload.
586pub fn reply_input(value: u128, offset: u32, len: u32) -> Result<MessageId> {
587    let mut res: ErrorWithHash = Default::default();
588
589    let value_ptr = value_ptr(&value);
590
591    unsafe {
592        gsys::gr_reply_input(offset, len, value_ptr, res.as_mut_ptr());
593    }
594
595    SyscallError(res.error_code).into_result()?;
596
597    Ok(res.hash.into())
598}
599
600/// Same as [`reply_push`] but uses the input buffer as a payload source.
601///
602/// The first and second arguments are the offset and length of the input
603/// buffer's piece that is to be pushed back to the output.
604///
605/// # Examples
606///
607/// Send half of the incoming payload back to the sender as a reply.
608///
609/// ```
610/// use gcore::msg;
611///
612/// #[unsafe(no_mangle)]
613/// extern "C" fn handle() {
614///     msg::reply_push_input(0, msg::size() as u32 / 2).expect("Unable to push");
615///     msg::reply_commit(0).expect("Unable to commit");
616/// }
617/// ```
618///
619/// # See also
620///
621/// - [`send_push_input`] function allows using the input buffer as a payload
622///   source for an outcoming message.
623pub fn reply_push_input(offset: u32, len: u32) -> Result<()> {
624    let mut error_code = 0u32;
625    unsafe { gsys::gr_reply_push_input(offset, len, &mut error_code as _) };
626    SyscallError(error_code).into_result()
627}
628
629/// Same as [`reply_input`], but with explicit gas limit.
630#[cfg(not(feature = "ethexe"))]
631pub fn reply_input_with_gas(
632    gas_limit: u64,
633    value: u128,
634    offset: u32,
635    len: u32,
636) -> Result<MessageId> {
637    let mut res: ErrorWithHash = Default::default();
638
639    let value_ptr = value_ptr(&value);
640
641    unsafe {
642        gsys::gr_reply_input_wgas(offset, len, gas_limit, value_ptr, res.as_mut_ptr());
643    }
644    SyscallError(res.error_code).into_result()?;
645
646    Ok(res.hash.into())
647}
648
649/// Same as [`send`] but uses the input buffer as a payload source.
650///
651/// The first argument is the address of the target account ([`ActorId`]). The
652/// second argument is the value to be transferred from the current program
653/// account to the message target account. The third and last arguments are the
654/// offset and length of the input buffer's piece to be sent back.
655///
656/// # Examples
657///
658/// Send half of the incoming payload back to the sender.
659///
660/// ```
661/// use gcore::msg;
662///
663/// #[unsafe(no_mangle)]
664/// extern "C" fn handle() {
665///     msg::send_input(msg::source(), 0, 0, msg::size() as u32 / 2).expect("Unable to send");
666/// }
667/// ```
668///
669/// # See also
670///
671/// - [`send_push_input`] function allows using the input buffer as a payload
672///   source for an outcoming message.
673pub fn send_input(destination: ActorId, value: u128, offset: u32, len: u32) -> Result<MessageId> {
674    send_input_delayed(destination, value, offset, len, 0)
675}
676
677/// Same as [`send_input`], but sends delayed.
678pub fn send_input_delayed(
679    destination: ActorId,
680    value: u128,
681    offset: u32,
682    len: u32,
683    delay: u32,
684) -> Result<MessageId> {
685    let pid_value = HashWithValue {
686        hash: destination.into(),
687        value,
688    };
689
690    let mut res: ErrorWithHash = Default::default();
691
692    unsafe {
693        gsys::gr_send_input(pid_value.as_ptr(), offset, len, delay, res.as_mut_ptr());
694    }
695    SyscallError(res.error_code).into_result()?;
696
697    Ok(res.hash.into())
698}
699
700/// Send a new message to the program or user.
701///
702/// Gear allows programs to communicate with each other and users via messages.
703/// For example, the [`send`] function allows sending such messages.
704///
705/// The first argument is the address of the target account ([`ActorId`]). The
706/// second argument is the payload buffer. The last argument is the value to be
707/// transferred from the current program account to the message target account.
708///
709/// Send transaction will be posted after processing is finished, similar to the
710/// reply message [`reply`].
711///
712/// # Examples
713///
714/// Send a message with value to the arbitrary address (don't repeat it in your
715/// program!):
716///
717/// ```
718/// use gcore::msg;
719///
720/// #[unsafe(no_mangle)]
721/// extern "C" fn handle() {
722///     // Receiver id is collected from bytes from 0 to 31
723///     let id: [u8; 32] = core::array::from_fn(|i| i as u8);
724///     msg::send(id.into(), b"HELLO", 42).expect("Unable to send");
725/// }
726/// ```
727///
728/// # See also
729///
730/// - [`reply`] function sends a new message as a reply to the message that is
731///   currently being processed.
732/// - [`send_init`], [`send_push`], and [`send_commit`] functions allow forming
733///   a message to send in parts.
734pub fn send(destination: ActorId, payload: &[u8], value: u128) -> Result<MessageId> {
735    send_delayed(destination, payload, value, 0)
736}
737
738/// Same as [`send`], but it spends gas from a reservation instead of borrowing
739/// it from the gas limit provided with the incoming message.
740///
741/// The first argument is the reservation identifier [`ReservationId`] obtained
742/// by calling the corresponding API. The second argument is the address of the
743/// target account ([`ActorId`]). The third argument is the payload buffer.
744/// Finally, the last argument is the value to be transferred from the current
745/// program account to the message target account.
746///
747/// # Examples
748///
749/// Send a message with value to the arbitrary address (don't repeat it in your
750/// program!):
751///
752/// ```
753/// use gcore::{exec, msg};
754///
755/// #[unsafe(no_mangle)]
756/// extern "C" fn handle() {
757///     // Reserve 5 million of gas for 100 blocks
758///     let reservation_id = exec::reserve_gas(5_000_000, 100).expect("Unable to reserve");
759///     // Receiver id is collected from bytes from 0 to 31
760///     let actor_id: [u8; 32] = core::array::from_fn(|i| i as u8);
761///     msg::send_from_reservation(reservation_id, actor_id.into(), b"HELLO", 42)
762///         .expect("Unable to send");
763/// }
764/// ```
765///
766/// # See also
767///
768/// - [`reply_from_reservation`] function sends a reply to the program or user
769///   by using gas from a reservation.
770/// - [`send_init`],[`send_push`], [`send_commit_from_reservation`] functions
771///   allows forming a message to send in parts.
772#[cfg(not(feature = "ethexe"))]
773pub fn send_from_reservation(
774    reservation_id: ReservationId,
775    destination: ActorId,
776    payload: &[u8],
777    value: u128,
778) -> Result<MessageId> {
779    send_delayed_from_reservation(reservation_id, destination, payload, value, 0)
780}
781
782/// Same as [`send_from_reservation`], but sends the message after the`delay`
783/// expressed in block count.
784#[cfg(not(feature = "ethexe"))]
785pub fn send_delayed_from_reservation(
786    reservation_id: ReservationId,
787    destination: ActorId,
788    payload: &[u8],
789    value: u128,
790    delay: u32,
791) -> Result<MessageId> {
792    let rid_pid_value = TwoHashesWithValue {
793        hash1: reservation_id.into(),
794        hash2: destination.into(),
795        value,
796    };
797
798    let mut res: ErrorWithHash = Default::default();
799
800    let payload_len = payload.len().try_into().map_err(|_| Error::SyscallUsage)?;
801
802    unsafe {
803        gsys::gr_reservation_send(
804            rid_pid_value.as_ptr(),
805            payload.as_ptr(),
806            payload_len,
807            delay,
808            res.as_mut_ptr(),
809        )
810    };
811    SyscallError(res.error_code).into_result()?;
812
813    Ok(res.hash.into())
814}
815
816/// Same as [`send_push`] but uses the input buffer as a payload source.
817///
818/// The first argument is the message handle [`MessageHandle`] that specifies a
819/// particular message built in parts. The second and third arguments are the
820/// offset and length of the input buffer's piece that is to be pushed back to
821/// the output.
822///
823/// # Examples
824///
825/// Send half of the incoming payload back to the sender.
826///
827/// ```
828/// use gcore::msg;
829///
830/// #[unsafe(no_mangle)]
831/// extern "C" fn handle() {
832///     let msg_handle = msg::send_init().expect("Unable to init");
833///     msg::send_push_input(msg_handle, 0, msg::size() as u32 / 2).expect("Unable to push");
834///     msg::send_commit(msg_handle, msg::source(), 0).expect("Unable to commit");
835/// }
836/// ```
837///
838/// /// # See also
839///
840/// - [`reply_push_input`] function allows using the input buffer as a payload
841///   source for a reply message.
842pub fn send_push_input(handle: MessageHandle, offset: u32, len: u32) -> Result<()> {
843    let mut error_code = 0u32;
844    unsafe {
845        gsys::gr_send_push_input(handle.into(), offset, len, &mut error_code as _);
846    }
847    SyscallError(error_code).into_result()
848}
849
850/// Same as [`send_input`], but with explicit gas limit.
851#[cfg(not(feature = "ethexe"))]
852pub fn send_input_with_gas(
853    destination: ActorId,
854    gas_limit: u64,
855    value: u128,
856    offset: u32,
857    len: u32,
858) -> Result<MessageId> {
859    send_input_with_gas_delayed(destination, gas_limit, value, offset, len, 0)
860}
861
862/// Same as [`send_input_with_gas`], but sends delayed.
863#[cfg(not(feature = "ethexe"))]
864pub fn send_input_with_gas_delayed(
865    destination: ActorId,
866    gas_limit: u64,
867    value: u128,
868    offset: u32,
869    len: u32,
870    delay: u32,
871) -> Result<MessageId> {
872    let pid_value = HashWithValue {
873        hash: destination.into(),
874        value,
875    };
876
877    let mut res: ErrorWithHash = Default::default();
878
879    unsafe {
880        gsys::gr_send_input_wgas(
881            pid_value.as_ptr(),
882            offset,
883            len,
884            gas_limit,
885            delay,
886            res.as_mut_ptr(),
887        );
888    }
889    SyscallError(res.error_code).into_result()?;
890
891    Ok(res.hash.into())
892}
893
894/// Same as [`send_commit`], but it spends gas from a reservation instead of
895/// borrowing it from the gas limit provided with the incoming message.
896///
897/// # Examples
898///
899/// ```
900/// use gcore::{exec, msg};
901///
902/// #[unsafe(no_mangle)]
903/// extern "C" fn handle() {
904///     let reservation_id = exec::reserve_gas(5_000_000, 100).expect("Unable to reserve");
905///     let msg_handle = msg::send_init().expect("Unable to init");
906///     msg::send_push(msg_handle, b"Hello,").expect("Unable to push");
907///     msg::send_push(msg_handle, b" world!").expect("Unable to push");
908///     msg::send_commit_from_reservation(reservation_id, msg_handle, msg::source(), 42)
909///         .expect("Unable to commit");
910/// }
911/// ```
912///
913/// # See also
914///
915/// - [`send_from_reservation`] allows sending message by using gas from
916///   reservation.
917/// - [`send_push`], [`send_init`] functions allows forming message to send in
918///   parts.
919#[cfg(not(feature = "ethexe"))]
920pub fn send_commit_from_reservation(
921    reservation_id: ReservationId,
922    handle: MessageHandle,
923    destination: ActorId,
924    value: u128,
925) -> Result<MessageId> {
926    send_commit_delayed_from_reservation(reservation_id, handle, destination, value, 0)
927}
928
929/// Same as [`send_commit_from_reservation`], but sends the message after the
930/// `delay` expressed in block count.
931#[cfg(not(feature = "ethexe"))]
932pub fn send_commit_delayed_from_reservation(
933    reservation_id: ReservationId,
934    handle: MessageHandle,
935    destination: ActorId,
936    value: u128,
937    delay: u32,
938) -> Result<MessageId> {
939    let rid_pid_value = TwoHashesWithValue {
940        hash1: reservation_id.into(),
941        hash2: destination.into(),
942        value,
943    };
944
945    let mut res: ErrorWithHash = Default::default();
946
947    unsafe {
948        gsys::gr_reservation_send_commit(
949            handle.into(),
950            rid_pid_value.as_ptr(),
951            delay,
952            res.as_mut_ptr(),
953        )
954    };
955    SyscallError(res.error_code).into_result()?;
956
957    Ok(res.hash.into())
958}
959
960/// Same as [`send`], but sends the message after the `delay` expressed in block
961/// count.
962pub fn send_delayed(
963    destination: ActorId,
964    payload: &[u8],
965    value: u128,
966    delay: u32,
967) -> Result<MessageId> {
968    let pid_value = HashWithValue {
969        hash: destination.into(),
970        value,
971    };
972
973    let mut res: ErrorWithHash = Default::default();
974
975    let payload_len = payload.len().try_into().map_err(|_| Error::SyscallUsage)?;
976
977    unsafe {
978        gsys::gr_send(
979            pid_value.as_ptr(),
980            payload.as_ptr(),
981            payload_len,
982            delay,
983            res.as_mut_ptr(),
984        )
985    };
986    SyscallError(res.error_code).into_result()?;
987
988    Ok(res.hash.into())
989}
990
991/// Same as [`send`], but with an explicit gas limit.
992///
993/// # Examples
994///
995/// ```
996/// use gcore::msg;
997///
998/// #[unsafe(no_mangle)]
999/// extern "C" fn handle() {
1000///     let id: [u8; 32] = core::array::from_fn(|i| i as u8);
1001///     msg::send_with_gas(id.into(), b"HELLO", 5_000_000, 42).expect("Unable to send");
1002/// }
1003/// ```
1004///
1005/// # See also
1006///
1007/// - [`reply_with_gas`] function sends a reply with an explicit gas limit.
1008/// - [`send_init`],[`send_push`], [`send_commit_with_gas`] functions allow
1009///   forming a message to send in parts with an explicit gas limit.
1010#[cfg(not(feature = "ethexe"))]
1011pub fn send_with_gas(
1012    destination: ActorId,
1013    payload: &[u8],
1014    gas_limit: u64,
1015    value: u128,
1016) -> Result<MessageId> {
1017    send_with_gas_delayed(destination, payload, gas_limit, value, 0)
1018}
1019
1020/// Same as [`send_with_gas`], but sends the message after the `delay` expressed
1021/// in block count.
1022#[cfg(not(feature = "ethexe"))]
1023pub fn send_with_gas_delayed(
1024    destination: ActorId,
1025    payload: &[u8],
1026    gas_limit: u64,
1027    value: u128,
1028    delay: u32,
1029) -> Result<MessageId> {
1030    let pid_value = HashWithValue {
1031        hash: destination.into(),
1032        value,
1033    };
1034
1035    let mut res: ErrorWithHash = Default::default();
1036
1037    let payload_len = payload.len().try_into().map_err(|_| Error::SyscallUsage)?;
1038
1039    unsafe {
1040        gsys::gr_send_wgas(
1041            pid_value.as_ptr(),
1042            payload.as_ptr(),
1043            payload_len,
1044            gas_limit,
1045            delay,
1046            res.as_mut_ptr(),
1047        )
1048    }
1049    SyscallError(res.error_code).into_result()?;
1050
1051    Ok(res.hash.into())
1052}
1053
1054/// Finalize and send the message formed in parts.
1055///
1056/// Gear allows programs to work with messages that consist of several parts.
1057/// This function finalizes the message built in parts and sends it.
1058///
1059/// The first argument is the message handle [`MessageHandle`] that specifies a
1060/// particular message built in parts. The second argument is the address of the
1061/// target account. The third argument is the maximum gas allowed to be utilized
1062/// during the message processing. Finally, the last argument is the value to be
1063/// transferred from the current program account to the message target account.
1064///
1065/// # Examples
1066///
1067/// ```
1068/// use gcore::msg;
1069///
1070/// #[unsafe(no_mangle)]
1071/// extern "C" fn handle() {
1072///     let msg_handle = msg::send_init().expect("Unable to init");
1073///     msg::send_push(msg_handle, b"Hello, ").expect("Unable to push");
1074///     msg::send_push(msg_handle, b" world!").expect("Unable to push");
1075///     msg::send_commit(msg_handle, msg::source(), 42).expect("Unable to commit");
1076/// }
1077/// ```
1078///
1079/// # See also
1080///
1081/// - [`send`] function allows sending a message in one step.
1082/// - [`send_push`], [`send_init`] functions allow forming a message to send in
1083///   parts.
1084pub fn send_commit(handle: MessageHandle, destination: ActorId, value: u128) -> Result<MessageId> {
1085    send_commit_delayed(handle, destination, value, 0)
1086}
1087
1088/// Same as [`send_commit`], but sends the message after the `delay` expressed
1089/// in block count.
1090pub fn send_commit_delayed(
1091    handle: MessageHandle,
1092    destination: ActorId,
1093    value: u128,
1094    delay: u32,
1095) -> Result<MessageId> {
1096    let pid_value = HashWithValue {
1097        hash: destination.into(),
1098        value,
1099    };
1100
1101    let mut res: ErrorWithHash = Default::default();
1102
1103    unsafe { gsys::gr_send_commit(handle.into(), pid_value.as_ptr(), delay, res.as_mut_ptr()) };
1104    SyscallError(res.error_code).into_result()?;
1105
1106    Ok(res.hash.into())
1107}
1108
1109/// Same as [`send_commit`], but with an explicit gas limit.
1110///
1111/// # Examples
1112///
1113/// ```
1114/// use gcore::msg;
1115///
1116/// #[unsafe(no_mangle)]
1117/// extern "C" fn handle() {
1118///     let msg_handle = msg::send_init().expect("Unable to init");
1119///     msg::send_push(msg_handle, b"Hello,").expect("Unable to push");
1120///     msg::send_push(msg_handle, b" world!").expect("Unable to push");
1121///     msg::send_commit_with_gas(msg_handle, msg::source(), 10_000_000, 42)
1122///         .expect("Unable to commit");
1123/// }
1124/// ```
1125///
1126/// # See also
1127///
1128/// - [`send`] function allows sending a message in one step.
1129/// - [`send_push`], [`send_init`] functions allows forming a message to send in
1130///   parts.
1131#[cfg(not(feature = "ethexe"))]
1132pub fn send_commit_with_gas(
1133    handle: MessageHandle,
1134    destination: ActorId,
1135    gas_limit: u64,
1136    value: u128,
1137) -> Result<MessageId> {
1138    send_commit_with_gas_delayed(handle, destination, gas_limit, value, 0)
1139}
1140
1141/// Same as [`send_commit_with_gas`], but sends the message after the `delay`
1142/// expressed in block count.
1143#[cfg(not(feature = "ethexe"))]
1144pub fn send_commit_with_gas_delayed(
1145    handle: MessageHandle,
1146    destination: ActorId,
1147    gas_limit: u64,
1148    value: u128,
1149    delay: u32,
1150) -> Result<MessageId> {
1151    let pid_value = HashWithValue {
1152        hash: destination.into(),
1153        value,
1154    };
1155
1156    let mut res: ErrorWithHash = Default::default();
1157
1158    unsafe {
1159        gsys::gr_send_commit_wgas(
1160            handle.into(),
1161            pid_value.as_ptr(),
1162            gas_limit,
1163            delay,
1164            res.as_mut_ptr(),
1165        )
1166    }
1167    SyscallError(res.error_code).into_result()?;
1168
1169    Ok(res.hash.into())
1170}
1171
1172/// Initialize a message to send formed in parts.
1173///
1174/// Gear allows programs to work with messages that consist of several parts.
1175/// This function initializes a message built in parts and returns the
1176/// corresponding [`MessageHandle`].
1177///
1178/// # Examples
1179///
1180/// ```
1181/// use gcore::msg;
1182///
1183/// #[unsafe(no_mangle)]
1184/// extern "C" fn handle() {
1185///     let msg_handle = msg::send_init().expect("Unable to init");
1186///     msg::send_push(msg_handle, b"Hello,").expect("Unable to push");
1187///     msg::send_push(msg_handle, b" world!").expect("Unable to push");
1188///     msg::send_commit(msg_handle, msg::source(), 42).expect("Unable to commit");
1189/// }
1190/// ```
1191///
1192/// # See also
1193/// - [`send`] function allows sending message in one step.
1194/// - [`send_push`], [`send_commit`] functions allows forming a message to send
1195///   in parts.
1196pub fn send_init() -> Result<MessageHandle> {
1197    unsafe {
1198        let mut res: ErrorWithHandle = Default::default();
1199        gsys::gr_send_init(res.as_mut_ptr());
1200        SyscallError(res.error_code).into_result()?;
1201        Ok(res.handle.into())
1202    }
1203}
1204
1205/// Push a payload part of the message to be sent in parts.
1206///
1207/// Gear allows programs to work with messages in parts.
1208/// This function adds a `payload` part to the message specified by the message
1209/// `handle`.
1210///
1211/// The first argument is the message handle [`MessageHandle`] that specifies a
1212/// particular message built in parts. The second argument is the payload
1213/// buffer.
1214///
1215/// # Examples
1216///
1217/// ```
1218/// use gcore::msg;
1219///
1220/// #[unsafe(no_mangle)]
1221/// extern "C" fn handle() {
1222///     let msg_handle = msg::send_init().expect("Unable to init");
1223///     msg::send_push(msg_handle, b"Hello,").expect("Unable to push");
1224///     msg::send_push(msg_handle, b" world!").expect("Unable to push");
1225///     msg::send_commit(msg_handle, msg::source(), 42).expect("Unable to commit");
1226/// }
1227/// ```
1228///
1229/// # See also
1230///
1231/// - [`reply_push`] function allows forming a reply message in parts.
1232/// - [`send`] function allows sending a message in one step.
1233/// - [`send_init`], [`send_commit`] functions allows forming a message in parts
1234///   and send it.
1235pub fn send_push(handle: MessageHandle, payload: &[u8]) -> Result<()> {
1236    let payload_len = payload.len().try_into().map_err(|_| Error::SyscallUsage)?;
1237
1238    let mut error_code = 0u32;
1239    unsafe {
1240        gsys::gr_send_push(
1241            handle.into(),
1242            payload.as_ptr(),
1243            payload_len,
1244            &mut error_code,
1245        )
1246    };
1247    SyscallError(error_code).into_result()
1248}
1249
1250/// Get the payload size of the message that is being processed.
1251///
1252/// This function returns the payload size of the current message that is being
1253/// processed.
1254///
1255/// # Examples
1256///
1257/// ```
1258/// use gcore::msg;
1259///
1260/// #[unsafe(no_mangle)]
1261/// extern "C" fn handle() {
1262///     let payload_size = msg::size();
1263/// }
1264/// ```
1265pub fn size() -> usize {
1266    let mut size = 0u32;
1267    unsafe { gsys::gr_size(&mut size as *mut u32) };
1268    size as usize
1269}
1270
1271/// Get the identifier of the message source (256-bit address).
1272///
1273/// This function is used to obtain the [`ActorId`] of the account that sends
1274/// the currently processing message (either a program or a user).
1275///
1276/// # Examples
1277///
1278/// ```
1279/// use gcore::msg;
1280///
1281/// #[unsafe(no_mangle)]
1282/// extern "C" fn handle() {
1283///     let who_sends_message = msg::source();
1284/// }
1285/// ```
1286pub fn source() -> ActorId {
1287    let mut source = ActorId::default();
1288    unsafe { gsys::gr_source(source.as_mut_ptr()) }
1289    source
1290}
1291
1292/// Get the value associated with the message that is being processed.
1293///
1294/// This function returns the value that has been sent along with a current
1295/// message that is being processed.
1296///
1297/// # Examples
1298///
1299/// ```
1300/// use gcore::msg;
1301///
1302/// #[unsafe(no_mangle)]
1303/// extern "C" fn handle() {
1304///     let amount_sent_with_message = msg::value();
1305/// }
1306/// ```
1307pub fn value() -> u128 {
1308    let mut value = 0u128;
1309    unsafe { gsys::gr_value(&mut value as *mut u128) };
1310    value
1311}