cosmwasm_vm/
sections.rs

1use crate::conversion::to_u32;
2use crate::{CommunicationError, VmResult};
3
4/// Decodes sections of data into multiple slices.
5///
6/// Each encoded section is suffixed by a section length, encoded as big endian uint32.
7///
8/// See also: [`encode_sections`].
9pub fn decode_sections(data: &[u8]) -> Result<Vec<&[u8]>, CommunicationError> {
10    let mut result: Vec<&[u8]> = vec![];
11    let mut remaining_len = data.len();
12    while remaining_len >= 4 {
13        let tail_len = u32::from_be_bytes([
14            data[remaining_len - 4],
15            data[remaining_len - 3],
16            data[remaining_len - 2],
17            data[remaining_len - 1],
18        ]) as usize;
19        let tail_len_idx = remaining_len - 4; // index of the first byte of the tail length
20        let section_start = tail_len_idx
21            .checked_sub(tail_len)
22            .ok_or_else(|| CommunicationError::invalid_section("section length overflow"))?;
23        result.push(&data[section_start..tail_len_idx]);
24        remaining_len = section_start;
25    }
26    if remaining_len > 0 {
27        return Err(CommunicationError::invalid_section(
28            "extra data outside of any section",
29        ));
30    }
31    result.reverse();
32    Ok(result)
33}
34
35/// Encodes multiple sections of data into one vector.
36///
37/// Each section is suffixed by a section length encoded as big endian uint32.
38/// Using suffixes instead of prefixes allows reading sections in reverse order,
39/// such that the first element does not need to be re-allocated if the contract's
40/// data structure supports truncation (such as a Rust vector).
41///
42/// The resulting data looks like this:
43///
44/// ```ignore
45/// section1 || section1_len || section2 || section2_len || section3 || section3_len || …
46/// ```
47#[allow(dead_code)]
48pub fn encode_sections(sections: &[Vec<u8>]) -> VmResult<Vec<u8>> {
49    let mut out_len: usize = sections.iter().map(|section| section.len()).sum();
50    out_len += 4 * sections.len();
51    let mut out_data = Vec::with_capacity(out_len);
52    for section in sections {
53        let section_len = to_u32(section.len())?.to_be_bytes();
54        out_data.extend(section);
55        out_data.extend_from_slice(&section_len);
56    }
57    debug_assert_eq!(out_data.len(), out_len);
58    debug_assert_eq!(out_data.capacity(), out_len);
59    Ok(out_data)
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn decode_sections_works_for_empty_sections() {
68        let dec = decode_sections(&[]).unwrap();
69        assert_eq!(dec.len(), 0);
70        let dec = decode_sections(b"\0\0\0\0").unwrap();
71        assert_eq!(dec, &[&[0u8; 0]]);
72        let dec = decode_sections(b"\0\0\0\0\0\0\0\0").unwrap();
73        assert_eq!(dec, &[&[0u8; 0]; 2]);
74        let dec = decode_sections(b"\0\0\0\0\0\0\0\0\0\0\0\0").unwrap();
75        assert_eq!(dec, &[&[0u8; 0]; 3]);
76    }
77
78    #[test]
79    fn decode_sections_works_for_one_element() {
80        let dec = decode_sections(b"\xAA\0\0\0\x01").unwrap();
81        assert_eq!(dec, &[vec![0xAA]]);
82        let dec = decode_sections(b"\xAA\xBB\0\0\0\x02").unwrap();
83        assert_eq!(dec, &[vec![0xAA, 0xBB]]);
84        let dec = decode_sections(b"\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\0\0\x01\x15").unwrap();
85        assert_eq!(dec, &[vec![0x9D; 277]]);
86    }
87
88    #[test]
89    fn decode_sections_works_for_two_elements() {
90        let data = b"\xAA\0\0\0\x01\xBB\xCC\0\0\0\x02".to_vec();
91        assert_eq!(
92            decode_sections(&data).unwrap(),
93            &[vec![0xAA], vec![0xBB, 0xCC]]
94        );
95        let data = b"\xDE\xEF\x62\0\0\0\x03\0\0\0\0".to_vec();
96        assert_eq!(
97            decode_sections(&data).unwrap(),
98            &[vec![0xDE, 0xEF, 0x62], vec![]]
99        );
100        let data = b"\0\0\0\0\xDE\xEF\x62\0\0\0\x03".to_vec();
101        assert_eq!(
102            decode_sections(&data).unwrap(),
103            &[vec![], vec![0xDE, 0xEF, 0x62]]
104        );
105        let data = b"\0\0\0\0\0\0\0\0".to_vec();
106        assert_eq!(decode_sections(&data).unwrap(), &[vec![0u8; 0], vec![]]);
107        let data = b"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\x13\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\0\0\x01\x15".to_vec();
108        assert_eq!(
109            decode_sections(&data).unwrap(),
110            &[vec![0xFF; 19], vec![0x9D; 277]]
111        );
112    }
113
114    #[test]
115    fn decode_sections_works_for_multiple_elements() {
116        let dec = decode_sections(b"\xAA\0\0\0\x01").unwrap();
117        assert_eq!(dec, &[vec![0xAA]]);
118        let dec = decode_sections(b"\xAA\0\0\0\x01\xDE\xDE\0\0\0\x02").unwrap();
119        assert_eq!(dec, &[vec![0xAA], vec![0xDE, 0xDE]]);
120        let dec = decode_sections(b"\xAA\0\0\0\x01\xDE\xDE\0\0\0\x02\0\0\0\0").unwrap();
121        assert_eq!(dec, &[vec![0xAA], vec![0xDE, 0xDE], vec![]]);
122        let dec = decode_sections(b"\xAA\0\0\0\x01\xDE\xDE\0\0\0\x02\0\0\0\0\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\x13").unwrap();
123        assert_eq!(dec, &[vec![0xAA], vec![0xDE, 0xDE], vec![], vec![0xFF; 19]]);
124    }
125
126    #[test]
127    fn decode_sections_fails_for_invalid_length() {
128        // section length too long
129        assert!(decode_sections(b"\xAA\0\0\0\x02").is_err());
130        // section length without section
131        assert!(decode_sections(b"\xAA\0\0\0\x01\xBB\x03\0\0\0\x03").is_err());
132    }
133
134    #[test]
135    fn decode_sections_fails_for_extra_bytes() {
136        // extra data after successful section
137        assert!(decode_sections(b"\x44\xAA\0\0\0\x01").is_err());
138        assert!(decode_sections(b"\x44\x44\xAA\0\0\0\x01").is_err());
139        assert!(decode_sections(b"\x44\x44\x44\xAA\0\0\0\x01").is_err());
140
141        // Insufficient length for even a first section (or extra data of 0 sections)
142        assert!(decode_sections(b"\x44").is_err());
143        assert!(decode_sections(b"\x44\x44").is_err());
144        assert!(decode_sections(b"\x44\x44\x44").is_err());
145    }
146
147    #[test]
148    fn encode_sections_works_for_empty_sections() {
149        let enc = encode_sections(&[]).unwrap();
150        assert_eq!(enc, b"" as &[u8]);
151        let enc = encode_sections(&[vec![]]).unwrap();
152        assert_eq!(enc, b"\0\0\0\0" as &[u8]);
153        let enc = encode_sections(&[vec![], vec![]]).unwrap();
154        assert_eq!(enc, b"\0\0\0\0\0\0\0\0" as &[u8]);
155        let enc = encode_sections(&[vec![], vec![], vec![]]).unwrap();
156        assert_eq!(enc, b"\0\0\0\0\0\0\0\0\0\0\0\0" as &[u8]);
157    }
158
159    #[test]
160    fn encode_sections_works_for_one_element() {
161        let enc = encode_sections(&[]).unwrap();
162        assert_eq!(enc, b"" as &[u8]);
163        let enc = encode_sections(&[vec![0xAA]]).unwrap();
164        assert_eq!(enc, b"\xAA\0\0\0\x01" as &[u8]);
165        let enc = encode_sections(&[vec![0xAA, 0xBB]]).unwrap();
166        assert_eq!(enc, b"\xAA\xBB\0\0\0\x02" as &[u8]);
167        let enc = encode_sections(&[vec![0x9D; 277]]).unwrap();
168        assert_eq!(enc, b"\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\0\0\x01\x15" as &[u8]);
169    }
170
171    #[test]
172    fn encode_sections_works_for_multiple_elements() {
173        let enc = encode_sections(&[vec![0xAA]]).unwrap();
174        assert_eq!(enc, b"\xAA\0\0\0\x01" as &[u8]);
175        let enc = encode_sections(&[vec![0xAA], vec![0xDE, 0xDE]]).unwrap();
176        assert_eq!(enc, b"\xAA\0\0\0\x01\xDE\xDE\0\0\0\x02" as &[u8]);
177        let enc = encode_sections(&[vec![0xAA], vec![0xDE, 0xDE], vec![]]).unwrap();
178        assert_eq!(enc, b"\xAA\0\0\0\x01\xDE\xDE\0\0\0\x02\0\0\0\0" as &[u8]);
179        let enc = encode_sections(&[vec![0xAA], vec![0xDE, 0xDE], vec![], vec![0xFF; 19]]).unwrap();
180        assert_eq!(enc, b"\xAA\0\0\0\x01\xDE\xDE\0\0\0\x02\0\0\0\0\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\x13" as &[u8]);
181    }
182}