use crate::re_throw::OrSyscallThrow;
use crate::sys::{self, SysResult, SyscallNo};
use crate::types::{ContractAddress, RuntimeMemoryLength, SHA256Hash};
use crate::xdr::*;
use crate::{FaultString, HandlingError};
use core::mem::MaybeUninit;
pub fn contract_abort(buf: &[u8]) -> ! {
let revert = true;
sys::raw_Return(buf, revert, &[])
}
pub fn contract_revert() -> ! {
sys::raw_Exit()
}
#[cfg(all(not(target_arch = "riscv32"), feature = "std"))]
#[track_caller]
pub(crate) fn abort_breadcrumb(
verb: &str,
location_label: &str,
exn: &dyn core::fmt::Debug,
) {
std::println!();
std::println!(" {verb} exception {:?}", exn);
std::println!(" {location_label}: {}", core::panic::Location::caller());
std::println!(" Backtrace:\n{}", unsafe { crate::Backtrace::capture() });
}
#[inline]
#[cfg_attr(not(target_arch = "riscv32"), track_caller)]
pub fn contract_abort_encoded<T>(exn: &T) -> !
where
T: WriteXDR + ?Sized + core::fmt::Debug,
{
#[cfg(all(not(target_arch = "riscv32"), feature = "std"))]
abort_breadcrumb("Throwing", "Location", &exn);
_contract_abort_encoded(exn)
}
#[inline(never)]
fn _contract_abort_encoded<T>(exn: &T) -> !
where
T: WriteXDR + ?Sized + core::fmt::Debug,
{
crate::call::with_scratch(|buf| {
crate::internal::encode_scratch(buf, exn)
.unwrap_or_else(|e| exception_encoding_error(e));
contract_abort(buf.as_ref());
})
}
#[cold]
#[inline(never)]
fn exception_encoding_error(err: WriteError) -> ! {
use crate::exn::LibraryExn;
crate::exn::abort_encode::library_abort(&LibraryExn::from(
HandlingError::EncodingException(FaultString::via_display(&err)),
))
}
pub fn get_caller() -> ContractAddress {
let mut out_addr: MaybeUninit<ContractAddress> =
MaybeUninit::<ContractAddress>::uninit();
sys::uninit_GetMsgSender(&mut out_addr)
.or_syscall_throw(SyscallNo::kGetMsgSender);
unsafe { out_addr.assume_init() }
}
pub fn get_source_transaction_hash() -> SHA256Hash {
let mut out_hash: MaybeUninit<SHA256Hash> =
MaybeUninit::<SHA256Hash>::uninit();
sys::uninit_GetSourceTransactionHash(&mut out_hash)
.or_syscall_throw(SyscallNo::kGetSourceTransactionHash);
unsafe { out_hash.assume_init() }
}
pub fn get_current_address() -> ContractAddress {
let mut out_addr: MaybeUninit<ContractAddress> =
MaybeUninit::<ContractAddress>::uninit();
sys::uninit_GetCurrentAddress(&mut out_addr)
.or_syscall_throw(SyscallNo::kGetCurrentAddress);
unsafe { out_addr.assume_init() }
}
pub fn try_get_calldata_len() -> SysResult<RuntimeMemoryLength> {
let mut out: RuntimeMemoryLength = 0;
let mut _auth_token_count: u32 = 0;
sys::raw_GetCalldataLen(&mut out, &mut _auth_token_count)?;
Ok(out)
}
pub fn get_calldata_len() -> RuntimeMemoryLength {
try_get_calldata_len().or_syscall_throw(SyscallNo::kGetCalldataLen)
}
pub type Calldata = crate::internal::ScratchBuf;
#[cfg(feature = "alloc")]
fn fetch_calldata_and_auth_tokens_into(
calldata: &mut Calldata,
) -> SysResult<u32> {
let mut len: RuntimeMemoryLength = 0;
let mut _auth_token_count: u32 = 0;
sys::raw_GetCalldataLen(&mut len, &mut _auth_token_count)?;
let len = len as usize;
calldata.clear();
calldata.reserve(len);
let mut written: MaybeUninit<RuntimeMemoryLength> = MaybeUninit::uninit();
let mut auth_token_count: MaybeUninit<u32> = MaybeUninit::uninit();
sys::uninit_GetCalldata(
&mut calldata.spare_capacity_mut()[..len],
&mut written,
&mut auth_token_count,
)?;
let written = unsafe { written.assume_init() } as usize;
if written != len {
return Err(
sys::SyscallErrorCode::kSyscallErrorCodeInvalidSyscallInput.into(),
);
}
unsafe { calldata.set_len(written) };
Ok(unsafe { auth_token_count.assume_init() })
}
#[cfg(not(feature = "alloc"))]
fn fetch_calldata_and_auth_tokens_into(
calldata: &mut Calldata,
) -> SysResult<u32> {
calldata.clear();
let mut written: MaybeUninit<RuntimeMemoryLength> = MaybeUninit::uninit();
let mut auth_token_count: MaybeUninit<u32> = MaybeUninit::uninit();
sys::uninit_GetCalldata(
calldata.spare_capacity_mut(),
&mut written,
&mut auth_token_count,
)?;
let written = unsafe { written.assume_init() } as usize;
if written > calldata.capacity() {
return Err(
sys::SyscallErrorCode::kSyscallErrorCodeInvalidSyscallInput.into(),
);
}
unsafe { calldata.set_len(written) };
Ok(unsafe { auth_token_count.assume_init() })
}
#[doc(hidden)]
#[inline(never)]
pub fn fetch_calldata_and_auth_tokens(calldata: &mut Calldata) -> u32 {
fetch_calldata_and_auth_tokens_into(calldata)
.or_syscall_throw(SyscallNo::kGetCalldata)
}