multiversx_chain_vm/host/vm_hooks/vh_handler/
vh_endpoint_arg.rs

1use multiversx_chain_vm_executor::VMHooksEarlyExit;
2use num_bigint::{BigInt, BigUint};
3use num_traits::ToPrimitive;
4
5use crate::host::vm_hooks::vh_early_exit::early_exit_vm_error;
6use crate::host::vm_hooks::VMHooksContext;
7use crate::vm_err_msg;
8
9use crate::types::RawHandle;
10
11use super::VMHooksHandler;
12
13/// Interface to only be used by code generated by the macros.
14/// The smart contract code doesn't have access to these methods directly.
15impl<C: VMHooksContext> VMHooksHandler<C> {
16    pub fn get_num_arguments(&mut self) -> Result<i32, VMHooksEarlyExit> {
17        Ok(self.context.input_ref().args.len() as i32)
18    }
19
20    pub fn get_argument_len(&mut self, arg_index: i32) -> Result<usize, VMHooksEarlyExit> {
21        let arg = self.context.input_ref().get_argument_vec_u8(arg_index);
22        Ok(arg.len())
23    }
24
25    pub fn load_argument_managed_buffer(
26        &mut self,
27        arg_index: i32,
28        dest: RawHandle,
29    ) -> Result<(), VMHooksEarlyExit> {
30        self.use_gas(
31            self.gas_schedule()
32                .managed_buffer_api_cost
33                .m_buffer_set_bytes,
34        )?;
35
36        let arg_bytes = self.context.input_ref().get_argument_vec_u8(arg_index);
37        self.context.m_types_lock().mb_set(dest, arg_bytes);
38
39        Ok(())
40    }
41
42    pub fn load_argument_big_int_unsigned(
43        &mut self,
44        arg_index: i32,
45        dest: RawHandle,
46    ) -> Result<(), VMHooksEarlyExit> {
47        self.use_gas(
48            self.gas_schedule()
49                .big_int_api_cost
50                .big_int_set_unsigned_bytes,
51        )?;
52
53        let arg_bytes = self.context.input_ref().get_argument_vec_u8(arg_index);
54        self.context
55            .m_types_lock()
56            .bi_set_unsigned_bytes(dest, &arg_bytes);
57
58        Ok(())
59    }
60
61    pub fn load_argument_big_int_signed(
62        &mut self,
63        arg_index: i32,
64        dest: RawHandle,
65    ) -> Result<(), VMHooksEarlyExit> {
66        self.use_gas(
67            self.gas_schedule()
68                .big_int_api_cost
69                .big_int_set_signed_bytes,
70        )?;
71
72        let arg_bytes = self.context.input_ref().get_argument_vec_u8(arg_index);
73        self.context
74            .m_types_lock()
75            .bi_set_signed_bytes(dest, &arg_bytes);
76
77        Ok(())
78    }
79
80    pub fn get_argument_i64(&mut self, arg_index: i32) -> Result<i64, VMHooksEarlyExit> {
81        // specific implementation provided, in order to simulate the VM error (status 10 instead of 4)
82        let bytes = self.context.input_ref().get_argument_vec_u8(arg_index);
83        let bi = BigInt::from_signed_bytes_be(&bytes);
84        if let Some(v) = bi.to_i64() {
85            Ok(v)
86        } else {
87            Err(early_exit_vm_error(vm_err_msg::ARG_OUT_OF_RANGE))
88        }
89    }
90
91    pub fn get_argument_u64(&mut self, arg_index: i32) -> Result<u64, VMHooksEarlyExit> {
92        // specific implementation provided, in order to simulate the VM error (status 10 instead of 4)
93        let bytes = self.context.input_ref().get_argument_vec_u8(arg_index);
94        let bu = BigUint::from_bytes_be(&bytes);
95        if let Some(v) = bu.to_u64() {
96            Ok(v)
97        } else {
98            Err(early_exit_vm_error(vm_err_msg::ARG_OUT_OF_RANGE))
99        }
100    }
101
102    pub fn load_callback_closure_buffer(
103        &mut self,
104        dest: RawHandle,
105    ) -> Result<(), VMHooksEarlyExit> {
106        let has_closure_data = self
107            .context
108            .input_ref()
109            .promise_callback_closure_data
110            .is_some();
111
112        if has_closure_data {
113            self.use_gas(
114                self.gas_schedule()
115                    .managed_buffer_api_cost
116                    .m_buffer_set_bytes,
117            )?;
118
119            let closure_data = self
120                .context
121                .input_ref()
122                .promise_callback_closure_data
123                .clone()
124                .unwrap();
125
126            self.context.m_types_lock().mb_set(dest, closure_data);
127            Ok(())
128        } else {
129            Err(early_exit_vm_error(vm_err_msg::ERROR_NO_CALLBACK_CLOSURE))
130        }
131    }
132}