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