use anyhow::{Context as _, anyhow};
use fvm_shared::{ActorID, sys};
use super::Context;
use super::ControlFlow;
use super::error::Abort;
use crate::kernel::UpgradeOps;
use crate::kernel::{ActorOps, CallResult, ClassifyResult, Result};
use crate::{Kernel, syscall_error};
pub fn resolve_address(
context: Context<'_, impl ActorOps>,
addr_off: u32, addr_len: u32,
) -> Result<u64> {
let addr = context.memory.read_address(addr_off, addr_len)?;
let actor_id = context.kernel.resolve_address(&addr)?;
Ok(actor_id)
}
pub fn lookup_delegated_address(
context: Context<'_, impl ActorOps>,
actor_id: ActorID,
obuf_off: u32,
obuf_len: u32,
) -> Result<u32> {
let obuf = context.memory.try_slice_mut(obuf_off, obuf_len)?;
match context.kernel.lookup_delegated_address(actor_id)? {
Some(address) => {
let address = address.to_bytes();
obuf.get_mut(..address.len())
.ok_or_else(
|| syscall_error!(BufferTooSmall; "address output buffer is too small"),
)?
.copy_from_slice(&address);
Ok(address.len() as u32)
}
None => Ok(0),
}
}
pub fn get_actor_code_cid(
context: Context<'_, impl ActorOps>,
actor_id: u64,
obuf_off: u32, obuf_len: u32,
) -> Result<u32> {
context.memory.check_bounds(obuf_off, obuf_len)?;
let typ = context.kernel.get_actor_code_cid(actor_id)?;
context.memory.write_cid(&typ, obuf_off, obuf_len)
}
pub fn next_actor_address(
context: Context<'_, impl ActorOps>,
obuf_off: u32, obuf_len: u32,
) -> Result<u32> {
let obuf = context.memory.try_slice_mut(obuf_off, obuf_len)?;
const EXPECTED_LEN: u32 = fvm_shared::address::PAYLOAD_HASH_LEN as u32 + 1;
if obuf_len < EXPECTED_LEN {
return Err(
syscall_error!(BufferTooSmall; "output buffer must have a minimum capacity of 21 bytes").into(),
);
}
let addr = context.kernel.next_actor_address()?;
let bytes = addr.to_bytes();
let len = bytes.len();
if len > obuf_len as usize {
return Err(anyhow!("created {} byte actor address", len)).or_fatal();
}
obuf[..len].copy_from_slice(bytes.as_slice());
Ok(len as u32)
}
pub fn create_actor(
context: Context<'_, impl ActorOps>,
actor_id: u64, typ_off: u32, delegated_addr_off: u32,
delegated_addr_len: u32,
) -> Result<()> {
let typ = context.memory.read_cid(typ_off)?;
let addr = (delegated_addr_len > 0)
.then(|| {
context
.memory
.read_address(delegated_addr_off, delegated_addr_len)
})
.transpose()?;
context.kernel.create_actor(typ, actor_id, addr)
}
pub fn upgrade_actor(
context: Context<'_, impl UpgradeOps + Kernel>,
new_code_cid_off: u32,
params_id: u32,
) -> ControlFlow<sys::out::send::Send> {
let cid = match context.memory.read_cid(new_code_cid_off) {
Ok(cid) => cid,
Err(err) => return err.into(),
};
match context.kernel.upgrade_actor(cid, params_id) {
Ok(CallResult {
block_id,
block_stat,
exit_code,
}) => {
if exit_code.is_success() {
ControlFlow::Abort(Abort::Exit(exit_code, String::new(), block_id))
} else {
ControlFlow::Return(sys::out::send::Send {
exit_code: exit_code.value(),
return_id: block_id,
return_codec: block_stat.codec,
return_size: block_stat.size,
})
}
}
Err(err) => err.into(),
}
}
pub fn get_builtin_actor_type(
context: Context<'_, impl ActorOps>,
code_cid_off: u32, ) -> Result<i32> {
let cid = context.memory.read_cid(code_cid_off)?;
Ok(context.kernel.get_builtin_actor_type(&cid)? as i32)
}
pub fn get_code_cid_for_type(
context: Context<'_, impl ActorOps>,
typ: i32,
obuf_off: u32, obuf_len: u32,
) -> Result<u32> {
context.memory.check_bounds(obuf_off, obuf_len)?;
let k = context.kernel.get_code_cid_for_type(typ as u32)?;
context.memory.write_cid(&k, obuf_off, obuf_len)
}
pub fn install_actor(
context: Context<'_, impl ActorOps>,
typ_off: u32, ) -> Result<()> {
let typ = context.memory.read_cid(typ_off)?;
context.kernel.install_actor(typ)
}
pub fn balance_of(context: Context<'_, impl ActorOps>, actor_id: u64) -> Result<sys::TokenAmount> {
let balance = context.kernel.balance_of(actor_id)?;
balance
.try_into()
.context("balance exceeds u128 limit")
.or_fatal()
}