Skip to main content

multiversx_sc/hex_call_data/
cd_de.rs

1use super::SEPARATOR;
2use crate::{
3    codec::{DecodeError, DecodeErrorHandler, TopDecodeMultiInput},
4    err_msg,
5    formatter::hex_util::hex_digits_to_byte,
6};
7use alloc::{boxed::Box, vec::Vec};
8
9/// Deserializes from the MultiversX smart contract call format.
10///
11/// This format consists of the function name, followed by '@', followed by hex-encoded argument bytes separated by '@' characters.
12/// Example: "funcName@00000@aaaa@1234@@".
13/// Arguments can be empty.
14/// Argument hex encodings must always have an even number of digits.
15///
16/// HexCallDataDeserializer borrows its input and will allocate new Vecs for each output.
17///
18/// Converting from bytes to specific argument types is not in scope. The `TopDecodeMulti` trait deals with that.
19///
20/// Currently not used anywhere in the framework, but the functionality is available for anyone who needs it.
21///
22pub struct HexCallDataDeserializer<'a> {
23    source: &'a [u8],
24    index: usize,
25    func_name_output: &'a [u8],
26}
27
28impl<'a> HexCallDataDeserializer<'a> {
29    pub fn new(source: &'a [u8]) -> Self {
30        let mut de = HexCallDataDeserializer {
31            source,
32            index: 0,
33            func_name_output: &[],
34        };
35
36        // extract func name and advance index, before any argument can be retrieved
37        if let Some(func_name) = de.next_argument_hex() {
38            de.func_name_output = func_name
39        }
40
41        de
42    }
43
44    /// Gets the first component of the call data, which is the function name.
45    /// Unlike the arguments, this can be called at any time.
46    #[inline]
47    pub fn get_func_name(&self) -> &'a [u8] {
48        self.func_name_output
49    }
50
51    fn next_argument_hex(&mut self) -> Option<&'a [u8]> {
52        let initial_index = self.index;
53        loop {
54            if !self.has_next() {
55                return None;
56            }
57
58            if self.index == self.source.len() {
59                let slice = &self.source[initial_index..self.index];
60                self.index += 1; // make index = len + 1 to signal that we are done, and return None from the next call on
61                return Some(slice);
62            }
63
64            let c = self.source[self.index];
65            if c == SEPARATOR {
66                let slice = &self.source[initial_index..self.index];
67                self.index += 1;
68                return Some(slice);
69            }
70
71            self.index += 1;
72        }
73    }
74
75    #[inline]
76    pub fn has_next(&self) -> bool {
77        self.index <= self.source.len()
78    }
79
80    /// Gets the next argument, deserializes from hex and returns the resulting bytes.
81    pub fn next_argument(&mut self) -> Result<Option<Vec<u8>>, &'static str> {
82        match self.next_argument_hex() {
83            None => Ok(None),
84            Some(arg_hex) => {
85                if arg_hex.len() % 2 != 0 {
86                    return Err(err_msg::DESERIALIZATION_ODD_DIGITS);
87                }
88                let res_len = arg_hex.len() / 2;
89                let mut res_vec = Vec::with_capacity(res_len);
90                for i in 0..res_len {
91                    match hex_digits_to_byte(arg_hex[2 * i], arg_hex[2 * i + 1]) {
92                        None => {
93                            return Err(err_msg::DESERIALIZATION_INVALID_BYTE);
94                        }
95                        Some(byte) => {
96                            res_vec.push(byte);
97                        }
98                    }
99                }
100                Ok(Some(res_vec))
101            }
102        }
103    }
104}
105
106impl TopDecodeMultiInput for HexCallDataDeserializer<'_> {
107    type ValueInput = Box<[u8]>;
108
109    fn has_next(&self) -> bool {
110        self.has_next()
111    }
112
113    fn next_value_input<H>(&mut self, h: H) -> Result<Self::ValueInput, H::HandledErr>
114    where
115        H: DecodeErrorHandler,
116    {
117        match self.next_argument() {
118            Ok(Some(arg_bytes)) => Ok(arg_bytes.into_boxed_slice()),
119            Ok(None) => Err(h.handle_error(DecodeError::MULTI_TOO_FEW_ARGS)),
120            Err(sc_err) => Err(h.handle_error(DecodeError::from(sc_err))),
121        }
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    use super::*;
128
129    #[test]
130    fn test_next_raw_bytes_1() {
131        let input: &[u8] = b"func@1111@2222";
132        let mut de = HexCallDataDeserializer::new(input);
133        assert_eq!(de.get_func_name(), &b"func"[..]);
134        assert_eq!(de.next_argument_hex(), Some(&b"1111"[..]));
135        assert_eq!(de.next_argument(), Ok(Some([0x22, 0x22].to_vec())));
136        assert_eq!(de.next_argument(), Ok(None));
137        assert_eq!(de.next_argument(), Ok(None));
138    }
139
140    #[test]
141    fn test_next_raw_bytes_empty() {
142        let mut de = HexCallDataDeserializer::new(&[]);
143        assert_eq!(de.get_func_name(), &[][..]);
144        assert_eq!(de.next_argument(), Ok(None));
145    }
146
147    #[test]
148    fn test_next_raw_bytes_only_func() {
149        let input: &[u8] = b"func";
150        let mut de = HexCallDataDeserializer::new(input);
151
152        assert_eq!(de.get_func_name(), &b"func"[..]);
153        assert_eq!(de.next_argument(), Ok(None));
154        assert_eq!(de.next_argument(), Ok(None));
155    }
156
157    #[test]
158    fn test_next_raw_bytes_some_empty() {
159        let input: &[u8] = b"func@@2222";
160        let mut de = HexCallDataDeserializer::new(input);
161        assert_eq!(de.next_argument(), Ok(Some(Vec::new())));
162        assert_eq!(de.next_argument(), Ok(Some([0x22, 0x22].to_vec())));
163        assert_eq!(de.next_argument(), Ok(None));
164        assert_eq!(de.next_argument(), Ok(None));
165
166        assert_eq!(de.get_func_name(), &b"func"[..]);
167    }
168
169    #[test]
170    fn test_next_raw_bytes_ends_empty() {
171        let input: &[u8] = b"func@";
172        let mut de = HexCallDataDeserializer::new(input);
173        assert_eq!(de.get_func_name(), &b"func"[..]);
174        assert_eq!(de.next_argument(), Ok(Some(Vec::new())));
175        assert_eq!(de.next_argument(), Ok(None));
176        assert_eq!(de.next_argument(), Ok(None));
177    }
178
179    #[test]
180    fn test_next_raw_bytes_many_empty() {
181        let input: &[u8] = b"func@@2222@@";
182        let mut de = HexCallDataDeserializer::new(input);
183        assert_eq!(de.get_func_name(), &b"func"[..]);
184        assert_eq!(de.next_argument(), Ok(Some(Vec::new())));
185        assert_eq!(de.next_argument(), Ok(Some([0x22, 0x22].to_vec())));
186        assert_eq!(de.next_argument(), Ok(Some(Vec::new())));
187        assert_eq!(de.next_argument(), Ok(Some(Vec::new())));
188        assert_eq!(de.next_argument(), Ok(None));
189        assert_eq!(de.next_argument(), Ok(None));
190    }
191
192    #[test]
193    fn test_next_raw_bytes_all_empty() {
194        let input: &[u8] = b"@@@";
195        let mut de = HexCallDataDeserializer::new(input);
196        assert_eq!(de.get_func_name(), &[][..]);
197        assert_eq!(de.next_argument(), Ok(Some(Vec::new())));
198        assert_eq!(de.next_argument(), Ok(Some(Vec::new())));
199        assert_eq!(de.next_argument(), Ok(Some(Vec::new())));
200        assert_eq!(de.next_argument(), Ok(None));
201        assert_eq!(de.next_argument(), Ok(None));
202    }
203
204    #[test]
205    fn test_next_raw_bytes_all_empty_but_last() {
206        let input: &[u8] = b"@@@1234";
207        let mut de = HexCallDataDeserializer::new(input);
208        assert_eq!(de.get_func_name(), &[][..]);
209        assert_eq!(de.next_argument(), Ok(Some(Vec::new())));
210        assert_eq!(de.next_argument(), Ok(Some(Vec::new())));
211        assert_eq!(de.next_argument(), Ok(Some([0x12, 0x34].to_vec())));
212        assert_eq!(de.next_argument(), Ok(None));
213        assert_eq!(de.next_argument(), Ok(None));
214    }
215
216    #[test]
217    fn test_next_argument_large() {
218        let input: &[u8] = b"func@0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
219        let mut de = HexCallDataDeserializer::new(input);
220        let expected: [u8; 32] = [
221            0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab,
222            0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67,
223            0x89, 0xab, 0xcd, 0xef,
224        ];
225        assert_eq!(de.get_func_name(), &b"func"[..]);
226        assert!(de.next_argument() == Ok(Some(expected.to_vec())));
227        assert_eq!(de.next_argument(), Ok(None));
228        assert_eq!(de.next_argument(), Ok(None));
229    }
230
231    #[test]
232    fn test_next_vec_odd() {
233        let input: &[u8] = b"func@123";
234        let mut de = HexCallDataDeserializer::new(input);
235        assert_eq!(de.get_func_name(), &b"func"[..]);
236        assert_eq!(de.next_argument(), Err(err_msg::DESERIALIZATION_ODD_DIGITS));
237        assert_eq!(de.next_argument(), Ok(None));
238        assert_eq!(de.next_argument(), Ok(None));
239    }
240}