use fvm_shared::error::ExitCode;
use fvm_shared::sys::SyscallSafe;
use fvm_shared::sys::out::vm::InvocationContext;
use fvm_shared::version::NetworkVersion;
use super::Context;
use super::error::Abort;
use crate::kernel::{ClassifyResult, Kernel};
#[derive(Copy, Clone)]
pub enum Never {}
unsafe impl SyscallSafe for Never {}
pub fn abort(
context: Context<'_, impl Kernel>,
code: u32,
message_off: u32,
message_len: u32,
) -> Result<Never, Abort> {
use crate::kernel::Context as _;
let code = ExitCode::new(code);
if context.kernel.network_version() >= NetworkVersion::V16 && code.is_system_error() {
return Err(Abort::Exit(
ExitCode::SYS_ILLEGAL_EXIT_CODE,
format!("actor aborted with code {}", code),
));
}
let message = if message_len == 0 {
"actor aborted".to_owned()
} else {
std::str::from_utf8(
context
.memory
.try_slice(message_off, message_len)
.map_err(|e| Abort::from_error(code, e))?,
)
.or_illegal_argument()
.context("error message was not utf8")
.map_err(|e| Abort::from_error(code, e))?
.to_owned()
};
Err(Abort::Exit(code, message))
}
pub fn context(context: Context<'_, impl Kernel>) -> crate::kernel::Result<InvocationContext> {
use anyhow::Context as _;
Ok(InvocationContext {
caller: context.kernel.msg_caller(),
receiver: context.kernel.msg_receiver(),
method_number: context.kernel.msg_method_number(),
value_received: context
.kernel
.msg_value_received()
.try_into()
.context("invalid token amount")
.or_fatal()?,
network_curr_epoch: context.kernel.network_epoch(),
network_version: context.kernel.network_version() as u32,
})
}