Skip to main content

scale_value/scale_impls/tracing_decoder/
visitor.rs

1// Copyright (C) 2022-2024 Parity Technologies (UK) Ltd. (admin@parity.io)
2// This file is a part of the scale-value crate.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//         http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use crate::prelude::*;
17
18use super::error::TraceDecodingError;
19use super::path::Path;
20use crate::{Composite, Primitive, Value, ValueDef, Variant};
21use core::marker::PhantomData;
22use scale_decode::visitor::TypeIdFor;
23use scale_type_resolver::TypeResolver;
24
25// Don't alloc more than 100M entries; error instead if we try to exceed this.
26// Helps to catch issues with bad data which leads panics instead of helpful errors.
27const MAX_CAPACITY: usize = 100_000_000;
28
29/// A visitor that will attempt to decode some bytes into a [`crate::Value`],
30/// returning a detailed error of where the decoding fails if it does.
31pub struct TraceDecodingVisitor<Resolver> {
32    path: Path,
33    marker: PhantomData<Resolver>,
34}
35
36impl<Resolver> TraceDecodingVisitor<Resolver> {
37    fn at_path(&self, path: Path) -> Self {
38        TraceDecodingVisitor { path, marker: PhantomData }
39    }
40    fn at_idx(&self, idx: usize) -> Self {
41        self.at_path(self.path.at_idx(idx))
42    }
43    fn at_field(&self, field: String) -> Self {
44        self.at_path(self.path.at_field(field))
45    }
46}
47
48impl<Resolver> Default for TraceDecodingVisitor<Resolver> {
49    fn default() -> Self {
50        Self::new()
51    }
52}
53
54impl<Resolver> TraceDecodingVisitor<Resolver> {
55    /// Construct a new [`TraceDecodingVisitor`].
56    pub fn new() -> Self {
57        TraceDecodingVisitor { path: Path::new(), marker: PhantomData }
58    }
59}
60
61macro_rules! to_unnamed_composite {
62    ($self:ident, $value:ident) => {{
63        let mut f = move || {
64            let mut idx = 0;
65
66            if $value.remaining() > MAX_CAPACITY {
67                let err: codec::Error = "TraceDecodingVisitor is trying to create a Vec with a capacity greater than 100M entries".into();
68                let err: TraceDecodingError<_> = err.into();
69                return Err(err);
70            }
71
72            let mut vals = Vec::with_capacity($value.remaining());
73            while let Some(val) = $value.decode_item($self.at_idx(idx)) {
74                match val {
75                    Err(e) => {
76                        let merged_error = e.with_outer_context(
77                            || $self.path.at_idx(idx),
78                            || Composite::Unnamed(vals.clone()),
79                            |inner_value| {
80                                let mut vals = vals.clone();
81                                vals.push(inner_value);
82                                Composite::Unnamed(vals)
83                            },
84                        );
85                        return Err(merged_error);
86                    }
87                    Ok(v) => {
88                        vals.push(v);
89                    }
90                }
91
92                idx += 1;
93            }
94
95            Ok::<_, TraceDecodingError<_>>(Composite::Unnamed(vals))
96        };
97
98        f()
99    }};
100}
101
102macro_rules! to_unnamed_composite_value {
103    ($self:ident, $value:ident, $type_id:ident) => {{
104        let composite = to_unnamed_composite!($self, $value).map_err(|e| {
105            e.map_decoded_so_far(|c| Value {
106                value: ValueDef::Composite(c),
107                context: $type_id.clone(),
108            })
109        })?;
110
111        Ok(Value { value: ValueDef::Composite(composite), context: $type_id })
112    }};
113}
114
115impl<Resolver> scale_decode::Visitor for TraceDecodingVisitor<Resolver>
116where
117    Resolver: TypeResolver,
118{
119    type Value<'scale, 'resolver> = Value<TypeIdFor<Self>>;
120    type Error = TraceDecodingError<Value<TypeIdFor<Self>>>;
121    type TypeResolver = Resolver;
122
123    fn visit_bool<'scale, 'resolver>(
124        self,
125        value: bool,
126        type_id: TypeIdFor<Self>,
127    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
128        Ok(Value::with_context(ValueDef::Primitive(Primitive::Bool(value)), type_id))
129    }
130
131    fn visit_char<'scale, 'resolver>(
132        self,
133        value: char,
134        type_id: TypeIdFor<Self>,
135    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
136        Ok(Value::with_context(ValueDef::Primitive(Primitive::Char(value)), type_id))
137    }
138
139    fn visit_u8<'scale, 'resolver>(
140        self,
141        value: u8,
142        type_id: TypeIdFor<Self>,
143    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
144        self.visit_u128(value as u128, type_id)
145    }
146
147    fn visit_u16<'scale, 'resolver>(
148        self,
149        value: u16,
150        type_id: TypeIdFor<Self>,
151    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
152        self.visit_u128(value as u128, type_id)
153    }
154
155    fn visit_u32<'scale, 'resolver>(
156        self,
157        value: u32,
158        type_id: TypeIdFor<Self>,
159    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
160        self.visit_u128(value as u128, type_id)
161    }
162
163    fn visit_u64<'scale, 'resolver>(
164        self,
165        value: u64,
166        type_id: TypeIdFor<Self>,
167    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
168        self.visit_u128(value as u128, type_id)
169    }
170
171    fn visit_u128<'scale, 'resolver>(
172        self,
173        value: u128,
174        type_id: TypeIdFor<Self>,
175    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
176        Ok(Value::with_context(ValueDef::Primitive(Primitive::U128(value)), type_id))
177    }
178
179    fn visit_u256<'info>(
180        self,
181        value: &[u8; 32],
182        type_id: TypeIdFor<Self>,
183    ) -> Result<Self::Value<'_, 'info>, Self::Error> {
184        Ok(Value::with_context(ValueDef::Primitive(Primitive::U256(*value)), type_id))
185    }
186
187    fn visit_i8<'scale, 'resolver>(
188        self,
189        value: i8,
190        type_id: TypeIdFor<Self>,
191    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
192        self.visit_i128(value as i128, type_id)
193    }
194
195    fn visit_i16<'scale, 'resolver>(
196        self,
197        value: i16,
198        type_id: TypeIdFor<Self>,
199    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
200        self.visit_i128(value as i128, type_id)
201    }
202
203    fn visit_i32<'scale, 'resolver>(
204        self,
205        value: i32,
206        type_id: TypeIdFor<Self>,
207    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
208        self.visit_i128(value as i128, type_id)
209    }
210
211    fn visit_i64<'scale, 'resolver>(
212        self,
213        value: i64,
214        type_id: TypeIdFor<Self>,
215    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
216        self.visit_i128(value as i128, type_id)
217    }
218
219    fn visit_i128<'scale, 'resolver>(
220        self,
221        value: i128,
222        type_id: TypeIdFor<Self>,
223    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
224        Ok(Value::with_context(ValueDef::Primitive(Primitive::I128(value)), type_id))
225    }
226
227    fn visit_i256<'info>(
228        self,
229        value: &[u8; 32],
230        type_id: TypeIdFor<Self>,
231    ) -> Result<Self::Value<'_, 'info>, Self::Error> {
232        Ok(Value::with_context(ValueDef::Primitive(Primitive::I256(*value)), type_id))
233    }
234
235    fn visit_bitsequence<'scale, 'info>(
236        self,
237        value: &mut scale_decode::visitor::types::BitSequence<'scale>,
238        type_id: TypeIdFor<Self>,
239    ) -> Result<Self::Value<'scale, 'info>, Self::Error> {
240        let bits: Result<_, _> = value.decode()?.collect();
241        Ok(Value::with_context(ValueDef::BitSequence(bits?), type_id))
242    }
243
244    fn visit_str<'scale, 'info>(
245        self,
246        value: &mut scale_decode::visitor::types::Str<'scale>,
247        type_id: TypeIdFor<Self>,
248    ) -> Result<Self::Value<'scale, 'info>, Self::Error> {
249        Ok(Value::with_context(
250            ValueDef::Primitive(Primitive::String(value.as_str()?.to_owned())),
251            type_id,
252        ))
253    }
254
255    fn visit_sequence<'scale, 'resolver>(
256        self,
257        value: &mut scale_decode::visitor::types::Sequence<'scale, 'resolver, Self::TypeResolver>,
258        type_id: TypeIdFor<Self>,
259    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
260        to_unnamed_composite_value!(self, value, type_id)
261    }
262
263    fn visit_array<'scale, 'resolver>(
264        self,
265        value: &mut scale_decode::visitor::types::Array<'scale, 'resolver, Self::TypeResolver>,
266        type_id: scale_decode::visitor::TypeIdFor<Self>,
267    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
268        to_unnamed_composite_value!(self, value, type_id)
269    }
270
271    fn visit_tuple<'scale, 'resolver>(
272        self,
273        value: &mut scale_decode::visitor::types::Tuple<'scale, 'resolver, Self::TypeResolver>,
274        type_id: TypeIdFor<Self>,
275    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
276        to_unnamed_composite_value!(self, value, type_id)
277    }
278
279    fn visit_variant<'scale, 'resolver>(
280        self,
281        value: &mut scale_decode::visitor::types::Variant<'scale, 'resolver, Self::TypeResolver>,
282        type_id: TypeIdFor<Self>,
283    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
284        let variant_name = value.name();
285        let path = self.path.at_variant(variant_name.to_owned());
286        let values = visit_composite(&self, value.fields());
287        match values {
288            Err(e) => {
289                let merged_error = e.with_outer_context(
290                    || path.clone(),
291                    || Value {
292                        value: ValueDef::Variant(Variant {
293                            name: variant_name.to_owned(),
294                            values: Composite::Unnamed(vec![]),
295                        }),
296                        context: type_id.clone(),
297                    },
298                    |inner_value| Value {
299                        value: ValueDef::Variant(Variant {
300                            name: variant_name.to_owned(),
301                            values: inner_value,
302                        }),
303                        context: type_id.clone(),
304                    },
305                );
306                Err(merged_error)
307            }
308            Ok(values) => Ok(Value {
309                value: ValueDef::Variant(Variant { name: variant_name.to_owned(), values }),
310                context: type_id,
311            }),
312        }
313    }
314
315    fn visit_composite<'scale, 'resolver>(
316        self,
317        value: &mut scale_decode::visitor::types::Composite<'scale, 'resolver, Self::TypeResolver>,
318        type_id: TypeIdFor<Self>,
319    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
320        let composite_vals = visit_composite(&self, value).map_err(|e| {
321            e.map_decoded_so_far(|c| Value {
322                value: ValueDef::Composite(c),
323                context: type_id.clone(),
324            })
325        })?;
326
327        Ok(Value { value: ValueDef::Composite(composite_vals), context: type_id })
328    }
329}
330
331fn visit_composite<R>(
332    this: &TraceDecodingVisitor<R>,
333    value: &mut scale_decode::visitor::types::Composite<'_, '_, R>,
334) -> Result<Composite<R::TypeId>, TraceDecodingError<Composite<R::TypeId>>>
335where
336    R: TypeResolver,
337{
338    let len = value.remaining();
339
340    // if no fields, we'll always assume unnamed.
341    let named = len > 0 && !value.has_unnamed_fields();
342
343    // if unnamed, treat like array/tuple/sequence.
344    if !named {
345        return to_unnamed_composite!(this, value);
346    }
347
348    // otherwise, treat as a named struct.
349    let mut vals = Vec::with_capacity(len);
350    let mut name = value.peek_name().unwrap_or("<unnamed>");
351
352    while let Some(val) = value.decode_item(this.at_field(name.to_owned())) {
353        match val {
354            Err(e) => {
355                let merged_error = e.with_outer_context(
356                    || this.path.at_field(name.to_owned()),
357                    || Composite::Named(vals.clone()),
358                    |inner_value| {
359                        let mut vals = vals.clone();
360                        vals.push((name.to_owned(), inner_value));
361                        Composite::Named(vals)
362                    },
363                );
364                return Err(merged_error);
365            }
366            Ok(v) => {
367                vals.push((name.to_owned(), v));
368            }
369        }
370
371        name = value.peek_name().unwrap_or("<unnamed>");
372    }
373
374    Ok(Composite::Named(vals))
375}