use std::ptr;
use cid::Cid;
use fvm_shared::address::{Address, MAX_ADDRESS_LEN, Payload};
use fvm_shared::econ::TokenAmount;
use fvm_shared::error::ErrorNumber;
use fvm_shared::{ActorID, MAX_CID_LEN};
use log::error;
use crate::{SyscallResult, sys};
pub fn resolve_address(addr: &Address) -> Option<ActorID> {
if let &Payload::ID(id) = addr.payload() {
return Some(id);
}
let bytes = addr.to_bytes();
unsafe {
match sys::actor::resolve_address(bytes.as_ptr(), bytes.len() as u32) {
Ok(value) => Some(value),
Err(ErrorNumber::NotFound) => None,
Err(other) => panic!("unexpected address resolution failure: {}", other),
}
}
}
pub fn lookup_delegated_address(addr: ActorID) -> Option<Address> {
let mut out_buffer = [0u8; MAX_ADDRESS_LEN];
unsafe {
match sys::actor::lookup_delegated_address(
addr,
out_buffer.as_mut_ptr(),
out_buffer.len() as u32,
) {
Ok(0) => None,
Ok(length) => match Address::from_bytes(&out_buffer[..length as usize]) {
Ok(addr) => Some(addr),
Err(e) => {
error!(
"unexpected address from 'lookup_delegated_address' with protocol {}: {}",
out_buffer[0], e
);
None
}
},
Err(ErrorNumber::NotFound) => None,
Err(other) => panic!("unexpected address resolution failure: {}", other),
}
}
}
pub fn get_actor_code_cid(addr: &Address) -> Option<Cid> {
let id = resolve_address(addr)?;
let mut buf = [0u8; MAX_CID_LEN];
unsafe {
match sys::actor::get_actor_code_cid(id, buf.as_mut_ptr(), MAX_CID_LEN as u32) {
Ok(len) => Some(Cid::read_bytes(&buf[..len as usize]).expect("invalid cid returned")),
Err(ErrorNumber::NotFound) => None,
Err(other) => panic!("unexpected code cid resolution failure: {}", other),
}
}
}
pub fn next_actor_address() -> Address {
let mut buf = [0u8; MAX_ADDRESS_LEN];
unsafe {
let len = sys::actor::next_actor_address(buf.as_mut_ptr(), MAX_ADDRESS_LEN as u32)
.expect("failed to create a new actor address");
Address::from_bytes(&buf[..len as usize]).expect("syscall returned invalid address")
}
}
pub fn create_actor(
actor_id: ActorID,
code_cid: &Cid,
delegated_address: Option<Address>,
) -> SyscallResult<()> {
unsafe {
let cid = code_cid.to_bytes();
let addr_bytes = delegated_address.map(|addr| addr.to_bytes());
let (addr_off, addr_len) = addr_bytes
.as_deref()
.map(|v| (v.as_ptr(), v.len()))
.unwrap_or((ptr::null(), 0));
sys::actor::create_actor(actor_id, cid.as_ptr(), addr_off, addr_len as u32)
}
}
#[cfg(feature = "upgrade-actor")]
pub fn upgrade_actor(
new_code_cid: &Cid,
params: Option<fvm_ipld_encoding::ipld_block::IpldBlock>,
) -> SyscallResult<fvm_shared::Response> {
use crate::{NO_DATA_BLOCK_ID, build_response};
unsafe {
let cid = new_code_cid.to_bytes();
let params_id = match params {
Some(p) => sys::ipld::block_create(p.codec, p.data.as_ptr(), p.data.len() as u32)?,
None => NO_DATA_BLOCK_ID,
};
let send = sys::actor::upgrade_actor(cid.as_ptr(), params_id)?;
build_response(send)
}
}
#[cfg(feature = "m2-native")]
pub fn install_actor(code_cid: &Cid) -> SyscallResult<()> {
let cid = code_cid.to_bytes();
unsafe { sys::actor::install_actor(cid.as_ptr()) }
}
pub fn get_builtin_actor_type(code_cid: &Cid) -> Option<i32> {
let cid = code_cid.to_bytes();
unsafe {
let res = sys::actor::get_builtin_actor_type(cid.as_ptr())
.expect("failed to determine if CID belongs to builtin actor");
if res == 0 { None } else { Some(res) }
}
}
pub fn get_code_cid_for_type(typ: i32) -> Cid {
let mut buf = [0u8; MAX_CID_LEN];
unsafe {
let len = sys::actor::get_code_cid_for_type(typ, buf.as_mut_ptr(), MAX_CID_LEN as u32)
.expect("failed to get CodeCID for type");
Cid::read_bytes(&buf[..len as usize]).expect("invalid cid returned")
}
}
pub fn balance_of(actor_id: ActorID) -> Option<TokenAmount> {
unsafe {
match sys::actor::balance_of(actor_id) {
Ok(balance) => Some(balance.into()),
Err(ErrorNumber::NotFound) => None,
Err(e) => panic!("unexpected error: {e}"),
}
}
}