Skip to main content

multiversx_sc_scenario/executor/debug/
contract_debug_instance_state.rs

1use multiversx_chain_vm_executor::{
2    BreakpointValue, ExecutorError, InstanceState, MemLength, MemPtr, VMHooksEarlyExit,
3};
4
5#[derive(Clone, Debug)]
6pub struct ContractDebugInstanceState;
7
8impl ContractDebugInstanceState {
9    /// Interprets the input as a regular pointer.
10    ///
11    /// ## Safety
12    ///
13    /// The offset and the length must point to valid memory.
14    pub unsafe fn main_memory_load(mem_ptr: MemPtr, mem_length: MemLength) -> &'static [u8] {
15        unsafe {
16            let bytes_ptr =
17                std::ptr::slice_from_raw_parts(mem_ptr as *const u8, mem_length as usize);
18            &*bytes_ptr
19        }
20    }
21
22    /// Interprets the input as a regular pointer and writes to current memory.
23    ///
24    /// ## Safety
25    ///
26    /// The offset and the length must point to valid memory.
27    pub unsafe fn main_memory_store(offset: MemPtr, data: &[u8]) {
28        unsafe {
29            std::ptr::copy(data.as_ptr(), offset as *mut u8, data.len());
30        }
31    }
32
33    pub fn main_memory_ptr(bytes: &[u8]) -> (MemPtr, MemLength) {
34        (bytes.as_ptr() as MemPtr, bytes.len() as MemLength)
35    }
36
37    pub fn main_memory_mut_ptr(bytes: &mut [u8]) -> (MemPtr, MemLength) {
38        (bytes.as_ptr() as MemPtr, bytes.len() as MemLength)
39    }
40
41    pub fn early_exit_panic(early_exit: VMHooksEarlyExit) -> ! {
42        std::panic::panic_any(early_exit)
43    }
44
45    pub fn breakpoint_panic(breakpoint_value: BreakpointValue) -> ! {
46        std::panic::panic_any(breakpoint_value)
47    }
48}
49
50impl InstanceState for ContractDebugInstanceState {
51    fn get_points_used(&mut self) -> Result<u64, ExecutorError> {
52        Ok(0)
53    }
54
55    fn set_points_used(&mut self, _points: u64) -> Result<(), ExecutorError> {
56        Ok(())
57    }
58
59    fn memory_load_to_slice(&self, mem_ptr: MemPtr, dest: &mut [u8]) -> Result<(), ExecutorError> {
60        let data = unsafe { Self::main_memory_load(mem_ptr, dest.len() as MemLength) };
61        dest.copy_from_slice(data);
62        Ok(())
63    }
64
65    fn memory_load_owned(
66        &self,
67        mem_ptr: MemPtr,
68        mem_length: MemLength,
69    ) -> Result<Vec<u8>, ExecutorError> {
70        let data = unsafe { Self::main_memory_load(mem_ptr, mem_length) };
71        Ok(data.to_vec())
72    }
73
74    fn memory_store(&self, mem_ptr: MemPtr, data: &[u8]) -> Result<(), ExecutorError> {
75        unsafe {
76            Self::main_memory_store(mem_ptr, data);
77        }
78        Ok(())
79    }
80}
81
82#[cfg(test)]
83#[allow(deprecated)]
84mod test {
85    use super::*;
86
87    #[test]
88    fn test_mem_ptr_conversion() {
89        assert_mem_load_sound(vec![]);
90        assert_mem_load_sound(vec![1]);
91        assert_mem_load_sound(vec![1, 2, 3]);
92
93        assert_mem_store_sound(vec![]);
94        assert_mem_store_sound(vec![1]);
95        assert_mem_store_sound(vec![1, 2, 3]);
96    }
97
98    fn assert_mem_load_sound(data: Vec<u8>) {
99        let (offset, length) = ContractDebugInstanceState::main_memory_ptr(&data);
100        let re_slice = unsafe { ContractDebugInstanceState::main_memory_load(offset, length) };
101        let cloned = re_slice.to_vec();
102        assert_eq!(data, cloned);
103    }
104
105    fn assert_mem_store_sound(mut data: Vec<u8>) {
106        let new_data: Vec<u8> = data.iter().map(|x| x * 2).collect();
107        let (offset, length) = ContractDebugInstanceState::main_memory_mut_ptr(&mut data);
108        assert_eq!(length, data.len() as isize);
109        unsafe {
110            ContractDebugInstanceState::main_memory_store(offset, &new_data);
111        }
112        assert_eq!(data, new_data);
113    }
114}