ab_transaction/
owned.rs

1mod builder_buffer;
2
3use crate::owned::builder_buffer::BuilderBuffer;
4use crate::{Transaction, TransactionHeader, TransactionSlot};
5use ab_aligned_buffer::SharedAlignedBuffer;
6use ab_contracts_io_type::trivial_type::TrivialType;
7use core::slice;
8
9#[derive(Debug, Default, Copy, Clone, TrivialType)]
10#[repr(C)]
11pub struct OwnedTransactionLengths {
12    pub read_slots: u16,
13    pub write_slots: u16,
14    pub payload: u32,
15    pub seal: u32,
16    /// Not used and must be set to `0`
17    pub padding: [u8; 12],
18}
19
20/// Errors for [`OwnedTransaction`]
21#[derive(Debug, thiserror::Error)]
22pub enum OwnedTransactionError {
23    /// Not enough bytes
24    #[error("Not enough bytes")]
25    NotEnoughBytes,
26    /// Payload is not a multiple of `u128`
27    #[error("Payload is not a multiple of `u128`")]
28    PayloadIsNotMultipleOfU128,
29    /// Expected number of bytes
30    #[error("Expected number of bytes: {actual} != {expected}")]
31    UnexpectedNumberOfBytes { actual: u32, expected: u32 },
32}
33
34/// An owned version of [`Transaction`].
35///
36/// It is correctly aligned in memory and well suited for sending and receiving over the network
37/// efficiently or storing in memory or on disk.
38///
39/// The internal layout of the owned transaction is following data structures concatenated as bytes
40/// (they are carefully picked to ensure alignment):
41/// * [`TransactionHeader`]
42/// * [`OwnedTransactionLengths`] (with values set to correspond to below contents
43/// * All read [`TransactionSlot`]
44/// * All write [`TransactionSlot`]
45/// * Payload as `u128`s
46/// * Seal as `u8`s
47#[derive(Debug, Clone)]
48pub struct OwnedTransaction {
49    buffer: SharedAlignedBuffer,
50}
51
52impl OwnedTransaction {
53    pub fn build(header: &TransactionHeader) -> OwnedTransactionBuilder {
54        OwnedTransactionBuilder {
55            buffer: BuilderBuffer::new(header),
56        }
57    }
58
59    /// Create an owned transaction from a buffer
60    pub fn from_buffer(buffer: SharedAlignedBuffer) -> Result<Self, OwnedTransactionError> {
61        if (buffer.len() as usize)
62            < size_of::<TransactionHeader>() + size_of::<OwnedTransactionLengths>()
63        {
64            return Err(OwnedTransactionError::NotEnoughBytes);
65        }
66
67        // SAFETY: Checked above that there are enough bytes and they are correctly aligned
68        let lengths = unsafe {
69            buffer
70                .as_ptr()
71                .add(size_of::<TransactionHeader>())
72                .cast::<OwnedTransactionLengths>()
73                .read()
74        };
75        let OwnedTransactionLengths {
76            read_slots,
77            write_slots,
78            payload,
79            seal,
80            padding: _,
81        } = lengths;
82
83        if payload % u128::SIZE != 0 {
84            return Err(OwnedTransactionError::PayloadIsNotMultipleOfU128);
85        }
86
87        let expected = (size_of::<TransactionHeader>() as u32
88            + size_of::<OwnedTransactionLengths>() as u32)
89            .saturating_add(u32::from(read_slots))
90            .saturating_add(u32::from(write_slots))
91            .saturating_add(payload)
92            .saturating_add(seal);
93
94        if buffer.len() != expected {
95            return Err(OwnedTransactionError::UnexpectedNumberOfBytes {
96                actual: buffer.len(),
97                expected,
98            });
99        }
100
101        Ok(Self { buffer })
102    }
103
104    // TODO: Implement
105    // pub fn from_transaction(transaction: Transaction<'_>) -> Result<Self, OwnedTransactionError> {
106    //     todo!()
107    // }
108
109    /// Inner buffer with owned transaction contents
110    pub fn buffer(&self) -> &SharedAlignedBuffer {
111        &self.buffer
112    }
113
114    pub fn transaction(&self) -> Transaction<'_> {
115        // SAFETY: All constructors ensure there are enough bytes and they are correctly aligned
116        let lengths = unsafe {
117            self.buffer
118                .as_ptr()
119                .add(size_of::<TransactionHeader>())
120                .cast::<OwnedTransactionLengths>()
121                .read()
122        };
123        let OwnedTransactionLengths {
124            read_slots,
125            write_slots,
126            payload,
127            seal,
128            padding: _,
129        } = lengths;
130
131        Transaction {
132            // SAFETY: Any bytes are valid for `TransactionHeader` and all constructors ensure there
133            // are enough bytes for header in the buffer
134            header: unsafe {
135                self.buffer
136                    .as_ptr()
137                    .cast::<TransactionHeader>()
138                    .as_ref_unchecked()
139            },
140            // SAFETY: Any bytes are valid for `TransactionSlot` and all constructors ensure there
141            // are enough bytes for read slots in the buffer
142            read_slots: unsafe {
143                slice::from_raw_parts(
144                    self.buffer
145                        .as_ptr()
146                        .add(size_of::<TransactionHeader>())
147                        .add(size_of::<OwnedTransactionLengths>())
148                        .cast::<TransactionSlot>(),
149                    usize::from(read_slots),
150                )
151            },
152            // SAFETY: Any bytes are valid for `TransactionSlot` and all constructors ensure there
153            // are enough bytes for write slots in the buffer
154            write_slots: unsafe {
155                slice::from_raw_parts(
156                    self.buffer
157                        .as_ptr()
158                        .add(size_of::<TransactionHeader>())
159                        .add(size_of::<OwnedTransactionLengths>())
160                        .cast::<TransactionSlot>()
161                        .add(usize::from(read_slots)),
162                    usize::from(write_slots),
163                )
164            },
165            // SAFETY: Any bytes are valid for `payload` and all constructors ensure there are
166            // enough bytes for payload in the buffer
167            payload: unsafe {
168                slice::from_raw_parts(
169                    self.buffer
170                        .as_ptr()
171                        .add(size_of::<TransactionHeader>())
172                        .add(size_of::<OwnedTransactionLengths>())
173                        .add(
174                            size_of::<TransactionSlot>()
175                                * (usize::from(read_slots) + usize::from(write_slots)),
176                        )
177                        .cast::<u128>(),
178                    payload as usize,
179                )
180            },
181            // SAFETY: Any bytes are valid for `seal` and all constructors ensure there are
182            // enough bytes for seal in the buffer
183            seal: unsafe {
184                slice::from_raw_parts(
185                    self.buffer
186                        .as_ptr()
187                        .add(size_of::<TransactionHeader>())
188                        .add(size_of::<OwnedTransactionLengths>())
189                        .add(
190                            size_of::<TransactionSlot>()
191                                * (usize::from(read_slots) + usize::from(write_slots))
192                                + payload as usize,
193                        ),
194                    seal as usize,
195                )
196            },
197        }
198    }
199}
200
201/// Errors for [`OwnedTransactionBuilder`]
202#[derive(Debug, thiserror::Error)]
203pub enum OwnedTransactionBuilderError {
204    /// Too many read slots
205    #[error("Too many read slots")]
206    TooManyReadSlots,
207    /// Too many write slots
208    #[error("Too many write slots")]
209    TooManyWriteSlots,
210    /// Payload too large
211    #[error("Payload too large")]
212    PayloadTooLarge,
213    /// Payload is not a multiple of `u128`
214    #[error("Payload is not a multiple of `u128`")]
215    PayloadIsNotMultipleOfU128,
216    /// Seal too large
217    #[error("Seal too large")]
218    SealTooLarge,
219    /// Transaction too large
220    #[error("Transaction too large")]
221    TransactionTooLarge,
222}
223
224#[derive(Debug, Clone)]
225pub struct OwnedTransactionBuilder {
226    buffer: BuilderBuffer,
227}
228
229impl OwnedTransactionBuilder {
230    pub fn with_read_slot(
231        mut self,
232        slot: &TransactionSlot,
233    ) -> Result<OwnedTransactionBuilderWithReadSlot, OwnedTransactionBuilderError> {
234        self.buffer.append_read_slots(slice::from_ref(slot))?;
235        Ok(OwnedTransactionBuilderWithReadSlot {
236            buffer: self.buffer,
237        })
238    }
239
240    pub fn with_read_slots(
241        mut self,
242        slots: &[TransactionSlot],
243    ) -> Result<OwnedTransactionBuilderWithReadSlot, OwnedTransactionBuilderError> {
244        self.buffer.append_read_slots(slots)?;
245        Ok(OwnedTransactionBuilderWithReadSlot {
246            buffer: self.buffer,
247        })
248    }
249
250    pub fn with_write_slot(
251        mut self,
252        slot: &TransactionSlot,
253    ) -> Result<OwnedTransactionBuilderWithWriteSlot, OwnedTransactionBuilderError> {
254        self.buffer.append_write_slots(slice::from_ref(slot))?;
255        Ok(OwnedTransactionBuilderWithWriteSlot {
256            buffer: self.buffer,
257        })
258    }
259
260    pub fn with_write_slots(
261        mut self,
262        slots: &[TransactionSlot],
263    ) -> Result<OwnedTransactionBuilderWithWriteSlot, OwnedTransactionBuilderError> {
264        self.buffer.append_write_slots(slots)?;
265        Ok(OwnedTransactionBuilderWithWriteSlot {
266            buffer: self.buffer,
267        })
268    }
269
270    pub fn with_payload(
271        mut self,
272        payload: &[u8],
273    ) -> Result<OwnedTransactionBuilderWithPayload, OwnedTransactionBuilderError> {
274        self.buffer.append_payload(payload)?;
275        Ok(OwnedTransactionBuilderWithPayload {
276            buffer: self.buffer,
277        })
278    }
279
280    pub fn with_seal(
281        mut self,
282        seal: &[u8],
283    ) -> Result<OwnedTransaction, OwnedTransactionBuilderError> {
284        self.buffer.append_seal(seal)?;
285        self.finish()
286    }
287
288    pub fn finish(self) -> Result<OwnedTransaction, OwnedTransactionBuilderError> {
289        let buffer = self.buffer.finish()?.into_shared();
290        Ok(OwnedTransaction { buffer })
291    }
292}
293
294#[derive(Debug, Clone)]
295pub struct OwnedTransactionBuilderWithReadSlot {
296    buffer: BuilderBuffer,
297}
298
299impl OwnedTransactionBuilderWithReadSlot {
300    pub fn with_read_slot(
301        mut self,
302        slot: &TransactionSlot,
303    ) -> Result<Self, OwnedTransactionBuilderError> {
304        self.buffer.append_read_slots(slice::from_ref(slot))?;
305        Ok(Self {
306            buffer: self.buffer,
307        })
308    }
309
310    pub fn with_read_slots(
311        mut self,
312        slots: &[TransactionSlot],
313    ) -> Result<Self, OwnedTransactionBuilderError> {
314        self.buffer.append_read_slots(slots)?;
315        Ok(Self {
316            buffer: self.buffer,
317        })
318    }
319
320    pub fn with_write_slot(
321        mut self,
322        slot: &TransactionSlot,
323    ) -> Result<OwnedTransactionBuilderWithWriteSlot, OwnedTransactionBuilderError> {
324        self.buffer.append_write_slots(slice::from_ref(slot))?;
325        Ok(OwnedTransactionBuilderWithWriteSlot {
326            buffer: self.buffer,
327        })
328    }
329
330    pub fn with_write_slots(
331        mut self,
332        slots: &[TransactionSlot],
333    ) -> Result<OwnedTransactionBuilderWithWriteSlot, OwnedTransactionBuilderError> {
334        self.buffer.append_write_slots(slots)?;
335        Ok(OwnedTransactionBuilderWithWriteSlot {
336            buffer: self.buffer,
337        })
338    }
339
340    pub fn with_payload(
341        mut self,
342        payload: &[u8],
343    ) -> Result<OwnedTransactionBuilderWithPayload, OwnedTransactionBuilderError> {
344        self.buffer.append_payload(payload)?;
345        Ok(OwnedTransactionBuilderWithPayload {
346            buffer: self.buffer,
347        })
348    }
349
350    pub fn with_seal(
351        mut self,
352        seal: &[u8],
353    ) -> Result<OwnedTransaction, OwnedTransactionBuilderError> {
354        self.buffer.append_seal(seal)?;
355        self.finish()
356    }
357
358    pub fn finish(self) -> Result<OwnedTransaction, OwnedTransactionBuilderError> {
359        let buffer = self.buffer.finish()?.into_shared();
360        Ok(OwnedTransaction { buffer })
361    }
362}
363
364#[derive(Debug, Clone)]
365pub struct OwnedTransactionBuilderWithWriteSlot {
366    buffer: BuilderBuffer,
367}
368
369impl OwnedTransactionBuilderWithWriteSlot {
370    pub fn with_write_slot(
371        mut self,
372        slot: &TransactionSlot,
373    ) -> Result<Self, OwnedTransactionBuilderError> {
374        self.buffer.append_write_slots(slice::from_ref(slot))?;
375        Ok(Self {
376            buffer: self.buffer,
377        })
378    }
379
380    pub fn with_write_slots(
381        mut self,
382        slots: &[TransactionSlot],
383    ) -> Result<Self, OwnedTransactionBuilderError> {
384        self.buffer.append_write_slots(slots)?;
385        Ok(Self {
386            buffer: self.buffer,
387        })
388    }
389
390    pub fn with_payload(
391        mut self,
392        payload: &[u8],
393    ) -> Result<OwnedTransactionBuilderWithPayload, OwnedTransactionBuilderError> {
394        self.buffer.append_payload(payload)?;
395        Ok(OwnedTransactionBuilderWithPayload {
396            buffer: self.buffer,
397        })
398    }
399
400    pub fn with_seal(
401        mut self,
402        seal: &[u8],
403    ) -> Result<OwnedTransaction, OwnedTransactionBuilderError> {
404        self.buffer.append_seal(seal)?;
405        self.finish()
406    }
407
408    pub fn finish(self) -> Result<OwnedTransaction, OwnedTransactionBuilderError> {
409        let buffer = self.buffer.finish()?.into_shared();
410        Ok(OwnedTransaction { buffer })
411    }
412}
413
414#[derive(Debug, Clone)]
415pub struct OwnedTransactionBuilderWithPayload {
416    buffer: BuilderBuffer,
417}
418
419impl OwnedTransactionBuilderWithPayload {
420    pub fn with_payload(mut self, payload: &[u8]) -> Result<Self, OwnedTransactionBuilderError> {
421        self.buffer.append_payload(payload)?;
422        Ok(Self {
423            buffer: self.buffer,
424        })
425    }
426
427    pub fn with_seal(
428        mut self,
429        seal: &[u8],
430    ) -> Result<OwnedTransaction, OwnedTransactionBuilderError> {
431        self.buffer.append_seal(seal)?;
432        self.finish()
433    }
434
435    pub fn finish(self) -> Result<OwnedTransaction, OwnedTransactionBuilderError> {
436        let buffer = self.buffer.finish()?.into_shared();
437        Ok(OwnedTransaction { buffer })
438    }
439}