#![no_std]
use bytemuck::{Pod, Zeroable};
pub type ErrorCode = u32;
pub type BlockNumber = u32;
pub type BlockCount = u32;
pub type BlockTimestamp = u64;
pub type BufferStart = u8;
pub type SizedBufferStart = u8;
pub type Gas = u64;
pub type Handle = u32;
pub type Hash = [u8; 32];
pub type Offset = u32;
pub type Length = u32;
pub type ReplyCode = [u8; 4];
pub type SignalCode = u32;
pub type Value = u128;
#[repr(C)]
#[derive(Default, Debug, Clone, Copy, Zeroable, Pod)]
pub struct BlockNumberWithHash {
pub bn: BlockNumber,
pub hash: Hash,
}
impl BlockNumberWithHash {
pub fn as_mut_ptr(&mut self) -> *mut Self {
self as _
}
}
#[repr(C)]
#[derive(Default, Debug, Clone, Copy, Zeroable, Pod)]
pub struct HashWithValue {
pub hash: Hash,
pub value: Value,
}
impl HashWithValue {
pub const fn as_ptr(&self) -> *const Self {
self as _
}
}
#[repr(C)]
#[derive(Default, Debug, Clone, Copy, Zeroable, Pod)]
pub struct ErrorWithReplyCode {
pub error_code: ErrorCode,
pub reply_code: ReplyCode,
}
impl ErrorWithReplyCode {
pub fn as_mut_ptr(&mut self) -> *mut Self {
self as _
}
}
impl From<Result<ReplyCode, ErrorCode>> for ErrorWithReplyCode {
fn from(result: Result<ReplyCode, ErrorCode>) -> Self {
let mut res: Self = Default::default();
match result {
Ok(code) => res.reply_code = code,
Err(length) => res.error_code = length,
}
res
}
}
#[repr(C)]
#[derive(Default, Debug, Clone, Copy, Zeroable, Pod)]
pub struct ErrorWithSignalCode {
pub error_code: ErrorCode,
pub signal_code: SignalCode,
}
impl ErrorWithSignalCode {
pub fn as_mut_ptr(&mut self) -> *mut Self {
self as _
}
}
impl From<Result<SignalCode, ErrorCode>> for ErrorWithSignalCode {
fn from(result: Result<SignalCode, ErrorCode>) -> Self {
let mut res: Self = Default::default();
match result {
Ok(code) => res.signal_code = code,
Err(code) => res.error_code = code,
}
res
}
}
#[repr(C, packed)]
#[derive(Default, Debug, Clone, Copy, Zeroable, Pod)]
pub struct ErrorWithGas {
pub error_code: ErrorCode,
pub gas: Gas,
}
impl ErrorWithGas {
pub fn as_mut_ptr(&mut self) -> *mut Self {
self as _
}
}
impl From<Result<Gas, ErrorCode>> for ErrorWithGas {
fn from(result: Result<Gas, ErrorCode>) -> Self {
let mut res: Self = Default::default();
match result {
Ok(gas) => res.gas = gas,
Err(code) => res.error_code = code,
}
res
}
}
#[repr(C)]
#[derive(Default, Debug, Clone, Copy, Zeroable, Pod)]
pub struct ErrorWithHandle {
pub error_code: ErrorCode,
pub handle: Handle,
}
impl ErrorWithHandle {
pub fn as_mut_ptr(&mut self) -> *mut Self {
self as _
}
}
impl From<Result<Handle, ErrorCode>> for ErrorWithHandle {
fn from(result: Result<Handle, ErrorCode>) -> Self {
let mut res: Self = Default::default();
match result {
Ok(handle) => res.handle = handle,
Err(code) => res.error_code = code,
}
res
}
}
#[repr(transparent)]
#[derive(Default, Debug, Clone, Copy, Zeroable, Pod)]
pub struct ErrorBytes([u8; size_of::<ErrorCode>()]);
impl From<Result<(), ErrorCode>> for ErrorBytes {
fn from(value: Result<(), ErrorCode>) -> Self {
Self(value.err().unwrap_or_default().to_le_bytes())
}
}
#[repr(C)]
#[derive(Default, Debug, Clone, Copy, Zeroable, Pod)]
pub struct ErrorWithHash {
pub error_code: ErrorCode,
pub hash: Hash,
}
impl ErrorWithHash {
pub fn as_mut_ptr(&mut self) -> *mut Self {
self as _
}
}
impl<T: Into<[u8; 32]>> From<Result<T, ErrorCode>> for ErrorWithHash {
fn from(result: Result<T, ErrorCode>) -> Self {
let mut res: Self = Default::default();
match result {
Ok(v) => res.hash = v.into(),
Err(code) => res.error_code = code,
}
res
}
}
#[repr(C)]
#[derive(Default, Debug, Clone, Copy, Zeroable, Pod)]
pub struct ErrorWithTwoHashes {
pub error_code: ErrorCode,
pub hash1: Hash,
pub hash2: Hash,
}
impl ErrorWithTwoHashes {
pub fn as_mut_ptr(&mut self) -> *mut Self {
self as _
}
}
impl<T1, T2> From<Result<(T1, T2), ErrorCode>> for ErrorWithTwoHashes
where
T1: Into<[u8; 32]>,
T2: Into<[u8; 32]>,
{
fn from(result: Result<(T1, T2), ErrorCode>) -> Self {
let mut res: Self = Default::default();
match result {
Ok((v1, v2)) => {
res.hash1 = v1.into();
res.hash2 = v2.into();
}
Err(code) => res.error_code = code,
}
res
}
}
#[repr(C)]
#[derive(Default, Debug, Clone, Copy, Zeroable, Pod)]
pub struct TwoHashes {
pub hash1: Hash,
pub hash2: Hash,
}
impl TwoHashes {
pub const fn as_ptr(&self) -> *const Self {
self as _
}
}
#[repr(C)]
#[derive(Default, Debug, Clone, Copy, Zeroable, Pod)]
pub struct TwoHashesWithValue {
pub hash1: Hash,
pub hash2: Hash,
pub value: Value,
}
impl TwoHashesWithValue {
pub const fn as_ptr(&self) -> *const Self {
self as _
}
}
#[repr(C, packed)]
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
pub struct EnvVars {
pub performance_multiplier: Percent,
pub existential_deposit: Value,
pub mailbox_threshold: Gas,
pub gas_multiplier: GasMultiplier,
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Zeroable, Pod)]
pub struct Percent(u32);
impl Percent {
pub fn new(value: u32) -> Self {
Self(value)
}
pub fn value(&self) -> u32 {
self.0
}
}
#[repr(C, packed)]
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
pub struct GasMultiplier {
gas_per_value: Gas,
value_per_gas: Value,
}
impl GasMultiplier {
pub const fn one() -> Self {
Self {
gas_per_value: 1,
value_per_gas: 1,
}
}
pub fn from_gas_per_value(gas_per_value: Gas) -> Self {
if gas_per_value == 1 {
Self::one()
} else {
Self {
gas_per_value,
value_per_gas: 0,
}
}
}
pub fn from_value_per_gas(value_per_gas: Value) -> Self {
if value_per_gas == 1 {
Self::one()
} else {
Self {
gas_per_value: 0,
value_per_gas,
}
}
}
pub fn gas_to_value(&self, gas: Gas) -> Value {
if self.value_per_gas != 0 {
(gas as Value).saturating_mul(self.value_per_gas)
} else {
gas.div_ceil(self.gas_per_value) as _
}
}
pub fn value_to_gas(&self, value: Value) -> Gas {
if self.gas_per_value != 0 {
(value as Gas).saturating_mul(self.gas_per_value)
} else {
(value / self.value_per_gas) as _
}
}
}
macro_rules! syscalls {
(
$(
$(#[$attrs:meta])*
$vis:vis fn $symbol:ident(
$($arg_name:ident: $arg_ty:ty),* $(,)?
) $(-> $ret_ty:ty)?;
)*
) => {
#[allow(improper_ctypes)]
unsafe extern "C" {
$(
$(#[$attrs])*
$vis fn $symbol($($arg_name: $arg_ty),*) $(-> $ret_ty)?;
)*
}
#[cfg(not(target_arch = "wasm32"))]
mod declarations {
use $crate::*;
$(
#[unsafe(no_mangle)]
$vis extern "C" fn $symbol($(_: $arg_ty),*) $(-> $ret_ty)? {
unimplemented!(concat!(
stringify!($symbol),
" syscall is only available for wasm32 architecture"
))
}
)*
}
};
}
syscalls! {
pub fn gr_env_vars(version: u32, vars: *mut BufferStart);
pub fn gr_block_height(height: *mut BlockNumber);
pub fn gr_block_timestamp(timestamp: *mut BlockTimestamp);
#[cfg(not(feature = "ethexe"))]
pub fn gr_create_program_wgas(
cid_value: *const HashWithValue,
salt: *const SizedBufferStart,
salt_len: Length,
payload: *const SizedBufferStart,
payload_len: Length,
gas_limit: Gas,
delay: BlockNumber,
err_mid_pid: *mut ErrorWithTwoHashes,
);
pub fn gr_create_program(
cid_value: *const HashWithValue,
salt: *const SizedBufferStart,
salt_len: Length,
payload: *const SizedBufferStart,
payload_len: Length,
delay: BlockNumber,
err_mid_pid: *mut ErrorWithTwoHashes,
);
#[cfg(not(feature = "ethexe"))]
pub fn gr_reply_deposit(message_id: *const Hash, gas: Gas, err: *mut ErrorCode);
pub fn gr_debug(payload: *const SizedBufferStart, len: Length);
pub fn gr_panic(payload: *const SizedBufferStart, len: Length) -> !;
pub fn gr_oom_panic() -> !;
pub fn gr_reply_code(err_code: *mut ErrorWithReplyCode);
#[cfg(not(feature = "ethexe"))]
pub fn gr_signal_code(err_code: *mut ErrorWithSignalCode);
pub fn gr_exit(inheritor_id: *const Hash) -> !;
pub fn gr_gas_available(gas: *mut Gas);
pub fn gr_leave() -> !;
pub fn gr_message_id(message_id: *mut Hash);
pub fn gr_program_id(program_id: *mut Hash);
pub fn gr_random(subject: *const Hash, bn_random: *mut BlockNumberWithHash);
pub fn gr_read(at: Offset, len: Length, buffer: *mut SizedBufferStart, err: *mut ErrorCode);
#[cfg(not(feature = "ethexe"))]
pub fn gr_reply_commit_wgas(gas_limit: Gas, value: *const Value, err_mid: *mut ErrorWithHash);
pub fn gr_reply_commit(value: *const Value, err_mid: *mut ErrorWithHash);
pub fn gr_reply_push(payload: *const SizedBufferStart, len: Length, err: *mut ErrorCode);
pub fn gr_reply_push_input(offset: Offset, len: Length, err: *mut ErrorCode);
pub fn gr_reply_to(err_mid: *mut ErrorWithHash);
#[cfg(not(feature = "ethexe"))]
pub fn gr_signal_from(err_mid: *mut ErrorWithHash);
#[cfg(not(feature = "ethexe"))]
pub fn gr_reply_input_wgas(
offset: Offset,
len: Length,
gas_limit: Gas,
value: *const Value,
err_mid: *mut ErrorWithHash,
);
#[cfg(not(feature = "ethexe"))]
pub fn gr_reply_wgas(
payload: *const SizedBufferStart,
len: Length,
gas_limit: Gas,
value: *const Value,
err_mid: *mut ErrorWithHash,
);
pub fn gr_reply(
payload: *const SizedBufferStart,
len: Length,
value: *const Value,
err_mid: *mut ErrorWithHash,
);
pub fn gr_reply_input(
offset: Offset,
len: Length,
value: *const Value,
err_mid: *mut ErrorWithHash,
);
#[cfg(not(feature = "ethexe"))]
pub fn gr_reservation_reply_commit(
rid_value: *const HashWithValue,
err_mid: *mut ErrorWithHash,
);
#[cfg(not(feature = "ethexe"))]
pub fn gr_reservation_reply(
rid_value: *const HashWithValue,
payload: *const SizedBufferStart,
len: Length,
err_mid: *mut ErrorWithHash,
);
#[cfg(not(feature = "ethexe"))]
pub fn gr_reservation_send_commit(
handle: Handle,
rid_pid_value: *const TwoHashesWithValue,
delay: BlockNumber,
err_mid: *mut ErrorWithHash,
);
#[cfg(not(feature = "ethexe"))]
pub fn gr_reservation_send(
rid_pid_value: *const TwoHashesWithValue,
payload: *const SizedBufferStart,
len: Length,
delay: BlockNumber,
err_mid: *mut ErrorWithHash,
);
#[cfg(not(feature = "ethexe"))]
pub fn gr_reserve_gas(gas: Gas, duration: BlockNumber, err_rid: *mut ErrorWithHash);
#[cfg(not(feature = "ethexe"))]
pub fn gr_send_commit_wgas(
handle: Handle,
pid_value: *const HashWithValue,
gas_limit: Gas,
delay: BlockNumber,
err_mid: *mut ErrorWithHash,
);
pub fn gr_send_commit(
handle: Handle,
pid_value: *const HashWithValue,
delay: BlockNumber,
err_mid: *mut ErrorWithHash,
);
pub fn gr_send_init(err_handle: *mut ErrorWithHandle);
pub fn gr_send_push(
handle: Handle,
payload: *const SizedBufferStart,
len: Length,
err: *mut ErrorCode,
);
pub fn gr_send_push_input(handle: Handle, offset: Offset, len: Length, err: *mut ErrorCode);
#[cfg(not(feature = "ethexe"))]
pub fn gr_send_input_wgas(
pid_value: *const HashWithValue,
offset: Offset,
len: Length,
gas_limit: Gas,
delay: BlockNumber,
err_mid: *mut ErrorWithHash,
);
#[cfg(not(feature = "ethexe"))]
pub fn gr_send_wgas(
pid_value: *const HashWithValue,
payload: *const SizedBufferStart,
len: Length,
gas_limit: Gas,
delay: BlockNumber,
err_mid: *mut ErrorWithHash,
);
pub fn gr_send(
pid_value: *const HashWithValue,
payload: *const SizedBufferStart,
len: Length,
delay: BlockNumber,
err_mid: *mut ErrorWithHash,
);
pub fn gr_send_input(
pid_value: *const HashWithValue,
offset: Offset,
len: Length,
delay: BlockNumber,
err_mid: *mut ErrorWithHash,
);
pub fn gr_size(length: *mut Length);
pub fn gr_source(program_id: *mut Hash);
#[cfg(not(feature = "ethexe"))]
pub fn gr_system_reserve_gas(gas: Gas, err: *mut ErrorCode);
#[cfg(not(feature = "ethexe"))]
pub fn gr_unreserve_gas(reservation_id: *const Hash, err_unreserved: *mut ErrorWithGas);
pub fn gr_value_available(value: *mut Value);
pub fn gr_value(value: *mut Value);
pub fn gr_wait_for(duration: BlockNumber) -> !;
pub fn gr_wait_up_to(duration: BlockNumber) -> !;
pub fn gr_wait() -> !;
pub fn gr_wake(message_id: *const Hash, delay: BlockNumber, err: *mut ErrorCode);
}