radix_transactions/model/preparation/
summarized_composite.rs1use crate::internal_prelude::*;
2use radix_common::constants::*;
3
4pub enum ConcatenatedDigest {}
5
6impl ConcatenatedDigest {
7 pub fn prepare_transaction_payload<T: TuplePreparable>(
9 decoder: &mut TransactionDecoder,
10 discriminator: TransactionDiscriminator,
11 header: ExpectedHeaderKind,
12 ) -> Result<(T, Summary), PrepareError> {
13 let digest = HashAccumulator::new()
14 .concat([TRANSACTION_HASHABLE_PAYLOAD_PREFIX, discriminator as u8]);
15 T::prepare_into_concatenated_digest(
16 decoder,
17 digest,
18 header.with_discriminator(discriminator as u8),
19 )
20 }
21
22 #[deprecated = "Use prepare_from_sbor_array_value_body instead for new models"]
23 pub fn prepare_from_sbor_array_full_value<T: ArrayPreparable>(
24 decoder: &mut TransactionDecoder,
25 value_type: ValueType,
26 max_length: usize,
27 ) -> Result<(T, Summary), PrepareError> {
28 T::prepare_into_concatenated_digest(
29 decoder,
30 HashAccumulator::new(),
31 value_type,
32 max_length,
33 true,
34 )
35 }
36
37 pub fn prepare_from_sbor_array_value_body<T: ArrayPreparable>(
38 decoder: &mut TransactionDecoder,
39 value_type: ValueType,
40 max_length: usize,
41 ) -> Result<(T, Summary), PrepareError> {
42 T::prepare_into_concatenated_digest(
43 decoder,
44 HashAccumulator::new(),
45 value_type,
46 max_length,
47 false,
48 )
49 }
50
51 #[deprecated = "Use prepare_from_sbor_tuple_value_body instead for new models"]
52 pub fn prepare_from_sbor_tuple_full_value<T: TuplePreparable>(
53 decoder: &mut TransactionDecoder,
54 ) -> Result<(T, Summary), PrepareError> {
55 T::prepare_into_concatenated_digest(
56 decoder,
57 HashAccumulator::new(),
58 ExpectedTupleHeader::TupleWithValueKind,
59 )
60 }
61
62 pub fn prepare_from_sbor_tuple_value_body<T: TuplePreparable>(
63 decoder: &mut TransactionDecoder,
64 ) -> Result<(T, Summary), PrepareError> {
65 T::prepare_into_concatenated_digest(
66 decoder,
67 HashAccumulator::new(),
68 ExpectedTupleHeader::TupleNoValueKind,
69 )
70 }
71}
72
73pub trait ArrayPreparable: Sized {
74 fn prepare_into_concatenated_digest(
75 decoder: &mut TransactionDecoder,
76 accumulator: HashAccumulator,
77 value_type: ValueType,
78 max_length: usize,
79 read_value_kind: bool,
80 ) -> Result<(Self, Summary), PrepareError>;
81}
82
83impl<T: TransactionPreparableFromValueBody> ArrayPreparable for Vec<T> {
84 fn prepare_into_concatenated_digest(
85 decoder: &mut TransactionDecoder,
86 mut accumulator: HashAccumulator,
87 value_type: ValueType,
88 max_length: usize,
89 read_value_kind: bool,
90 ) -> Result<(Self, Summary), PrepareError> {
91 decoder.track_stack_depth_increase()?;
92 let length = if read_value_kind {
93 decoder.read_array_header(T::value_kind())?
94 } else {
95 decoder.read_array_header_without_value_kind(T::value_kind())?
96 };
97
98 if length > max_length {
99 return Err(PrepareError::TooManyValues {
100 value_type,
101 actual: length,
102 max: max_length,
103 });
104 }
105
106 let mut effective_length = 2usize;
112 let mut total_bytes_hashed = 0usize;
113
114 let mut all_prepared: Vec<T> = Vec::with_capacity(length);
115 for _ in 0..length {
116 let prepared = T::prepare_from_value_body(decoder)?;
117 effective_length = effective_length
118 .checked_add(prepared.get_summary().effective_length)
119 .ok_or(PrepareError::LengthOverflow)?;
120 total_bytes_hashed = total_bytes_hashed
121 .checked_add(prepared.get_summary().total_bytes_hashed)
122 .ok_or(PrepareError::LengthOverflow)?;
123 accumulator = accumulator.concat(prepared.get_summary().hash);
124 all_prepared.push(prepared);
125 }
126
127 decoder.track_stack_depth_decrease()?;
128
129 total_bytes_hashed = total_bytes_hashed
130 .checked_add(accumulator.input_length())
131 .ok_or(PrepareError::LengthOverflow)?;
132
133 let summary = Summary {
134 effective_length,
135 total_bytes_hashed,
136 hash: accumulator.finalize(),
137 };
138
139 Ok((all_prepared, summary))
140 }
141}
142
143pub trait TuplePreparable: Sized {
144 fn prepare_into_concatenated_digest(
145 decoder: &mut TransactionDecoder,
146 accumulator: HashAccumulator,
147 header: ExpectedTupleHeader,
148 ) -> Result<(Self, Summary), PrepareError>;
149}
150
151pub enum ExpectedHeaderKind {
152 EnumNoValueKind,
153 EnumWithValueKind,
154 TupleNoValueKind,
155 TupleWithValueKind,
156}
157
158impl ExpectedHeaderKind {
159 pub fn with_discriminator(self, discriminator: u8) -> ExpectedTupleHeader {
160 match self {
161 Self::EnumNoValueKind => ExpectedTupleHeader::EnumNoValueKind { discriminator },
162 Self::EnumWithValueKind => ExpectedTupleHeader::EnumWithValueKind { discriminator },
163 Self::TupleNoValueKind => ExpectedTupleHeader::TupleNoValueKind,
164 Self::TupleWithValueKind => ExpectedTupleHeader::TupleWithValueKind,
165 }
166 }
167}
168
169pub enum ExpectedTupleHeader {
170 EnumNoValueKind { discriminator: u8 },
171 EnumWithValueKind { discriminator: u8 },
172 TupleWithValueKind,
173 TupleNoValueKind,
174}
175
176macro_rules! prepare_tuple {
177 ($n:tt$( $var_name:ident $type_name:ident)*) => {
178 impl<$($type_name: TransactionPreparableFromValue,)*> TuplePreparable for ($($type_name,)*) {
179 #[allow(unused_mut)]
180 fn prepare_into_concatenated_digest(decoder: &mut TransactionDecoder, mut accumulator: HashAccumulator, header: ExpectedTupleHeader) -> Result<(Self, Summary), PrepareError> {
181 decoder.track_stack_depth_increase()?;
182 decoder.read_header(header, $n)?;
183
184 let mut effective_length = 2usize;
191 let mut total_bytes_hashed = 0usize;
192
193 $(
194 let $var_name = <$type_name>::prepare_from_value(decoder)?;
195 effective_length = effective_length.checked_add($var_name.get_summary().effective_length).ok_or(PrepareError::LengthOverflow)?;
196 total_bytes_hashed = total_bytes_hashed.checked_add($var_name.get_summary().total_bytes_hashed).ok_or(PrepareError::LengthOverflow)?;
197 accumulator = accumulator.concat($var_name.get_summary().hash);
198 )*
199
200 decoder.track_stack_depth_decrease()?;
201
202 total_bytes_hashed = total_bytes_hashed.checked_add(accumulator.input_length()).ok_or(PrepareError::LengthOverflow)?;
203
204 let summary = Summary {
205 effective_length,
206 total_bytes_hashed,
207 hash: accumulator.finalize(),
208 };
209 Ok((($($var_name,)*), summary))
210 }
211 }
212 };
213}
214
215prepare_tuple! { 0 }
216prepare_tuple! { 1 p0 T0 }
217prepare_tuple! { 2 p0 T0 p1 T1 }
218prepare_tuple! { 3 p0 T0 p1 T1 p2 T2 }
219prepare_tuple! { 4 p0 T0 p1 T1 p2 T2 p3 T3 }
220prepare_tuple! { 5 p0 T0 p1 T1 p2 T2 p3 T3 p4 T4 }
221prepare_tuple! { 6 p0 T0 p1 T1 p2 T2 p3 T3 p4 T4 p5 T5 }