staging_xcm/
double_encoded.rs1use crate::{DECODE_ALL_ERR_MSG, MAX_XCM_DECODE_DEPTH, RECURSION_LIMIT};
18use alloc::vec::Vec;
19use codec::{Decode, DecodeLimit, DecodeWithMemTracking, Encode};
20use sp_runtime::Saturating;
21
22pub(crate) const DECODE_MAX_DEPTH_MSG: &str =
23 "Depth limit exceeded while decoding DoubleEncoded object";
24pub(crate) const DECODE_RECURSION_LIMIT_MSG: &str =
25 "Recursion limit exceeded while decoding DoubleEncoded object";
26
27environmental::environmental!(nesting_count: u32);
28
29fn descend_ref_and_check_depth(
30 depth: &mut u32,
31 depth_limit: u32,
32 err_msg: &'static str,
33) -> Result<(), codec::Error> {
34 depth.saturating_inc();
35 if *depth > depth_limit {
36 return Err(err_msg.into());
37 }
38 Ok(())
39}
40
41struct NestedInput<'a> {
63 downstream_input: &'a mut dyn codec::Input,
64 encoded: &'a [u8],
65 depth: u32,
66}
67
68impl<'a> codec::Input for NestedInput<'a> {
69 fn remaining_len(&mut self) -> Result<Option<usize>, codec::Error> {
70 self.encoded.remaining_len()
71 }
72
73 fn read(&mut self, into: &mut [u8]) -> Result<(), codec::Error> {
74 self.encoded.read(into)
75 }
76
77 fn read_byte(&mut self) -> Result<u8, codec::Error> {
78 self.encoded.read_byte()
79 }
80
81 fn descend_ref(&mut self) -> Result<(), codec::Error> {
82 descend_ref_and_check_depth(&mut self.depth, MAX_XCM_DECODE_DEPTH, DECODE_MAX_DEPTH_MSG)
83 }
84
85 fn ascend_ref(&mut self) {
86 self.depth.saturating_dec();
87 }
88
89 fn on_before_alloc_mem(&mut self, size: usize) -> Result<(), codec::Error> {
90 self.downstream_input.on_before_alloc_mem(size)
91 }
92}
93
94#[derive(Encode, DecodeWithMemTracking, scale_info::TypeInfo)]
97#[codec(encode_bound())]
98#[codec(decode_with_mem_tracking_bound(T: Decode))]
99#[scale_info(bounds(), skip_type_params(T))]
100#[scale_info(replace_segment("staging_xcm", "xcm"))]
101#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
102pub struct DoubleEncoded<T> {
103 encoded: Vec<u8>,
104 #[codec(skip)]
105 decoded: Option<T>,
106}
107
108impl<T> Decode for DoubleEncoded<T>
109where
110 T: Decode,
111{
112 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
113 let mut obj = Self { encoded: Vec::<u8>::decode(input)?, decoded: None };
114
115 nesting_count::using_once(&mut 0, || {
118 nesting_count::with(|count| {
119 descend_ref_and_check_depth(
120 count,
121 RECURSION_LIMIT as u32,
122 DECODE_RECURSION_LIMIT_MSG,
123 )
124 })
125 .unwrap_or(Err("Could not access nesting_count env variable".into()))?;
126
127 let mut nested_input =
128 NestedInput { downstream_input: input, encoded: &obj.encoded[..], depth: 0 };
129 let decoded = T::decode(&mut nested_input)?;
130 if nested_input.encoded.len() == obj.encoded.len() {
133 let _ = nesting_count::with(|count| {
134 count.saturating_dec();
135 });
136
137 return Ok(obj);
138 }
139 obj.decoded = Some(decoded);
140
141 if !nested_input.encoded.is_empty() {
144 return Err(DECODE_ALL_ERR_MSG.into());
145 }
146
147 let _ = nesting_count::with(|count| {
148 count.saturating_dec();
149 });
150
151 Ok(obj)
152 })
153 }
154}
155
156impl<T> Clone for DoubleEncoded<T> {
157 fn clone(&self) -> Self {
158 Self { encoded: self.encoded.clone(), decoded: None }
159 }
160}
161
162impl<T> PartialEq for DoubleEncoded<T> {
163 fn eq(&self, other: &Self) -> bool {
164 self.encoded.eq(&other.encoded)
165 }
166}
167impl<T> Eq for DoubleEncoded<T> {}
168
169impl<T> core::fmt::Debug for DoubleEncoded<T> {
170 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
171 array_bytes::bytes2hex("0x", &self.encoded).fmt(f)
172 }
173}
174
175impl<T> From<Vec<u8>> for DoubleEncoded<T> {
176 fn from(encoded: Vec<u8>) -> Self {
177 Self { encoded, decoded: None }
178 }
179}
180
181impl<T> DoubleEncoded<T> {
182 pub fn encoded(&self) -> &[u8] {
183 &self.encoded
184 }
185
186 pub fn transmute_encoded<S>(self) -> DoubleEncoded<S> {
188 DoubleEncoded { encoded: self.encoded, decoded: None }
189 }
190}
191
192impl<T: Decode> DoubleEncoded<T> {
193 pub fn ensure_decoded(&mut self) -> Result<&T, ()> {
197 if self.decoded.is_none() {
198 self.decoded =
199 T::decode_all_with_depth_limit(MAX_XCM_DECODE_DEPTH, &mut &self.encoded[..]).ok();
200 }
201 self.decoded.as_ref().ok_or(())
202 }
203
204 pub fn try_into(mut self) -> Result<T, ()> {
208 self.ensure_decoded()?;
209 self.decoded.ok_or(())
210 }
211}
212
213#[cfg(test)]
214mod tests {
215 use super::*;
216
217 #[test]
218 fn ensure_decoded_works() {
219 let val: u64 = 42;
220 let mut encoded: DoubleEncoded<_> = Encode::encode(&val).into();
221 assert_eq!(encoded.ensure_decoded(), Ok(&val));
222 }
223
224 #[test]
225 fn try_into_works() {
226 let val: u64 = 42;
227 let encoded: DoubleEncoded<_> = Encode::encode(&val).into();
228 assert_eq!(encoded.try_into(), Ok(val));
229 }
230}