Skip to main content

gear_wasm_instrument/
syscalls.rs

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