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}