use crate::prelude::*;
pub struct Syscall;
#[cfg(target_arch = "wasm32")]
impl Syscall {
pub fn message_id() -> MessageId {
::gcore::msg::id()
}
pub fn message_size() -> usize {
::gcore::msg::size()
}
pub fn message_source() -> ActorId {
::gcore::msg::source()
}
pub fn message_value() -> ValueUnit {
::gcore::msg::value()
}
pub fn reply_to() -> Result<MessageId, gcore::errors::Error> {
::gcore::msg::reply_to()
}
pub fn reply_code() -> Result<gcore::errors::ReplyCode, gcore::errors::Error> {
::gcore::msg::reply_code()
}
#[cfg(not(feature = "ethexe"))]
pub fn signal_from() -> Result<MessageId, gcore::errors::Error> {
::gcore::msg::signal_from()
}
#[cfg(not(feature = "ethexe"))]
pub fn signal_code() -> Result<Option<::gcore::errors::SignalCode>, gcore::errors::Error> {
::gcore::msg::signal_code()
}
pub fn program_id() -> ActorId {
::gcore::exec::program_id()
}
pub fn block_height() -> u32 {
::gcore::exec::block_height()
}
pub fn block_timestamp() -> u64 {
::gcore::exec::block_timestamp()
}
pub fn value_available() -> ValueUnit {
::gcore::exec::value_available()
}
pub fn gas_available() -> GasUnit {
::gcore::exec::gas_available()
}
pub fn env_vars() -> ::gcore::EnvVars {
::gcore::exec::env_vars()
}
pub fn exit(inheritor_id: ActorId) -> ! {
::gcore::exec::exit(inheritor_id)
}
pub fn panic(data: &[u8]) -> ! {
::gcore::ext::panic(data)
}
pub fn read_bytes() -> Result<Vec<u8>, ::gcore::errors::Error> {
let mut result = vec![0u8; ::gcore::msg::size()];
::gcore::msg::read(result.as_mut())?;
Ok(result)
}
#[cfg(not(feature = "ethexe"))]
pub fn system_reserve_gas(amount: GasUnit) -> Result<(), ::gcore::errors::Error> {
::gcore::exec::system_reserve_gas(amount)
}
}
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(feature = "std"))]
macro_rules! syscall_unimplemented {
($($name:ident( $( $param:ident : $ty:ty ),* ) -> $type:ty),* $(,)?) => {
impl Syscall {
$(
pub fn $name($( $param: $ty ),* ) -> $type {
unimplemented!("{ERROR}")
}
)*
}
};
}
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(feature = "std"))]
const ERROR: &str = "Syscall is implemented only for the wasm32 architecture and the std future";
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(feature = "std"))]
syscall_unimplemented!(
message_id() -> MessageId,
message_size() -> usize,
message_source() -> ActorId,
message_value() -> ValueUnit,
reply_to() -> Result<MessageId, gcore::errors::Error>,
reply_code() -> Result<ReplyCode, gcore::errors::Error>,
signal_from() -> Result<MessageId, gcore::errors::Error>,
signal_code() -> Result<Option<SignalCode>, gcore::errors::Error>,
program_id() -> ActorId,
block_height() -> u32,
block_timestamp() -> u64,
value_available() -> ValueUnit,
gas_available() -> GasUnit,
env_vars() -> ::gcore::EnvVars,
exit(_inheritor_id: ActorId) -> !,
panic(_data: &[u8]) -> !,
read_bytes() -> Result<Vec<u8>, gcore::errors::Error>,
system_reserve_gas(_amount: GasUnit) -> Result<(), ::gcore::errors::Error>,
);
#[cfg(not(target_arch = "wasm32"))]
#[cfg(feature = "std")]
const _: () = {
use core::cell::RefCell;
use paste::paste;
use std::thread_local;
macro_rules! syscall_struct_impl {
($($name:ident() -> $type:ty),* $(,)?) => {
#[derive(Clone)]
struct SyscallState {
$(
$name: $type,
)*
}
thread_local! {
static SYSCALL_STATE: RefCell<SyscallState> = RefCell::new(SyscallState::default());
}
impl Syscall {
$(
pub fn $name() -> $type {
SYSCALL_STATE.with_borrow(|state| state.$name.clone())
}
)*
}
impl Syscall {
$(
paste! {
pub fn [<with_ $name>]($name: $type) {
SYSCALL_STATE.with_borrow_mut(|state| state.$name = $name);
}
}
)*
}
};
}
syscall_struct_impl!(
message_id() -> MessageId,
message_size() -> usize,
message_source() -> ActorId,
message_value() -> ValueUnit,
reply_to() -> Result<MessageId, gcore::errors::Error>,
reply_code() -> Result<ReplyCode, gcore::errors::Error>,
signal_from() -> Result<MessageId, gcore::errors::Error>,
signal_code() -> Result<Option<SignalCode>, gcore::errors::Error>,
program_id() -> ActorId,
block_height() -> u32,
block_timestamp() -> u64,
value_available() -> ValueUnit,
gas_available() -> GasUnit,
read_bytes() -> Result<Vec<u8>, gcore::errors::Error>,
);
impl Default for SyscallState {
fn default() -> Self {
use gear_core_errors::{ExecutionError, ExtError};
Self {
message_id: MessageId::default(),
message_size: 0,
message_source: ActorId::default(),
message_value: 0,
reply_to: Err(ExtError::Execution(ExecutionError::NoReplyContext).into()),
reply_code: Err(ExtError::Execution(ExecutionError::NoReplyContext).into()),
signal_from: Err(ExtError::Execution(ExecutionError::NoSignalContext).into()),
signal_code: Err(ExtError::Execution(ExecutionError::NoSignalContext).into()),
program_id: ActorId::default(),
block_height: 0,
block_timestamp: 0,
value_available: 0,
gas_available: 0,
read_bytes: Err(::gcore::errors::Error::SyscallUsage),
}
}
}
impl Syscall {
pub fn env_vars() -> ::gcore::EnvVars {
::gcore::EnvVars {
performance_multiplier: ::gcore::Percent::new(100),
existential_deposit: 1_000_000_000_000,
mailbox_threshold: 3000,
gas_multiplier: ::gcore::GasMultiplier::from_value_per_gas(100),
}
}
pub fn exit(inheritor_id: ActorId) -> ! {
panic!("Program exited with inheritor id: {}", inheritor_id);
}
pub fn panic(data: &[u8]) -> ! {
if data.starts_with(b"GM") && data.len() >= 16 {
let mut payload = &data[16..];
if let Ok(s) = <String as parity_scale_codec::Decode>::decode(&mut payload) {
panic!("{}", s);
}
}
panic!("{:?}", data);
}
#[cfg(not(feature = "ethexe"))]
pub fn system_reserve_gas(_amount: GasUnit) -> Result<(), ::gcore::errors::Error> {
Ok(())
}
}
};