radix_transactions/model/preparation/
summarized_raw.rs

1use crate::internal_prelude::*;
2use sbor::*;
3
4/// For new values, prefer using [`SummarizedRawValueBody`].
5///
6/// For use where the value is:
7/// * Only ever serialized as a full SBOR body (with its value kind prefix)
8/// * Wants a hash which represents a hash of the full SBOR body in its SBOR-encoding
9#[derive(Debug, Clone, Eq, PartialEq)]
10#[deprecated = "For new models, prefer SummarizedRawValueBody, which allows the hash to be computed both when it's a full value, OR when it's only a child (e.g. in a vec)"]
11pub struct SummarizedRawFullValue<T: ManifestDecode> {
12    pub inner: T,
13    pub summary: Summary,
14}
15
16impl_has_summary!(<T: ManifestDecode> SummarizedRawFullValue<T>);
17
18#[allow(deprecated)]
19impl<T: ManifestDecode> TransactionPreparableFromValue for SummarizedRawFullValue<T> {
20    fn prepare_from_value(decoder: &mut TransactionDecoder) -> Result<Self, PrepareError> {
21        let start_offset = decoder.get_offset();
22        let inner = decoder.decode::<T>()?;
23        let end_offset = decoder.get_offset();
24        let summary = Summary {
25            effective_length: end_offset - start_offset,
26            total_bytes_hashed: end_offset - start_offset,
27            hash: hash(&decoder.get_slice_with_valid_bounds(start_offset, end_offset)),
28        };
29        Ok(Self { inner, summary })
30    }
31}
32
33/// For use where the value is:
34/// * Serialized as a full SBOR body (with its value kind prefix)
35/// * Wants a hash which represents a hash of the full SBOR body in its SBOR-encoding
36/// * Also wants a list of references
37#[derive(Debug, Clone, Eq, PartialEq)]
38#[deprecated = "For new models, prefer SummarizedRawValueBodyWithReferences, which allows the hash to be computed both when it's a full value, OR when it's only a child (e.g. in a vec)"]
39pub struct SummarizedRawFullValueWithReferences<T: ManifestDecode> {
40    pub inner: T,
41    pub summary: Summary,
42    pub references: IndexSet<Reference>,
43}
44
45#[allow(deprecated)]
46impl<T: ManifestDecode> HasSummary for SummarizedRawFullValueWithReferences<T> {
47    fn get_summary(&self) -> &Summary {
48        &self.summary
49    }
50
51    fn summary_mut(&mut self) -> &mut Summary {
52        &mut self.summary
53    }
54}
55
56#[allow(deprecated)]
57impl<T: ManifestDecode> TransactionPreparableFromValue for SummarizedRawFullValueWithReferences<T> {
58    fn prepare_from_value(decoder: &mut TransactionDecoder) -> Result<Self, PrepareError> {
59        let start_offset = decoder.get_offset();
60        let inner = decoder.decode::<T>()?;
61        let end_offset = decoder.get_offset();
62
63        let slice = decoder.get_slice_with_valid_bounds(start_offset, end_offset);
64        let references = extract_references(slice, traversal::ExpectedStart::Value);
65        let summary = Summary {
66            effective_length: end_offset - start_offset,
67            total_bytes_hashed: end_offset - start_offset,
68            hash: hash(slice),
69        };
70        Ok(Self {
71            inner,
72            summary,
73            references,
74        })
75    }
76}
77
78/// Similar to [`SummarizedRawValueBody`] For use where the value is:
79/// * EITHER exists as a full value OR is contained inside a Vec or Map under its SBOR parent
80/// * Wants a hash which represents a hash of all of the bytes in its SBOR-encoding (EXCEPT the possibly missing value kind prefix)
81/// * Also wants a list of references
82#[derive(Debug, Clone, Eq, PartialEq)]
83pub struct SummarizedRawValueBodyWithReferences<T: ManifestDecode + ManifestCategorize> {
84    pub inner: T,
85    pub summary: Summary,
86    pub references: IndexSet<Reference>,
87}
88
89impl_has_summary!(<T: ManifestDecode + ManifestCategorize> SummarizedRawValueBodyWithReferences<T>);
90
91impl<T: ManifestDecode + ManifestCategorize> TransactionPreparableFromValueBody
92    for SummarizedRawValueBodyWithReferences<T>
93{
94    fn prepare_from_value_body(decoder: &mut TransactionDecoder) -> Result<Self, PrepareError> {
95        let start_offset = decoder.get_offset();
96        let inner = decoder.decode_deeper_body_with_value_kind::<T>(T::value_kind())?;
97        let end_offset = decoder.get_offset();
98        let slice = decoder.get_slice_with_valid_bounds(start_offset, end_offset);
99        let references =
100            extract_references(slice, traversal::ExpectedStart::ValueBody(T::value_kind()));
101        let summary = Summary {
102            effective_length: end_offset - start_offset,
103            total_bytes_hashed: end_offset - start_offset,
104            hash: hash(slice),
105        };
106        Ok(Self {
107            inner,
108            references,
109            summary,
110        })
111    }
112
113    fn value_kind() -> ManifestValueKind {
114        T::value_kind()
115    }
116}
117
118/// For use where the value is:
119/// * EITHER exists as a full value OR is contained inside a Vec or Map under its SBOR parent
120/// * Wants a hash which represents a hash of all of the bytes in its SBOR-encoding (EXCEPT the possibly missing value kind prefix)
121#[derive(Debug, Clone, Eq, PartialEq)]
122pub struct SummarizedRawValueBody<T: ManifestDecode + ManifestCategorize> {
123    pub inner: T,
124    pub summary: Summary,
125}
126
127impl_has_summary!(<T: ManifestDecode + ManifestCategorize> SummarizedRawValueBody<T>);
128
129impl<T: ManifestDecode + ManifestCategorize> TransactionPreparableFromValueBody
130    for SummarizedRawValueBody<T>
131{
132    fn prepare_from_value_body(decoder: &mut TransactionDecoder) -> Result<Self, PrepareError> {
133        let start_offset = decoder.get_offset();
134        let inner = decoder.decode_deeper_body_with_value_kind::<T>(T::value_kind())?;
135        let end_offset = decoder.get_offset();
136        let summary = Summary {
137            effective_length: end_offset - start_offset,
138            total_bytes_hashed: end_offset - start_offset,
139            hash: hash(&decoder.get_slice_with_valid_bounds(start_offset, end_offset)),
140        };
141        Ok(Self { inner, summary })
142    }
143
144    fn value_kind() -> ManifestValueKind {
145        T::value_kind()
146    }
147}
148
149/// For use where the value is:
150/// * Contained inside a Vec or Map under its SBOR parent
151/// * AND is actually a Vec<u8> itself
152/// * AND wants a hash which represents a hash of its underlying raw bytes
153#[derive(Debug, Clone, Eq, PartialEq)]
154pub struct SummarizedRawValueBodyRawBytes {
155    pub inner: Vec<u8>,
156    pub summary: Summary,
157}
158
159impl_has_summary!(SummarizedRawValueBodyRawBytes);
160
161impl TransactionPreparableFromValueBody for SummarizedRawValueBodyRawBytes {
162    fn prepare_from_value_body(decoder: &mut TransactionDecoder) -> Result<Self, PrepareError> {
163        let inner = decoder.decode_deeper_body_with_value_kind::<Vec<u8>>(Self::value_kind())?;
164
165        // NOTE: We purposefully don't take the effective_length from the size of the SBOR type header
166        // This is because the SBOR value header isn't included in the hash...
167        // And we want to protect against non-determinism in the effective_length due to a different serializations of the SBOR value header.
168        // Whilst we believe the SBOR value header to currently be unique (eg we don't allow trailing bytes in the encoded size) - I'd rather not rely on that.
169        // So just assume it's 2 here (1 byte for value kind + 1 byte for length if length sufficiently short)
170        let effective_length = 2usize;
171
172        let summary = Summary {
173            effective_length: effective_length
174                .checked_add(inner.len())
175                .ok_or(PrepareError::LengthOverflow)?,
176            total_bytes_hashed: inner.len(),
177            hash: hash(&inner),
178        };
179        Ok(Self { inner, summary })
180    }
181
182    fn value_kind() -> ManifestValueKind {
183        Vec::<u8>::value_kind()
184    }
185}
186
187/// For use where the value is:
188/// * Already a hash, and it should be prepared as itself
189#[derive(Debug, Clone, Eq, PartialEq)]
190pub struct RawHash {
191    pub hash: Hash,
192    pub summary: Summary,
193}
194
195impl_has_summary!(RawHash);
196
197impl TransactionPreparableFromValueBody for RawHash {
198    fn prepare_from_value_body(decoder: &mut TransactionDecoder) -> Result<Self, PrepareError> {
199        let start_offset = decoder.get_offset();
200        let hash = decoder.decode_deeper_body_with_value_kind::<Hash>(Self::value_kind())?;
201        let end_offset = decoder.get_offset();
202        let summary = Summary {
203            effective_length: end_offset - start_offset,
204            // It's already been hashed before prepare, so don't count it
205            total_bytes_hashed: 0,
206            hash,
207        };
208        Ok(Self { hash, summary })
209    }
210
211    fn value_kind() -> ManifestValueKind {
212        ManifestValueKind::Array
213    }
214}