1use thiserror::Error;
2
3use cosmwasm_std::{Binary, Reply};
4
5const WIRE_TYPE_LENGTH_DELIMITED: u8 = 2;
7const VARINT_MAX_BYTES: usize = 9;
9
10#[derive(Clone, Debug, PartialEq)]
11pub struct MsgInstantiateContractResponse {
12 pub contract_address: String,
13 pub data: Option<Binary>,
14}
15
16#[derive(Clone, Debug, PartialEq)]
17pub struct MsgExecuteContractResponse {
18 pub data: Option<Binary>,
19}
20
21fn 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 *data = data[i + 1..].to_owned();
47
48 Ok(len as usize) }
50
51fn 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(bytes_field)))
103 }
104}
105
106pub fn parse_reply_instantiate_data(
107 msg: Reply,
108) -> Result<MsgInstantiateContractResponse, ParseReplyError> {
109 let data = msg
110 .result
111 .into_result()
112 .map_err(ParseReplyError::SubMsgFailure)?
113 .data
114 .ok_or_else(|| ParseReplyError::ParseFailure("Missing reply data".to_owned()))?;
115 parse_instantiate_response_data(&data.0)
116}
117
118pub fn parse_reply_execute_data(msg: Reply) -> Result<MsgExecuteContractResponse, ParseReplyError> {
119 let data = msg
120 .result
121 .into_result()
122 .map_err(ParseReplyError::SubMsgFailure)?
123 .data
124 .ok_or_else(|| ParseReplyError::ParseFailure("Missing reply data".to_owned()))?;
125 parse_execute_response_data(&data.0)
126}
127
128pub fn parse_instantiate_response_data(
129 data: &[u8],
130) -> Result<MsgInstantiateContractResponse, ParseReplyError> {
131 let mut data = data.to_vec();
133 let contract_addr = parse_protobuf_string(&mut data, 1)?;
135
136 let data = parse_protobuf_bytes(&mut data, 2)?;
138
139 Ok(MsgInstantiateContractResponse {
140 contract_address: contract_addr,
141 data,
142 })
143}
144
145pub fn parse_execute_response_data(
146 data: &[u8],
147) -> Result<MsgExecuteContractResponse, ParseReplyError> {
148 let mut data = data.to_vec();
150 let inner_data = parse_protobuf_bytes(&mut data, 1)?;
151
152 Ok(MsgExecuteContractResponse { data: inner_data })
153}
154
155#[derive(Error, Debug, PartialEq)]
156pub enum ParseReplyError {
157 #[error("Failure response from sub-message: {0}")]
158 SubMsgFailure(String),
159
160 #[error("Invalid reply from sub-message: {0}")]
161 ParseFailure(String),
162
163 #[error("Error occurred while converting from UTF-8")]
164 BrokenUtf8(#[from] std::string::FromUtf8Error),
165}
166
167#[cfg(test)]
168mod test {
169 use super::*;
170 use crate::parse_reply::ParseReplyError::{BrokenUtf8, ParseFailure};
171 use cosmwasm_std::{ContractResult, SubMsgExecutionResponse};
172 use prost::Message;
173 use std::str::from_utf8;
174
175 fn encode_bytes(data: &[u8]) -> Vec<u8> {
176 #[derive(Clone, PartialEq, Message)]
177 struct ProtobufBytes {
178 #[prost(bytes, tag = "1")]
179 pub data: Vec<u8>,
180 }
181
182 let data = ProtobufBytes {
183 data: data.to_vec(),
184 };
185 let mut encoded_data = Vec::<u8>::with_capacity(data.encoded_len());
186 data.encode(&mut encoded_data).unwrap();
187
188 encoded_data
189 }
190
191 fn encode_string(data: &str) -> Vec<u8> {
192 #[derive(Clone, PartialEq, Message)]
193 struct ProtobufString {
194 #[prost(string, tag = "1")]
195 pub data: String,
196 }
197
198 let data = ProtobufString {
199 data: data.to_string(),
200 };
201 let mut encoded_data = Vec::<u8>::with_capacity(data.encoded_len());
202 data.encode(&mut encoded_data).unwrap();
203
204 encoded_data
205 }
206
207 #[derive(Clone, PartialEq, Message)]
208 struct MsgInstantiateContractResponse {
209 #[prost(string, tag = "1")]
210 pub contract_address: ::prost::alloc::string::String,
211 #[prost(bytes, tag = "2")]
212 pub data: ::prost::alloc::vec::Vec<u8>,
213 }
214
215 #[derive(Clone, PartialEq, Message)]
216 struct MsgExecuteContractResponse {
217 #[prost(bytes, tag = "1")]
218 pub data: ::prost::alloc::vec::Vec<u8>,
219 }
220
221 #[test]
222 fn parse_protobuf_varint_tests() {
223 let field_number = 1;
224 let mut data = b"\x0a".to_vec();
226 let len = parse_protobuf_varint(&mut data, field_number).unwrap();
227 assert_eq!(len, 10);
228
229 let mut data = b"\x0a\x0b".to_vec();
231 let len = parse_protobuf_varint(&mut data, field_number).unwrap();
232 assert_eq!(len, 10);
233 assert_eq!(data, b"\x0b".to_vec());
234
235 let mut data = b"\xac\x02".to_vec();
239 let len = parse_protobuf_varint(&mut data, field_number).unwrap();
240 assert_eq!(len, 300);
241
242 let mut data = b"\xac\x02\x0c".to_vec();
244 let len = parse_protobuf_varint(&mut data, field_number).unwrap();
245 assert_eq!(len, 300);
246 assert_eq!(data, b"\x0c".to_vec());
247
248 let mut data = vec![];
250 let err = parse_protobuf_varint(&mut data, field_number).unwrap_err();
251 assert!(matches!(err, ParseFailure(..)));
252
253 let mut data = b"\x80".to_vec();
255 let err = parse_protobuf_varint(&mut data, field_number).unwrap_err();
256 assert!(matches!(err, ParseFailure(..)));
257
258 let mut data = b"\x80\x81\x82\x83\x84\x83\x82\x81\x80".to_vec();
260 let err = parse_protobuf_varint(&mut data, field_number).unwrap_err();
261 assert!(matches!(err, ParseFailure(..)));
262 }
263
264 #[test]
265 fn parse_protobuf_length_prefixed_tests() {
266 let field_number = 1;
267 let mut data = b"\x0a\x03abc".to_vec();
269 let res = parse_protobuf_length_prefixed(&mut data, field_number).unwrap();
270 assert_eq!(res, b"abc".to_vec());
271 assert_eq!(data, vec![0u8; 0]);
272
273 let mut data = b"\x0a\x03abcd".to_vec();
275 let res = parse_protobuf_length_prefixed(&mut data, field_number).unwrap();
276 assert_eq!(res, b"abc".to_vec());
277 assert_eq!(data, b"d".to_vec());
278
279 let mut data = [b"\x0a\xac\x02", vec![65u8; 300].as_slice()]
281 .concat()
282 .to_vec();
283 let res = parse_protobuf_length_prefixed(&mut data, field_number).unwrap();
284 assert_eq!(res, vec![65u8; 300]);
285 assert_eq!(data, vec![0u8; 0]);
286
287 let mut data = [b"\x0a\xac\x02", vec![65u8; 300].as_slice(), b"rest"]
289 .concat()
290 .to_vec();
291 let res = parse_protobuf_length_prefixed(&mut data, field_number).unwrap();
292 assert_eq!(res, vec![65u8; 300]);
293 assert_eq!(data, b"rest");
294
295 let mut data = b"\x0a\x01".to_vec();
297 let field_number = 1;
298 let err = parse_protobuf_length_prefixed(&mut data, field_number).unwrap_err();
299 assert!(matches!(err, ParseFailure(..)));
300
301 let mut data = b"\x0b\x01a".to_vec();
303 let err = parse_protobuf_length_prefixed(&mut data, field_number).unwrap_err();
304 assert!(matches!(err, ParseFailure(..)));
305
306 let field_number = 2;
308 let mut data = b"\x0a\x01a".to_vec();
309 let err = parse_protobuf_length_prefixed(&mut data, field_number).unwrap_err();
310 assert!(matches!(err, ParseFailure(..)));
311 }
312
313 #[test]
314 fn parse_protobuf_bytes_works() {
315 let field_number = 1;
316
317 let data = vec![];
319 let mut encoded_data = encode_bytes(&data);
320
321 let res = parse_protobuf_bytes(&mut encoded_data, field_number).unwrap();
322 assert_eq!(res, None);
323
324 let data = b"test".to_vec();
326 let mut encoded_data = encode_bytes(&data);
327
328 let res = parse_protobuf_bytes(&mut encoded_data, field_number).unwrap();
329 assert_eq!(res, Some(Binary(data)));
330
331 let data = vec![0x40; 300];
333 let mut encoded_data = encode_bytes(&data);
334
335 let res = parse_protobuf_bytes(&mut encoded_data, field_number).unwrap();
336 assert_eq!(res, Some(Binary(data)));
337
338 let field_number = 5;
340 let data = b"test field 5".to_vec();
341 let mut encoded_data = encode_bytes(&data);
342 encoded_data[0] = (field_number << 3) + WIRE_TYPE_LENGTH_DELIMITED;
343
344 let res = parse_protobuf_bytes(&mut encoded_data, field_number).unwrap();
345 assert_eq!(res, Some(Binary(data)));
346
347 let field_number = 1;
349 let test_len: usize = 4;
350 let data = b"test_remainder".to_vec();
351 let mut encoded_data = encode_bytes(&data);
352 encoded_data[1] = test_len as u8;
353
354 let res = parse_protobuf_bytes(&mut encoded_data, field_number).unwrap();
355 assert_eq!(res, Some(Binary(data[..test_len].to_owned())));
356 assert_eq!(encoded_data, data[test_len..].to_owned());
357 }
358
359 #[test]
360 fn parse_protobuf_string_tests() {
361 let field_number = 1;
362
363 let data = "";
365 let mut encoded_data = encode_string(data);
366
367 let res = parse_protobuf_string(&mut encoded_data, field_number).unwrap();
368 assert_eq!(res, data);
369
370 let data = "test";
372 let mut encoded_data = encode_string(data);
373
374 let res = parse_protobuf_string(&mut encoded_data, field_number).unwrap();
375 assert_eq!(res, data);
376
377 let data = vec![0x40; 300];
379 let str_data = from_utf8(data.as_slice()).unwrap();
380 let mut encoded_data = encode_string(str_data);
381
382 let res = parse_protobuf_string(&mut encoded_data, field_number).unwrap();
383 assert_eq!(res, str_data);
384
385 let field_number = 5;
387 let data = "test field 5";
388 let mut encoded_data = encode_string(data);
389 encoded_data[0] = (field_number << 3) + WIRE_TYPE_LENGTH_DELIMITED;
390
391 let res = parse_protobuf_string(&mut encoded_data, field_number).unwrap();
392 assert_eq!(res, data);
393
394 let field_number = 1;
396 let test_len: usize = 4;
397 let data = "test_remainder";
398 let mut encoded_data = encode_string(data);
399 encoded_data[1] = test_len as u8;
400
401 let res = parse_protobuf_string(&mut encoded_data, field_number).unwrap();
402 assert_eq!(res, data[..test_len]);
403 assert_eq!(encoded_data, data[test_len..].as_bytes());
404
405 let field_number = 1;
407 let data = "test_X";
408 let mut encoded_data = encode_string(data);
409 let encoded_len = encoded_data.len();
410 encoded_data[encoded_len - 1] = 0xd3;
411 let err = parse_protobuf_string(&mut encoded_data, field_number).unwrap_err();
412 assert!(matches!(err, BrokenUtf8(..)));
413 }
414
415 #[test]
416 fn parse_reply_instantiate_data_works() {
417 let contract_addr: &str = "Contract #1";
418 for (data, expected) in [
419 (
420 vec![],
421 super::MsgInstantiateContractResponse {
422 contract_address: contract_addr.to_string(),
423 data: None,
424 },
425 ),
426 (
427 vec![1u8, 2, 255, 7, 5],
428 super::MsgInstantiateContractResponse {
429 contract_address: contract_addr.to_string(),
430 data: Some(Binary(vec![1u8, 2, 255, 7, 5])),
431 },
432 ),
433 (
434 vec![1u8; 127],
435 super::MsgInstantiateContractResponse {
436 contract_address: contract_addr.to_string(),
437 data: Some(Binary(vec![1u8; 127])),
438 },
439 ),
440 (
441 vec![2u8; 128],
442 super::MsgInstantiateContractResponse {
443 contract_address: contract_addr.to_string(),
444 data: Some(Binary(vec![2u8; 128])),
445 },
446 ),
447 (
448 vec![3u8; 257],
449 super::MsgInstantiateContractResponse {
450 contract_address: contract_addr.to_string(),
451 data: Some(Binary(vec![3u8; 257])),
452 },
453 ),
454 ] {
455 let instantiate_reply = MsgInstantiateContractResponse {
456 contract_address: contract_addr.to_string(),
457 data,
458 };
459 let mut encoded_instantiate_reply =
460 Vec::<u8>::with_capacity(instantiate_reply.encoded_len());
461 instantiate_reply
463 .encode(&mut encoded_instantiate_reply)
464 .unwrap();
465
466 let msg = Reply {
468 id: 1,
469 result: ContractResult::Ok(SubMsgExecutionResponse {
470 events: vec![],
471 data: Some(encoded_instantiate_reply.into()),
472 }),
473 };
474
475 let res = parse_reply_instantiate_data(msg).unwrap();
476 assert_eq!(res, expected);
477 }
478 }
479
480 #[test]
481 fn parse_reply_execute_data_works() {
482 for (data, expected) in [
483 (vec![], super::MsgExecuteContractResponse { data: None }),
484 (
485 vec![1u8, 2, 3, 127, 15],
486 super::MsgExecuteContractResponse {
487 data: Some(Binary(vec![1u8, 2, 3, 127, 15])),
488 },
489 ),
490 (
491 vec![0u8; 255],
492 super::MsgExecuteContractResponse {
493 data: Some(Binary(vec![0u8; 255])),
494 },
495 ),
496 (
497 vec![1u8; 256],
498 super::MsgExecuteContractResponse {
499 data: Some(Binary(vec![1u8; 256])),
500 },
501 ),
502 (
503 vec![2u8; 32769],
504 super::MsgExecuteContractResponse {
505 data: Some(Binary(vec![2u8; 32769])),
506 },
507 ),
508 ] {
509 let execute_reply = MsgExecuteContractResponse { data };
510 let mut encoded_execute_reply = Vec::<u8>::with_capacity(execute_reply.encoded_len());
511 execute_reply.encode(&mut encoded_execute_reply).unwrap();
513
514 let msg = Reply {
516 id: 1,
517 result: ContractResult::Ok(SubMsgExecutionResponse {
518 events: vec![],
519 data: Some(encoded_execute_reply.into()),
520 }),
521 };
522
523 let res = parse_reply_execute_data(msg).unwrap();
524
525 assert_eq!(res, expected);
526 }
527 }
528}