gear_wasm_instrument/
syscalls.rs

1// This file is part of Gear.
2
3// Copyright (C) 2022-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//! Gear syscalls for programs execution signatures.
20
21pub use pointers::*;
22
23use alloc::{borrow::ToOwned, collections::BTreeMap, string::String, vec::Vec};
24use core::iter;
25use enum_iterator::{self, Sequence};
26use wasmparser::{FuncType, ValType};
27
28/// All available syscalls.
29///
30/// The type is mainly used to prevent from skipping syscall integration test
31/// for a newly introduced syscall or from typo in syscall name.
32#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Sequence, Hash)]
33pub enum SyscallName {
34    // Message sending related
35    // --
36    // Sending `handle` message
37    Send,
38    SendWGas,
39    SendCommit,
40    SendCommitWGas,
41    SendInit,
42    SendPush,
43    ReservationSend,
44    ReservationSendCommit,
45    SendInput,
46    SendPushInput,
47    SendInputWGas,
48
49    // Sending `handle_reply` message
50    Reply,
51    ReplyWGas,
52    ReplyCommit,
53    ReplyCommitWGas,
54    ReplyPush,
55    ReservationReply,
56    ReservationReplyCommit,
57    ReplyInput,
58    ReplyPushInput,
59    ReplyInputWGas,
60
61    // Sending `init` message
62    CreateProgram,
63    CreateProgramWGas,
64
65    // Message data related
66    Read,
67    ReplyTo,
68    SignalFrom,
69    Size,
70    ReplyCode,
71    SignalCode,
72    MessageId,
73    ProgramId,
74    Source,
75    Value,
76
77    // Program execution related
78    // --
79    // Execution environmental data
80    EnvVars,
81    BlockHeight,
82    BlockTimestamp,
83    GasAvailable,
84    ValueAvailable,
85
86    // Changing execution path calls
87    Exit,
88    Leave,
89    Wait,
90    WaitFor,
91    WaitUpTo,
92    Wake,
93    Panic,
94    OomPanic,
95
96    // Hard under the hood calls, serving proper program execution
97    Alloc,
98    Free,
99    FreeRange,
100    SystemBreak,
101
102    // Miscellaneous
103    ReplyDeposit,
104    Debug,
105    Random,
106    ReserveGas,
107    UnreserveGas,
108    SystemReserveGas,
109}
110
111impl SyscallName {
112    /// Returns name of the syscall.
113    pub fn to_str(&self) -> &'static str {
114        match self {
115            Self::Alloc => "alloc",
116            Self::EnvVars => "gr_env_vars",
117            Self::BlockHeight => "gr_block_height",
118            Self::BlockTimestamp => "gr_block_timestamp",
119            Self::CreateProgram => "gr_create_program",
120            Self::CreateProgramWGas => "gr_create_program_wgas",
121            Self::ReplyDeposit => "gr_reply_deposit",
122            Self::Debug => "gr_debug",
123            Self::Panic => "gr_panic",
124            Self::OomPanic => "gr_oom_panic",
125            Self::Exit => "gr_exit",
126            Self::Free => "free",
127            Self::FreeRange => "free_range",
128            Self::GasAvailable => "gr_gas_available",
129            Self::Leave => "gr_leave",
130            Self::MessageId => "gr_message_id",
131            Self::SystemBreak => "gr_system_break",
132            Self::ProgramId => "gr_program_id",
133            Self::Random => "gr_random",
134            Self::Read => "gr_read",
135            Self::Reply => "gr_reply",
136            Self::ReplyCommit => "gr_reply_commit",
137            Self::ReplyCommitWGas => "gr_reply_commit_wgas",
138            Self::ReplyPush => "gr_reply_push",
139            Self::ReplyTo => "gr_reply_to",
140            Self::SignalFrom => "gr_signal_from",
141            Self::ReplyWGas => "gr_reply_wgas",
142            Self::ReplyInput => "gr_reply_input",
143            Self::ReplyPushInput => "gr_reply_push_input",
144            Self::ReplyInputWGas => "gr_reply_input_wgas",
145            Self::ReservationReply => "gr_reservation_reply",
146            Self::ReservationReplyCommit => "gr_reservation_reply_commit",
147            Self::ReservationSend => "gr_reservation_send",
148            Self::ReservationSendCommit => "gr_reservation_send_commit",
149            Self::ReserveGas => "gr_reserve_gas",
150            Self::Send => "gr_send",
151            Self::SendCommit => "gr_send_commit",
152            Self::SendCommitWGas => "gr_send_commit_wgas",
153            Self::SendInit => "gr_send_init",
154            Self::SendPush => "gr_send_push",
155            Self::SendWGas => "gr_send_wgas",
156            Self::SendInput => "gr_send_input",
157            Self::SendPushInput => "gr_send_push_input",
158            Self::SendInputWGas => "gr_send_input_wgas",
159            Self::Size => "gr_size",
160            Self::Source => "gr_source",
161            Self::ReplyCode => "gr_reply_code",
162            Self::SignalCode => "gr_signal_code",
163            Self::SystemReserveGas => "gr_system_reserve_gas",
164            Self::UnreserveGas => "gr_unreserve_gas",
165            Self::Value => "gr_value",
166            Self::ValueAvailable => "gr_value_available",
167            Self::Wait => "gr_wait",
168            Self::WaitFor => "gr_wait_for",
169            Self::WaitUpTo => "gr_wait_up_to",
170            Self::Wake => "gr_wake",
171        }
172    }
173
174    /// Returns iterator of all syscalls.
175    pub fn all() -> impl Iterator<Item = Self> {
176        enum_iterator::all()
177    }
178
179    /// Returns iterator of all syscall names (actually supported by this module
180    /// syscalls).
181    pub fn instrumentable() -> impl Iterator<Item = Self> {
182        Self::all().filter(|syscall| *syscall != Self::SystemBreak)
183    }
184
185    /// Returns map of all syscall string values to syscall names.
186    pub fn instrumentable_map() -> BTreeMap<String, SyscallName> {
187        Self::instrumentable()
188            .map(|syscall| (syscall.to_str().into(), syscall))
189            .collect()
190    }
191
192    /// Returns signature for syscall by name.
193    pub fn signature(self) -> SyscallSignature {
194        use RegularParamType::*;
195
196        match self {
197            Self::Alloc => SyscallSignature::system(([Alloc], [ValType::I32])),
198            Self::Free => SyscallSignature::system(([Free], [ValType::I32])),
199            Self::FreeRange => SyscallSignature::system(([Free, FreeUpperBound], [ValType::I32])),
200            Self::Debug => SyscallSignature::gr_infallible([
201                Ptr::SizedBufferStart {
202                    length_param_idx: 1,
203                }
204                .into(),
205                Length,
206            ]),
207            Self::Panic => SyscallSignature::gr_infallible([
208                Ptr::SizedBufferStart {
209                    length_param_idx: 1,
210                }
211                .into(),
212                Length,
213            ]),
214            Self::OomPanic => SyscallSignature::gr_infallible([]),
215            Self::BlockHeight => SyscallSignature::gr_infallible([Ptr::MutBlockNumber.into()]),
216            Self::BlockTimestamp => {
217                SyscallSignature::gr_infallible([Ptr::MutBlockTimestamp.into()])
218            }
219            Self::Exit => SyscallSignature::gr_infallible([Ptr::Hash(HashType::ActorId).into()]),
220            Self::GasAvailable => SyscallSignature::gr_infallible([Ptr::MutGas.into()]),
221            Self::ProgramId => {
222                SyscallSignature::gr_infallible([Ptr::MutHash(HashType::ActorId).into()])
223            }
224            Self::Leave => SyscallSignature::gr_infallible([]),
225            Self::ValueAvailable => SyscallSignature::gr_infallible([Ptr::MutValue.into()]),
226            Self::Wait => SyscallSignature::gr_infallible([]),
227            Self::WaitUpTo => SyscallSignature::gr_infallible([DurationBlockNumber]),
228            Self::WaitFor => SyscallSignature::gr_infallible([DurationBlockNumber]),
229            Self::Wake => SyscallSignature::gr_fallible((
230                [Ptr::Hash(HashType::MessageId).into(), DelayBlockNumber],
231                ErrPtr::ErrorCode,
232            )),
233            Self::ReplyCode => SyscallSignature::gr_fallible(ErrPtr::ErrorWithReplyCode),
234            Self::SignalCode => SyscallSignature::gr_fallible(ErrPtr::ErrorWithSignalCode),
235            Self::MessageId => {
236                SyscallSignature::gr_infallible([Ptr::MutHash(HashType::MessageId).into()])
237            }
238            Self::EnvVars => SyscallSignature::gr_infallible([Version, Ptr::MutBufferStart.into()]),
239            Self::Read => SyscallSignature::gr_fallible((
240                [
241                    Offset,
242                    Length,
243                    Ptr::MutSizedBufferStart {
244                        length_param_idx: 1,
245                    }
246                    .into(),
247                ],
248                ErrPtr::ErrorCode,
249            )),
250            Self::Reply => SyscallSignature::gr_fallible((
251                [
252                    Ptr::SizedBufferStart {
253                        length_param_idx: 1,
254                    }
255                    .into(),
256                    Length,
257                    Ptr::Value.into(),
258                ],
259                ErrPtr::ErrorWithHash(HashType::MessageId),
260            )),
261            Self::ReplyInput => SyscallSignature::gr_fallible((
262                [Offset, Length, Ptr::Value.into()],
263                ErrPtr::ErrorWithHash(HashType::MessageId),
264            )),
265            Self::ReplyWGas => SyscallSignature::gr_fallible((
266                [
267                    Ptr::SizedBufferStart {
268                        length_param_idx: 1,
269                    }
270                    .into(),
271                    Length,
272                    Gas,
273                    Ptr::Value.into(),
274                ],
275                ErrPtr::ErrorWithHash(HashType::MessageId),
276            )),
277            Self::ReplyInputWGas => SyscallSignature::gr_fallible((
278                [Offset, Length, Gas, Ptr::Value.into()],
279                ErrPtr::ErrorWithHash(HashType::MessageId),
280            )),
281            Self::ReplyCommit => SyscallSignature::gr_fallible((
282                [Ptr::Value.into()],
283                ErrPtr::ErrorWithHash(HashType::MessageId),
284            )),
285            Self::ReplyCommitWGas => SyscallSignature::gr_fallible((
286                [Gas, Ptr::Value.into()],
287                ErrPtr::ErrorWithHash(HashType::MessageId),
288            )),
289            Self::ReservationReply => SyscallSignature::gr_fallible((
290                [
291                    Ptr::HashWithValue(HashType::ReservationId).into(),
292                    Ptr::SizedBufferStart {
293                        length_param_idx: 2,
294                    }
295                    .into(),
296                    Length,
297                ],
298                ErrPtr::ErrorWithHash(HashType::MessageId),
299            )),
300            Self::ReservationReplyCommit => SyscallSignature::gr_fallible((
301                [Ptr::HashWithValue(HashType::ReservationId).into()],
302                ErrPtr::ErrorWithHash(HashType::MessageId),
303            )),
304            Self::ReplyPush => SyscallSignature::gr_fallible((
305                [
306                    Ptr::SizedBufferStart {
307                        length_param_idx: 1,
308                    }
309                    .into(),
310                    Length,
311                ],
312                ErrPtr::ErrorCode,
313            )),
314            Self::ReplyPushInput => {
315                SyscallSignature::gr_fallible(([Offset, Length], ErrPtr::ErrorCode))
316            }
317            Self::ReplyTo => {
318                SyscallSignature::gr_fallible(ErrPtr::ErrorWithHash(HashType::MessageId))
319            }
320            Self::SignalFrom => {
321                SyscallSignature::gr_fallible(ErrPtr::ErrorWithHash(HashType::MessageId))
322            }
323            Self::Send => SyscallSignature::gr_fallible((
324                [
325                    Ptr::HashWithValue(HashType::ActorId).into(),
326                    Ptr::SizedBufferStart {
327                        length_param_idx: 2,
328                    }
329                    .into(),
330                    Length,
331                    DelayBlockNumber,
332                ],
333                ErrPtr::ErrorWithHash(HashType::MessageId),
334            )),
335            Self::SendInput => SyscallSignature::gr_fallible((
336                [
337                    Ptr::HashWithValue(HashType::ActorId).into(),
338                    Offset,
339                    Length,
340                    DelayBlockNumber,
341                ],
342                ErrPtr::ErrorWithHash(HashType::MessageId),
343            )),
344            Self::SendWGas => SyscallSignature::gr_fallible((
345                [
346                    Ptr::HashWithValue(HashType::ActorId).into(),
347                    Ptr::SizedBufferStart {
348                        length_param_idx: 2,
349                    }
350                    .into(),
351                    Length,
352                    Gas,
353                    DelayBlockNumber,
354                ],
355                ErrPtr::ErrorWithHash(HashType::MessageId),
356            )),
357            Self::SendInputWGas => SyscallSignature::gr_fallible((
358                [
359                    Ptr::HashWithValue(HashType::ActorId).into(),
360                    Offset,
361                    Length,
362                    Gas,
363                    DelayBlockNumber,
364                ],
365                ErrPtr::ErrorWithHash(HashType::MessageId),
366            )),
367            Self::SendCommit => SyscallSignature::gr_fallible((
368                [
369                    Handler,
370                    Ptr::HashWithValue(HashType::ActorId).into(),
371                    DelayBlockNumber,
372                ],
373                ErrPtr::ErrorWithHash(HashType::MessageId),
374            )),
375            Self::SendCommitWGas => SyscallSignature::gr_fallible((
376                [
377                    Handler,
378                    Ptr::HashWithValue(HashType::ActorId).into(),
379                    Gas,
380                    DelayBlockNumber,
381                ],
382                ErrPtr::ErrorWithHash(HashType::MessageId),
383            )),
384            Self::SendInit => SyscallSignature::gr_fallible(ErrPtr::ErrorWithHandle),
385            Self::SendPush => SyscallSignature::gr_fallible((
386                [
387                    Handler,
388                    Ptr::SizedBufferStart {
389                        length_param_idx: 2,
390                    }
391                    .into(),
392                    Length,
393                ],
394                ErrPtr::ErrorCode,
395            )),
396            Self::SendPushInput => {
397                SyscallSignature::gr_fallible(([Handler, Offset, Length], ErrPtr::ErrorCode))
398            }
399            Self::ReservationSend => SyscallSignature::gr_fallible((
400                [
401                    Ptr::TwoHashesWithValue(HashType::ReservationId, HashType::ActorId).into(),
402                    Ptr::SizedBufferStart {
403                        length_param_idx: 2,
404                    }
405                    .into(),
406                    Length,
407                    DelayBlockNumber,
408                ],
409                ErrPtr::ErrorWithHash(HashType::MessageId),
410            )),
411            Self::ReservationSendCommit => SyscallSignature::gr_fallible((
412                [
413                    Handler,
414                    Ptr::TwoHashesWithValue(HashType::ReservationId, HashType::ActorId).into(),
415                    DelayBlockNumber,
416                ],
417                ErrPtr::ErrorWithHash(HashType::MessageId),
418            )),
419            Self::Size => SyscallSignature::gr_infallible([Ptr::MutLength.into()]),
420            Self::Source => {
421                SyscallSignature::gr_infallible([Ptr::MutHash(HashType::ActorId).into()])
422            }
423            Self::Value => SyscallSignature::gr_infallible([Ptr::MutValue.into()]),
424            Self::CreateProgram => SyscallSignature::gr_fallible((
425                [
426                    Ptr::HashWithValue(HashType::CodeId).into(),
427                    Ptr::SizedBufferStart {
428                        length_param_idx: 2,
429                    }
430                    .into(),
431                    Length,
432                    Ptr::SizedBufferStart {
433                        length_param_idx: 4,
434                    }
435                    .into(),
436                    Length,
437                    DelayBlockNumber,
438                ],
439                ErrPtr::ErrorWithTwoHashes(HashType::MessageId, HashType::ActorId),
440            )),
441            Self::CreateProgramWGas => SyscallSignature::gr_fallible((
442                [
443                    Ptr::HashWithValue(HashType::CodeId).into(),
444                    Ptr::SizedBufferStart {
445                        length_param_idx: 2,
446                    }
447                    .into(),
448                    Length,
449                    Ptr::SizedBufferStart {
450                        length_param_idx: 4,
451                    }
452                    .into(),
453                    Length,
454                    Gas,
455                    DelayBlockNumber,
456                ],
457                ErrPtr::ErrorWithTwoHashes(HashType::MessageId, HashType::ActorId),
458            )),
459            Self::ReplyDeposit => SyscallSignature::gr_fallible((
460                [Ptr::Hash(HashType::MessageId).into(), Gas],
461                ErrPtr::ErrorCode,
462            )),
463            Self::ReserveGas => SyscallSignature::gr_fallible((
464                [Gas, DurationBlockNumber],
465                ErrPtr::ErrorWithHash(HashType::ReservationId),
466            )),
467            Self::UnreserveGas => SyscallSignature::gr_fallible((
468                [Ptr::Hash(HashType::ReservationId).into()],
469                ErrPtr::ErrorWithGas,
470            )),
471            Self::SystemReserveGas => SyscallSignature::gr_fallible(([Gas], ErrPtr::ErrorCode)),
472            Self::Random => SyscallSignature::gr_infallible([
473                Ptr::Hash(HashType::SubjectId).into(),
474                Ptr::MutBlockNumberWithHash(HashType::SubjectId).into(),
475            ]),
476            Self::SystemBreak => unimplemented!("Unsupported syscall signature for system_break"),
477        }
478    }
479
480    /// Checks whether the syscall returns error either by writing to input
481    /// error pointer or by returning value indicating an error.
482    ///
483    /// There are only 3 syscalls returning error value: `Alloc`, `Free` &
484    /// `FreeRange`.
485    pub fn returns_error(self) -> bool {
486        let signature = self.signature();
487
488        match &signature {
489            SyscallSignature::Fallible(_) | SyscallSignature::System(_) => true,
490            SyscallSignature::Infallible(_) => false,
491        }
492    }
493
494    /// Checks whether the syscall is fallible.
495    ///
496    /// ### Note:
497    /// This differs from [`SyscallName::returns_error`] as fallible syscalls
498    /// are those last param of which is a mutable error pointer.
499    pub fn is_fallible(self) -> bool {
500        self.signature().is_fallible()
501    }
502}
503
504/// Syscall param type.
505#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
506pub enum ParamType {
507    Regular(RegularParamType),
508    Error(ErrPtr),
509}
510
511/// Syscall regular param type.
512///
513/// `Pointer` variant contains additional data about the type this pointer
514/// belongs to, see [`Ptr`] for more details.
515#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
516pub enum RegularParamType {
517    Length,              // i32 buffers length
518    Pointer(Ptr),        // i32 non-error pointer
519    Gas,                 // i64 gas amount
520    Offset,              // i32 offset in the input buffer (message payload)
521    DurationBlockNumber, // i32 duration in blocks
522    DelayBlockNumber,    // i32 delay in blocks
523    Handler,             // i32 handler number
524    Alloc,               // i32 pages to alloc
525    Free,                // i32 page number to free
526    FreeUpperBound,      // i32 free upper bound for use with free_range
527    Version,             // i32 version number of exec settings
528}
529
530/// Hash type.
531///
532/// Used to distinguish between different hash types in the syscall signatures.
533#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
534pub enum HashType {
535    ActorId,
536    CodeId,
537    MessageId,
538    ReservationId,
539    /// This enum variant is used for the `gr_random` syscall.
540    SubjectId,
541}
542
543impl From<ParamType> for ValType {
544    fn from(value: ParamType) -> Self {
545        use RegularParamType::*;
546
547        match value {
548            ParamType::Regular(regular_ptr) => match regular_ptr {
549                Length | Pointer(_) | Offset | DurationBlockNumber | DelayBlockNumber | Handler
550                | Alloc | Free | FreeUpperBound | Version => ValType::I32,
551                Gas => ValType::I64,
552            },
553            ParamType::Error(_) => ValType::I32,
554        }
555    }
556}
557
558/// Syscall signature.
559#[derive(Debug, Clone, PartialEq, Eq, Hash)]
560pub enum SyscallSignature {
561    Fallible(FallibleSyscallSignature),
562    Infallible(InfallibleSyscallSignature),
563    System(SystemSyscallSignature),
564}
565
566impl SyscallSignature {
567    pub fn gr_fallible(fallible: impl Into<FallibleSyscallSignature>) -> Self {
568        Self::Fallible(fallible.into())
569    }
570
571    pub fn gr_infallible(infallible: impl Into<InfallibleSyscallSignature>) -> Self {
572        Self::Infallible(infallible.into())
573    }
574
575    pub fn system(system: impl Into<SystemSyscallSignature>) -> Self {
576        Self::System(system.into())
577    }
578
579    pub fn params(&self) -> &[ParamType] {
580        match self {
581            SyscallSignature::Fallible(fallible) => &fallible.0,
582            SyscallSignature::Infallible(infallible) => &infallible.0,
583            SyscallSignature::System(system) => &system.params,
584        }
585    }
586
587    pub fn results(&self) -> Option<&[ValType]> {
588        match self {
589            SyscallSignature::Fallible(_) | SyscallSignature::Infallible(_) => None,
590            SyscallSignature::System(system) => Some(&system.results),
591        }
592    }
593
594    pub fn func_type(&self) -> FuncType {
595        let (params, results) = match self {
596            SyscallSignature::Fallible(fallible) => (fallible.params(), Vec::new()),
597            SyscallSignature::Infallible(infallible) => (infallible.params(), Vec::new()),
598            SyscallSignature::System(system) => (system.params(), system.results().to_owned()),
599        };
600
601        FuncType::new(
602            params.iter().copied().map(Into::into).collect::<Vec<_>>(),
603            results,
604        )
605    }
606
607    pub fn is_fallible(&self) -> bool {
608        matches!(self, SyscallSignature::Fallible(_))
609    }
610
611    pub fn is_infallible(&self) -> bool {
612        matches!(self, SyscallSignature::Infallible(_))
613    }
614
615    pub fn is_system(&self) -> bool {
616        matches!(self, SyscallSignature::System(_))
617    }
618}
619
620#[derive(Debug, Clone, PartialEq, Eq, Hash)]
621pub struct FallibleSyscallSignature(Vec<ParamType>);
622
623impl FallibleSyscallSignature {
624    pub fn new<const N: usize>(params: [RegularParamType; N], err_ptr: ErrPtr) -> Self {
625        let params = params
626            .into_iter()
627            .map(ParamType::Regular)
628            .chain(iter::once(err_ptr.into()))
629            .collect();
630
631        FallibleSyscallSignature(params)
632    }
633
634    pub fn params(&self) -> &[ParamType] {
635        &self.0
636    }
637}
638
639impl<const N: usize> From<([RegularParamType; N], ErrPtr)> for FallibleSyscallSignature {
640    fn from((params, err_ptr): ([RegularParamType; N], ErrPtr)) -> Self {
641        FallibleSyscallSignature::new(params, err_ptr)
642    }
643}
644
645impl From<ErrPtr> for FallibleSyscallSignature {
646    fn from(err_ptr: ErrPtr) -> Self {
647        FallibleSyscallSignature::new([], err_ptr)
648    }
649}
650
651#[derive(Debug, Clone, PartialEq, Eq, Hash)]
652pub struct InfallibleSyscallSignature(Vec<ParamType>);
653
654impl InfallibleSyscallSignature {
655    pub fn new<const N: usize>(params: [RegularParamType; N]) -> Self {
656        InfallibleSyscallSignature(params.into_iter().map(ParamType::Regular).collect())
657    }
658
659    pub fn params(&self) -> &[ParamType] {
660        &self.0
661    }
662}
663
664impl<const N: usize> From<[RegularParamType; N]> for InfallibleSyscallSignature {
665    fn from(params: [RegularParamType; N]) -> Self {
666        InfallibleSyscallSignature::new(params)
667    }
668}
669
670#[derive(Debug, Clone, PartialEq, Eq, Hash)]
671pub struct SystemSyscallSignature {
672    params: Vec<ParamType>,
673    results: Vec<ValType>,
674}
675
676impl SystemSyscallSignature {
677    pub fn new<const N: usize, const M: usize>(
678        params: [RegularParamType; N],
679        results: [ValType; M],
680    ) -> Self {
681        SystemSyscallSignature {
682            params: params.into_iter().map(ParamType::Regular).collect(),
683            results: results.to_vec(),
684        }
685    }
686
687    pub fn params(&self) -> &[ParamType] {
688        &self.params
689    }
690
691    pub fn results(&self) -> &[ValType] {
692        &self.results
693    }
694}
695
696impl<const N: usize, const M: usize> From<([RegularParamType; N], [ValType; M])>
697    for SystemSyscallSignature
698{
699    fn from((params, results): ([RegularParamType; N], [ValType; M])) -> Self {
700        SystemSyscallSignature::new(params, results)
701    }
702}
703
704// TODO: issue write macros
705mod pointers {
706    use super::{HashType, ParamType, RegularParamType};
707
708    /// Pointer type.
709    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
710    pub enum Ptr {
711        // Const ptrs.
712        SizedBufferStart { length_param_idx: usize },
713        Hash(HashType),
714        Value,
715        HashWithValue(HashType),
716        TwoHashes(HashType, HashType),
717        TwoHashesWithValue(HashType, HashType),
718        // Mutable ptrs.
719        MutBlockNumber,
720        MutBlockTimestamp,
721        MutSizedBufferStart { length_param_idx: usize },
722        MutBufferStart,
723        MutHash(HashType),
724        MutGas,
725        MutLength,
726        MutValue,
727        MutBlockNumberWithHash(HashType),
728    }
729
730    impl Ptr {
731        pub fn is_mutable(self) -> bool {
732            use Ptr::*;
733
734            match self {
735                SizedBufferStart { .. }
736                | Hash(_)
737                | Value
738                | HashWithValue(_)
739                | TwoHashes(_, _)
740                | TwoHashesWithValue(_, _) => false,
741                MutBlockNumber
742                | MutBlockTimestamp
743                | MutSizedBufferStart { .. }
744                | MutBufferStart
745                | MutHash(_)
746                | MutGas
747                | MutLength
748                | MutValue
749                | MutBlockNumberWithHash(_) => true,
750            }
751        }
752    }
753
754    impl From<Ptr> for RegularParamType {
755        fn from(ptr: Ptr) -> RegularParamType {
756            RegularParamType::Pointer(ptr)
757        }
758    }
759
760    /// Error pointer type.
761    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
762    pub enum ErrPtr {
763        ErrorCode,
764        ErrorWithReplyCode,
765        ErrorWithSignalCode,
766        ErrorWithGas,
767        ErrorWithHandle,
768        ErrorWithHash(HashType),
769        ErrorWithTwoHashes(HashType, HashType),
770    }
771
772    impl From<ErrPtr> for ParamType {
773        fn from(err_ptr: ErrPtr) -> ParamType {
774            ParamType::Error(err_ptr)
775        }
776    }
777}