multiversx_chain_vm/host/context/managed_type_container/
tx_managed_buffer.rs

1use crate::{
2    host::context::{TxFunctionName, TxTokenTransfer},
3    types::{RawHandle, VMAddress, VMCodeMetadata},
4};
5
6use super::ManagedTypeContainer;
7
8/// Returned if load/copy slice could not be performed.
9/// No further data needed.
10pub struct InvalidSliceError;
11
12impl ManagedTypeContainer {
13    pub fn mb_get_owned(&self, handle: RawHandle) -> Vec<u8> {
14        self.managed_buffer_map.get(handle).to_vec()
15    }
16
17    pub fn mb_get(&self, handle: RawHandle) -> &[u8] {
18        self.managed_buffer_map.get(handle).as_slice()
19    }
20
21    pub fn mb_len(&self, handle: RawHandle) -> usize {
22        self.managed_buffer_map.get(handle).len()
23    }
24
25    pub fn mb_to_bytes(&self, handle: RawHandle) -> Vec<u8> {
26        self.mb_get(handle).to_vec()
27    }
28
29    pub fn mb_to_address(&self, handle: RawHandle) -> VMAddress {
30        VMAddress::from_slice(self.mb_get(handle))
31    }
32
33    pub fn mb_to_function_name(&self, handle: RawHandle) -> TxFunctionName {
34        TxFunctionName::from(self.mb_get(handle))
35    }
36
37    pub fn mb_to_code_metadata(&self, handle: RawHandle) -> VMCodeMetadata {
38        let bytes: [u8; 2] = self.mb_get(handle).try_into().unwrap();
39        VMCodeMetadata::from(bytes)
40    }
41
42    pub fn mb_get_slice(
43        &self,
44        source_handle: RawHandle,
45        starting_position: usize,
46        slice_len: usize,
47    ) -> Result<Vec<u8>, InvalidSliceError> {
48        let all_bytes = self.mb_get(source_handle);
49        if starting_position + slice_len <= all_bytes.len() {
50            let slice = &all_bytes[starting_position..starting_position + slice_len];
51            Ok(slice.to_vec())
52        } else {
53            Err(InvalidSliceError)
54        }
55    }
56
57    pub fn mb_set(&mut self, handle: RawHandle, value: Vec<u8>) {
58        self.managed_buffer_map.insert(handle, value);
59    }
60
61    pub fn mb_new(&mut self, value: Vec<u8>) -> RawHandle {
62        self.managed_buffer_map.insert_new_handle_raw(value)
63    }
64
65    pub fn mb_update<R, F: FnOnce(&mut Vec<u8>) -> R>(&mut self, handle: RawHandle, f: F) -> R {
66        let value = self.managed_buffer_map.get_mut(handle);
67        f(value)
68    }
69
70    pub fn mb_set_slice(
71        &mut self,
72        dest_handle: RawHandle,
73        starting_position: usize,
74        source_slice: &[u8],
75    ) -> Result<(), InvalidSliceError> {
76        self.mb_update(dest_handle, |bytes| {
77            let end_position = starting_position + source_slice.len();
78            if end_position <= bytes.len() {
79                bytes[starting_position..end_position].copy_from_slice(source_slice);
80                Ok(())
81            } else {
82                Err(InvalidSliceError)
83            }
84        })
85    }
86
87    pub fn mb_append_bytes(&mut self, accumulator_handle: RawHandle, bytes: &[u8]) {
88        self.mb_update(accumulator_handle, |accumulator| {
89            accumulator.extend_from_slice(bytes);
90        });
91    }
92
93    /// Retrieves data saved in the format of a ManagedVec<ManagedBuffer>,
94    /// i.e. the main data structure encodes the handles of other buffers.
95    pub fn mb_get_vec_of_bytes(&self, source_handle: RawHandle) -> (Vec<Vec<u8>>, usize) {
96        let mut result = Vec::new();
97        let mut num_bytes_copied = 0;
98        let data = self.mb_get(source_handle);
99        assert!(
100            data.len() % 4 == 0,
101            "malformed ManagedVec<ManagedBuffer> data"
102        );
103        for chunk in data.chunks(4) {
104            let item_handle = i32::from_be_bytes(chunk.try_into().unwrap());
105            let data = self.mb_get(item_handle).to_vec();
106            num_bytes_copied += data.len();
107            result.push(data);
108        }
109        (result, num_bytes_copied)
110    }
111
112    /// Creates the underlying structure of a ManagedVec<ManagedBuffer> from memory..
113    pub fn mb_set_vec_of_bytes(
114        &mut self,
115        destination_handle: RawHandle,
116        data: Vec<Vec<u8>>,
117    ) -> usize {
118        let mut m_vec_raw_data = Vec::new();
119        let mut num_bytes_copied = 0;
120        for item in data.into_iter() {
121            num_bytes_copied += item.len();
122            let handle = self.managed_buffer_map.insert_new_handle_raw(item);
123            m_vec_raw_data.extend_from_slice(handle.to_be_bytes().as_slice());
124        }
125        self.mb_set(destination_handle, m_vec_raw_data);
126        num_bytes_copied
127    }
128
129    pub fn mb_get_vec_of_esdt_payments(
130        &self,
131        source_handle: RawHandle,
132    ) -> (Vec<TxTokenTransfer>, usize) {
133        let mut result = Vec::new();
134        let mut num_bytes_copied = 0;
135        let data = self.mb_get(source_handle);
136        assert!(
137            data.len() % 16 == 0,
138            "malformed ManagedVec<EsdtTokenPayment> data"
139        );
140        for chunk in data.chunks(16) {
141            let token_id_handle = i32::from_be_bytes(chunk[0..4].try_into().unwrap());
142            let token_id = self.mb_get(token_id_handle).to_vec();
143            num_bytes_copied += token_id.len();
144
145            let nonce = u64::from_be_bytes(chunk[4..12].try_into().unwrap());
146
147            let amount_handle = i32::from_be_bytes(chunk[12..16].try_into().unwrap());
148            let amount = self.bu_get(amount_handle);
149            num_bytes_copied += (amount.bits() / 8) as usize;
150
151            result.push(TxTokenTransfer {
152                token_identifier: token_id,
153                nonce,
154                value: amount,
155            });
156        }
157        (result, num_bytes_copied)
158    }
159
160    pub fn mb_set_vec_of_esdt_payments(
161        &mut self,
162        dest_handle: RawHandle,
163        transfers: &[TxTokenTransfer],
164    ) -> usize {
165        let mut num_bytes_copied = 0;
166
167        self.mb_set(dest_handle, vec![]);
168
169        for transfer in transfers {
170            num_bytes_copied += transfer.token_identifier.len();
171            let token_identifier_handle = self.mb_new(transfer.token_identifier.clone());
172
173            num_bytes_copied += (transfer.value.bits() / 8) as usize;
174            let amount_handle = self.bi_new_from_big_int(transfer.value.clone().into());
175
176            self.mb_append_bytes(
177                dest_handle,
178                &handle_to_be_bytes(token_identifier_handle)[..],
179            );
180            self.mb_append_bytes(dest_handle, &transfer.nonce.to_be_bytes()[..]);
181            self.mb_append_bytes(dest_handle, &handle_to_be_bytes(amount_handle)[..]);
182        }
183
184        num_bytes_copied
185    }
186}
187
188pub fn handle_to_be_bytes(handle: RawHandle) -> [u8; 4] {
189    handle.to_be_bytes()
190}
191
192#[cfg(test)]
193pub mod tests {
194    use super::*;
195
196    #[test]
197    fn test_vec_of_bytes() {
198        let mut m_types = ManagedTypeContainer::new();
199        let handle = m_types.mb_new(vec![]);
200        let data = vec![b"abc".to_vec(), b"defghi".to_vec(), b"jk".to_vec()];
201        let _ = m_types.mb_set_vec_of_bytes(handle, data.clone());
202        let (retrieved, _) = m_types.mb_get_vec_of_bytes(handle);
203        assert_eq!(data, retrieved);
204    }
205
206    #[test]
207    fn test_vec_of_esdt_payments() {
208        let mut m_types = ManagedTypeContainer::new();
209        let handle = m_types.mb_new(vec![]);
210        let transfers = vec![TxTokenTransfer {
211            token_identifier: b"TOKEN-12345".to_vec(),
212            nonce: 6,
213            value: 789u32.into(),
214        }];
215        let _ = m_types.mb_set_vec_of_esdt_payments(handle, transfers.as_slice());
216        let (retrieved, _) = m_types.mb_get_vec_of_esdt_payments(handle);
217        assert_eq!(transfers, retrieved);
218    }
219}