use multiversx_chain_vm_executor::VMHooksEarlyExit;
use num_bigint::{BigInt, BigUint};
use num_traits::ToPrimitive;
use crate::host::vm_hooks::VMHooksContext;
use crate::host::vm_hooks::vh_early_exit::early_exit_vm_error;
use crate::vm_err_msg;
use crate::types::RawHandle;
use super::VMHooksHandler;
impl<C: VMHooksContext> VMHooksHandler<C> {
pub fn get_num_arguments(&mut self) -> Result<i32, VMHooksEarlyExit> {
self.use_gas(self.gas_schedule().base_ops_api_cost.get_num_arguments)?;
Ok(self.context.input_ref().args.len() as i32)
}
pub fn get_argument_len(&mut self, arg_index: i32) -> Result<usize, VMHooksEarlyExit> {
self.use_gas(self.gas_schedule().base_ops_api_cost.get_argument)?;
let arg = self.context.input_ref().get_argument_vec_u8(arg_index);
Ok(arg.len())
}
pub fn load_argument_managed_buffer(
&mut self,
arg_index: i32,
dest: RawHandle,
) -> Result<(), VMHooksEarlyExit> {
self.use_gas(
self.gas_schedule()
.managed_buffer_api_cost
.m_buffer_set_bytes,
)?;
let arg_bytes = self.context.input_ref().get_argument_vec_u8(arg_index);
self.context.m_types_lock().mb_set(dest, arg_bytes);
Ok(())
}
pub fn load_argument_big_int_unsigned(
&mut self,
arg_index: i32,
dest: RawHandle,
) -> Result<(), VMHooksEarlyExit> {
self.use_gas(
self.gas_schedule()
.big_int_api_cost
.big_int_set_unsigned_bytes,
)?;
let arg_bytes = self.context.input_ref().get_argument_vec_u8(arg_index);
self.context
.m_types_lock()
.bi_set_unsigned_bytes(dest, &arg_bytes);
Ok(())
}
pub fn load_argument_big_int_signed(
&mut self,
arg_index: i32,
dest: RawHandle,
) -> Result<(), VMHooksEarlyExit> {
self.use_gas(
self.gas_schedule()
.big_int_api_cost
.big_int_set_signed_bytes,
)?;
let arg_bytes = self.context.input_ref().get_argument_vec_u8(arg_index);
self.context
.m_types_lock()
.bi_set_signed_bytes(dest, &arg_bytes);
Ok(())
}
pub fn get_argument_i64(&mut self, arg_index: i32) -> Result<i64, VMHooksEarlyExit> {
self.use_gas(self.gas_schedule().base_ops_api_cost.int_64_get_argument)?;
let bytes = self.context.input_ref().get_argument_vec_u8(arg_index);
let bi = BigInt::from_signed_bytes_be(&bytes);
if let Some(v) = bi.to_i64() {
Ok(v)
} else {
Err(early_exit_vm_error(vm_err_msg::ARG_OUT_OF_RANGE))
}
}
pub fn get_argument_u64(&mut self, arg_index: i32) -> Result<u64, VMHooksEarlyExit> {
self.use_gas(self.gas_schedule().base_ops_api_cost.int_64_get_argument)?;
let bytes = self.context.input_ref().get_argument_vec_u8(arg_index);
let bu = BigUint::from_bytes_be(&bytes);
if let Some(v) = bu.to_u64() {
Ok(v)
} else {
Err(early_exit_vm_error(vm_err_msg::ARG_OUT_OF_RANGE))
}
}
pub fn load_callback_closure_buffer(
&mut self,
dest: RawHandle,
) -> Result<(), VMHooksEarlyExit> {
let has_closure_data = self
.context
.input_ref()
.promise_callback_closure_data
.is_some();
if has_closure_data {
self.use_gas(
self.gas_schedule()
.managed_buffer_api_cost
.m_buffer_set_bytes,
)?;
let closure_data = self
.context
.input_ref()
.promise_callback_closure_data
.clone()
.unwrap();
self.context.m_types_lock().mb_set(dest, closure_data);
Ok(())
} else {
Err(early_exit_vm_error(vm_err_msg::ERROR_NO_CALLBACK_CLOSURE))
}
}
}