cw_utils/
parse_reply.rs

1use thiserror::Error;
2
3use cosmwasm_std::Binary;
4
5// Protobuf wire types (https://developers.google.com/protocol-buffers/docs/encoding)
6const WIRE_TYPE_LENGTH_DELIMITED: u8 = 2;
7// Up to 9 bytes of varints as a practical limit (https://github.com/multiformats/unsigned-varint#practical-maximum-of-9-bytes-for-security)
8const VARINT_MAX_BYTES: usize = 9;
9
10#[derive(Clone, Debug, PartialEq, Eq)]
11pub struct MsgInstantiateContractResponse {
12    pub contract_address: String,
13    pub data: Option<Binary>,
14}
15
16#[derive(Clone, Debug, PartialEq, Eq)]
17pub struct MsgExecuteContractResponse {
18    pub data: Option<Binary>,
19}
20
21/// Base128 varint decoding.
22/// The remaining of the data is kept in the data parameter.
23fn parse_protobuf_varint(data: &mut Vec<u8>, field_number: u8) -> Result<usize, ParseReplyError> {
24    let data_len = data.len();
25    let mut len: u64 = 0;
26    let mut i = 0;
27    while i < VARINT_MAX_BYTES {
28        if data_len == i {
29            return Err(ParseReplyError::ParseFailure(format!(
30                "failed to decode Protobuf message: field #{}: varint data too short",
31                field_number
32            )));
33        }
34        len += ((data[i] & 0x7f) as u64) << (i * 7);
35        if data[i] & 0x80 == 0 {
36            break;
37        }
38        i += 1;
39    }
40    if i == VARINT_MAX_BYTES {
41        return Err(ParseReplyError::ParseFailure(format!(
42            "failed to decode Protobuf message: field #{}: varint data too long",
43            field_number
44        )));
45    }
46    let _ = data.drain(..=i);
47
48    Ok(len as usize) // Gently fall back to the arch's max addressable size
49}
50
51/// Helper function to parse length-prefixed protobuf fields.
52/// The remaining of the data is kept in the data parameter.
53fn parse_protobuf_length_prefixed(
54    data: &mut Vec<u8>,
55    field_number: u8,
56) -> Result<Vec<u8>, ParseReplyError> {
57    if data.is_empty() {
58        return Ok(vec![]);
59    };
60    let mut rest_1 = data.split_off(1);
61    let wire_type = data[0] & 0b11;
62    let field = data[0] >> 3;
63
64    if field != field_number {
65        return Err(ParseReplyError::ParseFailure(format!(
66            "failed to decode Protobuf message: invalid field #{} for field #{}",
67            field, field_number
68        )));
69    }
70    if wire_type != WIRE_TYPE_LENGTH_DELIMITED {
71        return Err(ParseReplyError::ParseFailure(format!(
72            "failed to decode Protobuf message: field #{}: invalid wire type {}",
73            field_number, wire_type
74        )));
75    }
76
77    let len = parse_protobuf_varint(&mut rest_1, field_number)?;
78    if rest_1.len() < len {
79        return Err(ParseReplyError::ParseFailure(format!(
80            "failed to decode Protobuf message: field #{}: message too short",
81            field_number
82        )));
83    }
84    *data = rest_1.split_off(len);
85
86    Ok(rest_1)
87}
88
89fn parse_protobuf_string(data: &mut Vec<u8>, field_number: u8) -> Result<String, ParseReplyError> {
90    let str_field = parse_protobuf_length_prefixed(data, field_number)?;
91    Ok(String::from_utf8(str_field)?)
92}
93
94fn parse_protobuf_bytes(
95    data: &mut Vec<u8>,
96    field_number: u8,
97) -> Result<Option<Binary>, ParseReplyError> {
98    let bytes_field = parse_protobuf_length_prefixed(data, field_number)?;
99    if bytes_field.is_empty() {
100        Ok(None)
101    } else {
102        Ok(Some(Binary::new(bytes_field)))
103    }
104}
105
106pub fn parse_instantiate_response_data(
107    data: &[u8],
108) -> Result<MsgInstantiateContractResponse, ParseReplyError> {
109    // Manual protobuf decoding
110    let mut data = data.to_vec();
111    // Parse contract addr
112    let contract_addr = parse_protobuf_string(&mut data, 1)?;
113
114    // Parse (optional) data
115    let data = parse_protobuf_bytes(&mut data, 2)?;
116
117    Ok(MsgInstantiateContractResponse {
118        contract_address: contract_addr,
119        data,
120    })
121}
122
123pub fn parse_execute_response_data(
124    data: &[u8],
125) -> Result<MsgExecuteContractResponse, ParseReplyError> {
126    // Manual protobuf decoding
127    let mut data = data.to_vec();
128    let inner_data = parse_protobuf_bytes(&mut data, 1)?;
129
130    Ok(MsgExecuteContractResponse { data: inner_data })
131}
132
133#[derive(Error, Debug, PartialEq, Eq)]
134pub enum ParseReplyError {
135    #[error("Failure response from sub-message: {0}")]
136    SubMsgFailure(String),
137
138    #[error("Invalid reply from sub-message: {0}")]
139    ParseFailure(String),
140
141    #[error("Error occurred while converting from UTF-8")]
142    BrokenUtf8(#[from] std::string::FromUtf8Error),
143}
144
145#[cfg(test)]
146mod test {
147    use super::*;
148    use crate::parse_reply::ParseReplyError::{BrokenUtf8, ParseFailure};
149    use prost::Message;
150    use std::str::from_utf8;
151
152    fn encode_bytes(data: &[u8]) -> Vec<u8> {
153        #[derive(Clone, PartialEq, Message)]
154        struct ProtobufBytes {
155            #[prost(bytes, tag = "1")]
156            pub data: Vec<u8>,
157        }
158
159        let data = ProtobufBytes {
160            data: data.to_vec(),
161        };
162        let mut encoded_data = Vec::<u8>::with_capacity(data.encoded_len());
163        data.encode(&mut encoded_data).unwrap();
164
165        encoded_data
166    }
167
168    fn encode_string(data: &str) -> Vec<u8> {
169        #[derive(Clone, PartialEq, Message)]
170        struct ProtobufString {
171            #[prost(string, tag = "1")]
172            pub data: String,
173        }
174
175        let data = ProtobufString {
176            data: data.to_string(),
177        };
178        let mut encoded_data = Vec::<u8>::with_capacity(data.encoded_len());
179        data.encode(&mut encoded_data).unwrap();
180
181        encoded_data
182    }
183
184    #[derive(Clone, PartialEq, Message)]
185    struct MsgInstantiateContractResponse {
186        #[prost(string, tag = "1")]
187        pub contract_address: ::prost::alloc::string::String,
188        #[prost(bytes, tag = "2")]
189        pub data: ::prost::alloc::vec::Vec<u8>,
190    }
191
192    #[derive(Clone, PartialEq, Message)]
193    struct MsgExecuteContractResponse {
194        #[prost(bytes, tag = "1")]
195        pub data: ::prost::alloc::vec::Vec<u8>,
196    }
197
198    #[test]
199    fn parse_protobuf_varint_tests() {
200        let field_number = 1;
201        // Single-byte varint works
202        let mut data = b"\x0a".to_vec();
203        let len = parse_protobuf_varint(&mut data, field_number).unwrap();
204        assert_eq!(len, 10);
205
206        // Rest is returned
207        let mut data = b"\x0a\x0b".to_vec();
208        let len = parse_protobuf_varint(&mut data, field_number).unwrap();
209        assert_eq!(len, 10);
210        assert_eq!(data, b"\x0b".to_vec());
211
212        // Multi-byte varint works
213        // 300 % 128 = 44. 44 + 128 = 172 (0xac) (1st byte)
214        // 300 / 128 = 2 (x02) (2nd byte)
215        let mut data = b"\xac\x02".to_vec();
216        let len = parse_protobuf_varint(&mut data, field_number).unwrap();
217        assert_eq!(len, 300);
218
219        // Rest is returned
220        let mut data = b"\xac\x02\x0c".to_vec();
221        let len = parse_protobuf_varint(&mut data, field_number).unwrap();
222        assert_eq!(len, 300);
223        assert_eq!(data, b"\x0c".to_vec());
224
225        // varint data too short (Empty varint)
226        let mut data = vec![];
227        let err = parse_protobuf_varint(&mut data, field_number).unwrap_err();
228        assert!(matches!(err, ParseFailure(..)));
229
230        // varint data too short (Incomplete varint)
231        let mut data = b"\x80".to_vec();
232        let err = parse_protobuf_varint(&mut data, field_number).unwrap_err();
233        assert!(matches!(err, ParseFailure(..)));
234
235        // varint data too long
236        let mut data = b"\x80\x81\x82\x83\x84\x83\x82\x81\x80".to_vec();
237        let err = parse_protobuf_varint(&mut data, field_number).unwrap_err();
238        assert!(matches!(err, ParseFailure(..)));
239    }
240
241    #[test]
242    fn parse_protobuf_length_prefixed_tests() {
243        let field_number = 1;
244        // Single-byte length-prefixed works
245        let mut data = b"\x0a\x03abc".to_vec();
246        let res = parse_protobuf_length_prefixed(&mut data, field_number).unwrap();
247        assert_eq!(res, b"abc".to_vec());
248        assert_eq!(data, vec![0u8; 0]);
249
250        // Rest is returned
251        let mut data = b"\x0a\x03abcd".to_vec();
252        let res = parse_protobuf_length_prefixed(&mut data, field_number).unwrap();
253        assert_eq!(res, b"abc".to_vec());
254        assert_eq!(data, b"d".to_vec());
255
256        // Multi-byte length-prefixed works
257        let mut data = [b"\x0a\xac\x02", vec![65u8; 300].as_slice()]
258            .concat()
259            .to_vec();
260        let res = parse_protobuf_length_prefixed(&mut data, field_number).unwrap();
261        assert_eq!(res, vec![65u8; 300]);
262        assert_eq!(data, vec![0u8; 0]);
263
264        // Rest is returned
265        let mut data = [b"\x0a\xac\x02", vec![65u8; 300].as_slice(), b"rest"]
266            .concat()
267            .to_vec();
268        let res = parse_protobuf_length_prefixed(&mut data, field_number).unwrap();
269        assert_eq!(res, vec![65u8; 300]);
270        assert_eq!(data, b"rest");
271
272        // message too short
273        let mut data = b"\x0a\x01".to_vec();
274        let field_number = 1;
275        let err = parse_protobuf_length_prefixed(&mut data, field_number).unwrap_err();
276        assert!(matches!(err, ParseFailure(..)));
277
278        // invalid wire type
279        let mut data = b"\x0b\x01a".to_vec();
280        let err = parse_protobuf_length_prefixed(&mut data, field_number).unwrap_err();
281        assert!(matches!(err, ParseFailure(..)));
282
283        // invalid field number
284        let field_number = 2;
285        let mut data = b"\x0a\x01a".to_vec();
286        let err = parse_protobuf_length_prefixed(&mut data, field_number).unwrap_err();
287        assert!(matches!(err, ParseFailure(..)));
288    }
289
290    #[test]
291    fn parse_protobuf_bytes_works() {
292        let field_number = 1;
293
294        // Empty works
295        let data = vec![];
296        let mut encoded_data = encode_bytes(&data);
297
298        let res = parse_protobuf_bytes(&mut encoded_data, field_number).unwrap();
299        assert_eq!(res, None);
300
301        // Simple works
302        let data = b"test".to_vec();
303        let mut encoded_data = encode_bytes(&data);
304
305        let res = parse_protobuf_bytes(&mut encoded_data, field_number).unwrap();
306        assert_eq!(res, Some(Binary::new(data)));
307
308        // Large works
309        let data = vec![0x40; 300];
310        let mut encoded_data = encode_bytes(&data);
311
312        let res = parse_protobuf_bytes(&mut encoded_data, field_number).unwrap();
313        assert_eq!(res, Some(Binary::new(data)));
314
315        // Field number works
316        let field_number = 5;
317        let data = b"test field 5".to_vec();
318        let mut encoded_data = encode_bytes(&data);
319        encoded_data[0] = (field_number << 3) + WIRE_TYPE_LENGTH_DELIMITED;
320
321        let res = parse_protobuf_bytes(&mut encoded_data, field_number).unwrap();
322        assert_eq!(res, Some(Binary::new(data)));
323
324        // Remainder is kept
325        let field_number = 1;
326        let test_len: usize = 4;
327        let data = b"test_remainder".to_vec();
328        let mut encoded_data = encode_bytes(&data);
329        encoded_data[1] = test_len as u8;
330
331        let res = parse_protobuf_bytes(&mut encoded_data, field_number).unwrap();
332        assert_eq!(res, Some(Binary::new(data[..test_len].to_owned())));
333        assert_eq!(encoded_data, data[test_len..].to_owned());
334    }
335
336    #[test]
337    fn parse_protobuf_string_tests() {
338        let field_number = 1;
339
340        // Empty works
341        let data = "";
342        let mut encoded_data = encode_string(data);
343
344        let res = parse_protobuf_string(&mut encoded_data, field_number).unwrap();
345        assert_eq!(res, data);
346
347        // Simple works
348        let data = "test";
349        let mut encoded_data = encode_string(data);
350
351        let res = parse_protobuf_string(&mut encoded_data, field_number).unwrap();
352        assert_eq!(res, data);
353
354        // Large works
355        let data = vec![0x40; 300];
356        let str_data = from_utf8(data.as_slice()).unwrap();
357        let mut encoded_data = encode_string(str_data);
358
359        let res = parse_protobuf_string(&mut encoded_data, field_number).unwrap();
360        assert_eq!(res, str_data);
361
362        // Field number works
363        let field_number = 5;
364        let data = "test field 5";
365        let mut encoded_data = encode_string(data);
366        encoded_data[0] = (field_number << 3) + WIRE_TYPE_LENGTH_DELIMITED;
367
368        let res = parse_protobuf_string(&mut encoded_data, field_number).unwrap();
369        assert_eq!(res, data);
370
371        // Remainder is kept
372        let field_number = 1;
373        let test_len: usize = 4;
374        let data = "test_remainder";
375        let mut encoded_data = encode_string(data);
376        encoded_data[1] = test_len as u8;
377
378        let res = parse_protobuf_string(&mut encoded_data, field_number).unwrap();
379        assert_eq!(res, data[..test_len]);
380        assert_eq!(encoded_data, &data.as_bytes()[test_len..]);
381
382        // Broken utf-8 errs
383        let field_number = 1;
384        let data = "test_X";
385        let mut encoded_data = encode_string(data);
386        let encoded_len = encoded_data.len();
387        encoded_data[encoded_len - 1] = 0xd3;
388        let err = parse_protobuf_string(&mut encoded_data, field_number).unwrap_err();
389        assert!(matches!(err, BrokenUtf8(..)));
390    }
391
392    #[test]
393    fn parse_instantiate_response_data_works() {
394        let contract_addr: &str = "Contract #1";
395        for (data, expected) in [
396            (
397                vec![],
398                super::MsgInstantiateContractResponse {
399                    contract_address: contract_addr.to_string(),
400                    data: None,
401                },
402            ),
403            (
404                vec![1u8, 2, 255, 7, 5],
405                super::MsgInstantiateContractResponse {
406                    contract_address: contract_addr.to_string(),
407                    data: Some(Binary::new(vec![1u8, 2, 255, 7, 5])),
408                },
409            ),
410            (
411                vec![1u8; 127],
412                super::MsgInstantiateContractResponse {
413                    contract_address: contract_addr.to_string(),
414                    data: Some(Binary::new(vec![1u8; 127])),
415                },
416            ),
417            (
418                vec![2u8; 128],
419                super::MsgInstantiateContractResponse {
420                    contract_address: contract_addr.to_string(),
421                    data: Some(Binary::new(vec![2u8; 128])),
422                },
423            ),
424            (
425                vec![3u8; 257],
426                super::MsgInstantiateContractResponse {
427                    contract_address: contract_addr.to_string(),
428                    data: Some(Binary::new(vec![3u8; 257])),
429                },
430            ),
431        ] {
432            let instantiate_reply = MsgInstantiateContractResponse {
433                contract_address: contract_addr.to_string(),
434                data,
435            };
436            let mut encoded_instantiate_reply =
437                Vec::<u8>::with_capacity(instantiate_reply.encoded_len());
438            // The data must encode successfully
439            instantiate_reply
440                .encode(&mut encoded_instantiate_reply)
441                .unwrap();
442
443            let res = parse_instantiate_response_data(&encoded_instantiate_reply).unwrap();
444
445            assert_eq!(res, expected);
446        }
447    }
448
449    #[test]
450    fn parse_execute_response_data_works() {
451        for (data, expected) in [
452            (vec![], super::MsgExecuteContractResponse { data: None }),
453            (
454                vec![1u8, 2, 3, 127, 15],
455                super::MsgExecuteContractResponse {
456                    data: Some(Binary::new(vec![1u8, 2, 3, 127, 15])),
457                },
458            ),
459            (
460                vec![0u8; 255],
461                super::MsgExecuteContractResponse {
462                    data: Some(Binary::new(vec![0u8; 255])),
463                },
464            ),
465            (
466                vec![1u8; 256],
467                super::MsgExecuteContractResponse {
468                    data: Some(Binary::new(vec![1u8; 256])),
469                },
470            ),
471            (
472                vec![2u8; 32769],
473                super::MsgExecuteContractResponse {
474                    data: Some(Binary::new(vec![2u8; 32769])),
475                },
476            ),
477        ] {
478            let execute_reply = MsgExecuteContractResponse { data };
479            let mut encoded_execute_reply = Vec::<u8>::with_capacity(execute_reply.encoded_len());
480            // The data must encode successfully
481            execute_reply.encode(&mut encoded_execute_reply).unwrap();
482
483            let res = parse_execute_response_data(&encoded_execute_reply).unwrap();
484
485            assert_eq!(res, expected);
486        }
487    }
488}