radix_transactions/model/preparation/
decoder.rs

1use crate::internal_prelude::*;
2use sbor::*;
3
4#[derive(Debug, Clone, Eq, PartialEq)]
5pub enum ValueType {
6    Blob,
7    Subintent,
8    ChildSubintentSpecifier,
9    SubintentSignatureBatches,
10    // Too many signatures is captured at validation time
11}
12
13#[derive(Debug, Clone, Eq, PartialEq)]
14pub enum PrepareError {
15    TransactionTypeNotSupported,
16    TransactionTooLarge,
17    DecodeError(DecodeError),
18    EncodeError(EncodeError),
19    TooManyValues {
20        value_type: ValueType,
21        actual: usize,
22        max: usize,
23    },
24    LengthOverflow,
25    UnexpectedTransactionDiscriminator {
26        actual: Option<u8>,
27    },
28}
29
30impl From<DecodeError> for PrepareError {
31    fn from(value: DecodeError) -> Self {
32        Self::DecodeError(value)
33    }
34}
35
36impl From<EncodeError> for PrepareError {
37    fn from(value: EncodeError) -> Self {
38        Self::EncodeError(value)
39    }
40}
41
42pub type PreparationSettings = PreparationSettingsV1;
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Sbor)]
45pub struct PreparationSettingsV1 {
46    pub v2_transactions_permitted: bool,
47    pub max_user_payload_length: usize,
48    pub max_ledger_payload_length: usize,
49    pub max_child_subintents_per_intent: usize,
50    pub max_subintents_per_transaction: usize,
51    pub max_blobs: usize,
52}
53
54static LATEST_PREPARATION_SETTINGS: PreparationSettings = PreparationSettings::latest();
55
56impl PreparationSettings {
57    pub const fn latest() -> Self {
58        Self::cuttlefish()
59    }
60
61    pub const fn babylon() -> Self {
62        let max_user_payload_length = 1024 * 1024;
63        Self {
64            v2_transactions_permitted: false,
65            max_user_payload_length,
66            max_ledger_payload_length: max_user_payload_length + 10,
67            max_child_subintents_per_intent: 0,
68            max_subintents_per_transaction: 0,
69            max_blobs: 64,
70        }
71    }
72
73    pub const fn cuttlefish() -> Self {
74        Self {
75            v2_transactions_permitted: true,
76            max_child_subintents_per_intent: 32,
77            max_subintents_per_transaction: 32,
78            ..Self::babylon()
79        }
80    }
81
82    pub fn latest_ref() -> &'static Self {
83        &LATEST_PREPARATION_SETTINGS
84    }
85
86    fn check_len(
87        &self,
88        kind: TransactionPayloadKind,
89        payload_len: usize,
90    ) -> Result<(), PrepareError> {
91        match kind {
92            TransactionPayloadKind::CompleteUserTransaction => {
93                if payload_len > self.max_user_payload_length {
94                    return Err(PrepareError::TransactionTooLarge);
95                }
96            }
97            TransactionPayloadKind::LedgerTransaction => {
98                if payload_len > self.max_ledger_payload_length {
99                    return Err(PrepareError::TransactionTooLarge);
100                }
101            }
102            TransactionPayloadKind::Other => {
103                // No explicit payload length checks
104            }
105        }
106        Ok(())
107    }
108}
109
110pub struct TransactionDecoder<'a> {
111    decoder: ManifestDecoder<'a>,
112    settings: &'a PreparationSettings,
113}
114
115impl<'a> TransactionDecoder<'a> {
116    pub fn new_transaction(
117        payload: &'a [u8],
118        kind: TransactionPayloadKind,
119        settings: &'a PreparationSettings,
120    ) -> Result<Self, PrepareError> {
121        settings.check_len(kind, payload.len())?;
122        let mut decoder = ManifestDecoder::new(payload, MANIFEST_SBOR_V1_MAX_DEPTH);
123        decoder.read_and_check_payload_prefix(MANIFEST_SBOR_V1_PAYLOAD_PREFIX)?;
124        Ok(Self { decoder, settings })
125    }
126
127    pub fn new_partial(
128        payload: &'a [u8],
129        settings: &'a PreparationSettings,
130    ) -> Result<Self, PrepareError> {
131        let mut decoder = ManifestDecoder::new(payload, MANIFEST_SBOR_V1_MAX_DEPTH);
132        decoder.read_and_check_payload_prefix(MANIFEST_SBOR_V1_PAYLOAD_PREFIX)?;
133        Ok(Self { decoder, settings })
134    }
135
136    pub fn settings(&self) -> &PreparationSettings {
137        self.settings
138    }
139
140    /// Should be called before any manual call to read_X_header
141    pub fn track_stack_depth_increase(&mut self) -> Result<(), PrepareError> {
142        Ok(self.decoder.track_stack_depth_increase()?)
143    }
144
145    pub fn read_header(
146        &mut self,
147        header: ExpectedTupleHeader,
148        expected_length: usize,
149    ) -> Result<(), PrepareError> {
150        match header {
151            ExpectedTupleHeader::EnumNoValueKind { discriminator } => {
152                self.decoder.read_expected_discriminator(discriminator)?;
153            }
154            ExpectedTupleHeader::EnumWithValueKind { discriminator } => {
155                self.read_and_check_value_kind(ValueKind::Enum)?;
156                self.decoder.read_expected_discriminator(discriminator)?;
157            }
158            ExpectedTupleHeader::TupleWithValueKind => {
159                self.read_and_check_value_kind(ValueKind::Tuple)?;
160            }
161            ExpectedTupleHeader::TupleNoValueKind => {}
162        }
163        self.decoder.read_and_check_size(expected_length)?;
164        Ok(())
165    }
166
167    pub fn read_enum_header(&mut self) -> Result<(u8, usize), PrepareError> {
168        self.read_and_check_value_kind(ValueKind::Enum)?;
169        let discriminator = self.decoder.read_discriminator()?;
170        let length = self.decoder.read_size()?;
171        Ok((discriminator, length))
172    }
173
174    pub fn read_array_header(
175        &mut self,
176        element_value_kind: ManifestValueKind,
177    ) -> Result<usize, PrepareError> {
178        self.read_and_check_value_kind(ValueKind::Array)?;
179        self.read_array_header_without_value_kind(element_value_kind)
180    }
181
182    pub fn read_array_header_without_value_kind(
183        &mut self,
184        element_value_kind: ManifestValueKind,
185    ) -> Result<usize, PrepareError> {
186        self.read_and_check_value_kind(element_value_kind)?;
187        Ok(self.decoder.read_size()?)
188    }
189
190    pub fn read_and_check_value_kind(
191        &mut self,
192        value_kind: ManifestValueKind,
193    ) -> Result<(), PrepareError> {
194        self.decoder.read_and_check_value_kind(value_kind)?;
195        Ok(())
196    }
197
198    /// Should be called after reading all the children following a manual read_X_header call
199    pub fn track_stack_depth_decrease(&mut self) -> Result<(), PrepareError> {
200        Ok(self.decoder.track_stack_depth_decrease()?)
201    }
202
203    pub fn decode<T: ManifestDecode>(&mut self) -> Result<T, PrepareError> {
204        Ok(self.decoder.decode()?)
205    }
206
207    pub fn decode_deeper_body_with_value_kind<T: ManifestDecode>(
208        &mut self,
209        value_kind: ManifestValueKind,
210    ) -> Result<T, PrepareError> {
211        Ok(self
212            .decoder
213            .decode_deeper_body_with_value_kind(value_kind)?)
214    }
215
216    pub fn get_offset(&self) -> usize {
217        self.decoder.get_offset()
218    }
219
220    pub fn get_slice_with_valid_bounds(&self, start_offset: usize, end_offset: usize) -> &[u8] {
221        &self.decoder.get_input_slice()[start_offset..end_offset]
222    }
223
224    pub fn get_input_slice(&self) -> &[u8] {
225        self.decoder.get_input_slice()
226    }
227
228    pub fn check_complete(self) -> Result<(), PrepareError> {
229        self.decoder.check_end()?;
230        Ok(())
231    }
232}