multiversx_chain_vm/host/context/managed_type_container/
tx_managed_buffer.rs1use crate::{
2 host::context::{TxFunctionName, TxTokenTransfer},
3 types::{RawHandle, VMAddress, VMCodeMetadata},
4};
5
6use super::ManagedTypeContainer;
7
8pub 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 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 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}