1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
// Copyright 2021-2023 Protocol Labs
// SPDX-License-Identifier: Apache-2.0, MIT
//! This module contains types exchanged at the syscall layer between actors
//! (usually through the SDK) and the FVM.
use bitflags::bitflags;
use num_bigint::TryFromBigIntError;
pub mod out;
pub type BlockId = u32;
pub type Codec = u64;
/// The token amount type used in syscalls. It can represent any token amount (in atto-FIL) from 0
/// to `2^128-1` attoFIL. Or 0 to about 340 exaFIL.
///
/// Internally, this type is a tuple of `u64`s storing the "low" and "high" bits of a little-endian
/// u128.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(packed, C)]
pub struct TokenAmount {
pub lo: u64,
pub hi: u64,
}
impl From<TokenAmount> for crate::econ::TokenAmount {
fn from(v: TokenAmount) -> Self {
crate::econ::TokenAmount::from_atto((v.hi as u128) << 64 | (v.lo as u128))
}
}
impl TryFrom<crate::econ::TokenAmount> for TokenAmount {
type Error = TryFromBigIntError<()>;
fn try_from(v: crate::econ::TokenAmount) -> Result<Self, Self::Error> {
v.atto().try_into().map(|v: u128| Self {
hi: (v >> u64::BITS) as u64,
lo: v as u64,
})
}
}
impl<'a> TryFrom<&'a crate::econ::TokenAmount> for TokenAmount {
type Error = TryFromBigIntError<()>;
fn try_from(v: &'a crate::econ::TokenAmount) -> Result<Self, Self::Error> {
v.atto().try_into().map(|v: u128| Self {
hi: (v >> u64::BITS) as u64,
lo: v as u64,
})
}
}
bitflags! {
/// Flags passed to the send syscall.
#[derive(Default, Copy, Clone, Eq, PartialEq, Debug)]
#[repr(transparent)]
// note: this is 64 bits because I don't want to hate my past self, not because we need them
// right now. It doesn't really cost anything anyways.
pub struct SendFlags: u64 {
/// Send in "read-only" mode.
const READ_ONLY = 0b00000001;
}
}
impl SendFlags {
pub fn read_only(self) -> bool {
self.intersects(Self::READ_ONLY)
}
}
/// A fixed sized struct for serializing an [event `Entry`](crate::event::Entry) separately from the
/// key/value bytes.
#[repr(C, packed)]
pub struct EventEntry {
pub flags: crate::event::Flags,
pub codec: u64,
pub key_len: u32,
pub val_len: u32,
}
/// An unsafe trait to mark "syscall safe" types. These types must be safe to memcpy to and from
/// WASM. This means:
///
/// 1. Repr C & packed alignment (no reordering, no padding).
/// 2. Copy, Sized, and no pointers.
/// 3. No floats (non-determinism).
///
/// # Safety
///
/// Incorrectly implementing this could lead to undefined behavior in types passed between wasm and
/// rust.
pub unsafe trait SyscallSafe: Copy + Sized + 'static {}
macro_rules! assert_syscall_safe {
($($t:ty,)*) => {
$(unsafe impl SyscallSafe for $t {})*
}
}
assert_syscall_safe! {
(),
u8, u16, u32, u64,
i8, i16, i32, i64,
TokenAmount,
out::ipld::IpldOpen,
out::ipld::IpldStat,
out::send::Send,
out::crypto::VerifyConsensusFault,
out::network::NetworkContext,
out::vm::MessageContext,
}
unsafe impl<T, const N: usize> SyscallSafe for [T; N] where T: SyscallSafe {}