ab_core_primitives/transaction/
owned.rs1use crate::transaction::{
4 SerializedTransactionLengths, Transaction, TransactionHeader, TransactionSlot,
5};
6use ab_aligned_buffer::{OwnedAlignedBuffer, SharedAlignedBuffer};
7use ab_io_type::trivial_type::TrivialType;
8use core::slice;
9
10#[derive(Debug, thiserror::Error)]
12pub enum OwnedTransactionError {
13 #[error("Too many read slots")]
15 TooManyReadSlots,
16 #[error("Too many write slots")]
18 TooManyWriteSlots,
19 #[error("The payload is too large")]
21 PayloadTooLarge,
22 #[error("The payload is not a multiple of `u128`")]
24 PayloadIsNotMultipleOfU128,
25 #[error("The leal too large")]
27 SealTooLarge,
28 #[error("The transaction is too large")]
30 TransactionTooLarge,
31 #[error("Not enough bytes")]
33 NotEnoughBytes,
34 #[error("Invalid padding")]
36 InvalidPadding,
37 #[error("Expected number of bytes: {actual} != {expected}")]
39 UnexpectedNumberOfBytes {
40 actual: u32,
42 expected: u32,
44 },
45}
46
47#[derive(Debug, Clone)]
52pub struct OwnedTransaction {
53 buffer: SharedAlignedBuffer,
54}
55
56impl OwnedTransaction {
57 pub fn from_parts(
59 header: &TransactionHeader,
60 read_slots: &[TransactionSlot],
61 write_slots: &[TransactionSlot],
62 payload: &[u128],
63 seal: &[u8],
64 ) -> Result<Self, OwnedTransactionError> {
65 let mut buffer = OwnedAlignedBuffer::with_capacity(
66 (TransactionHeader::SIZE + SerializedTransactionLengths::SIZE)
67 .saturating_add(size_of_val(read_slots) as u32)
68 .saturating_add(size_of_val(write_slots) as u32)
69 .saturating_add(size_of_val(payload) as u32)
70 .saturating_add(size_of_val(seal) as u32),
71 );
72
73 Self::from_parts_into(header, read_slots, write_slots, payload, seal, &mut buffer)?;
74
75 Ok(Self {
76 buffer: buffer.into_shared(),
77 })
78 }
79
80 pub fn from_parts_into(
82 header: &TransactionHeader,
83 read_slots: &[TransactionSlot],
84 write_slots: &[TransactionSlot],
85 payload: &[u128],
86 seal: &[u8],
87 buffer: &mut OwnedAlignedBuffer,
88 ) -> Result<(), OwnedTransactionError> {
89 const _: () = {
90 assert!(
92 size_of::<TransactionHeader>() % align_of::<SerializedTransactionLengths>() == 0
93 );
94 };
95
96 let transaction_lengths = SerializedTransactionLengths {
97 read_slots: read_slots
98 .len()
99 .try_into()
100 .map_err(|_error| OwnedTransactionError::TooManyReadSlots)?,
101 write_slots: read_slots
102 .len()
103 .try_into()
104 .map_err(|_error| OwnedTransactionError::TooManyWriteSlots)?,
105 payload: size_of_val(payload)
106 .try_into()
107 .map_err(|_error| OwnedTransactionError::PayloadTooLarge)?,
108 seal: seal
109 .len()
110 .try_into()
111 .map_err(|_error| OwnedTransactionError::SealTooLarge)?,
112 padding: [0; _],
113 };
114
115 let true = buffer.append(header.as_bytes()) else {
116 unreachable!("Always fits into `u32`");
117 };
118 let true = buffer.append(transaction_lengths.as_bytes()) else {
119 unreachable!("Always fits into `u32`");
120 };
121
122 const _: () = {
123 assert!(
126 (size_of::<TransactionHeader>() + size_of::<SerializedTransactionLengths>())
127 % align_of::<TransactionSlot>()
128 == 0
129 );
130 };
131 if transaction_lengths.read_slots > 0 {
132 if !buffer.append(unsafe {
134 slice::from_raw_parts(read_slots.as_ptr().cast::<u8>(), size_of_val(read_slots))
135 }) {
136 return Err(OwnedTransactionError::TransactionTooLarge);
137 }
138 }
139 if transaction_lengths.write_slots > 0 {
140 if !buffer.append(unsafe {
142 slice::from_raw_parts(write_slots.as_ptr().cast::<u8>(), size_of_val(write_slots))
143 }) {
144 return Err(OwnedTransactionError::TransactionTooLarge);
145 }
146 }
147
148 const _: () = {
149 assert!(
152 (size_of::<TransactionHeader>() + size_of::<SerializedTransactionLengths>())
153 % align_of::<u128>()
154 == 0
155 );
156 assert!(
157 (size_of::<TransactionHeader>()
158 + size_of::<SerializedTransactionLengths>()
159 + size_of::<TransactionSlot>())
160 % align_of::<u128>()
161 == 0
162 );
163 };
164 if transaction_lengths.payload > 0 {
165 if transaction_lengths.payload % u128::SIZE != 0 {
166 return Err(OwnedTransactionError::PayloadIsNotMultipleOfU128);
167 }
168
169 if !buffer.append(unsafe {
171 slice::from_raw_parts(payload.as_ptr().cast::<u8>(), size_of_val(payload))
172 }) {
173 return Err(OwnedTransactionError::TransactionTooLarge);
174 }
175 }
176
177 const _: () = {
178 assert!(
181 (size_of::<TransactionHeader>() + size_of::<SerializedTransactionLengths>())
182 % align_of::<u128>()
183 == 0
184 );
185 assert!(
186 (size_of::<TransactionHeader>()
187 + size_of::<SerializedTransactionLengths>()
188 + size_of::<TransactionSlot>())
189 % align_of::<u128>()
190 == 0
191 );
192 };
193 if transaction_lengths.seal > 0 && !buffer.append(seal) {
194 return Err(OwnedTransactionError::TransactionTooLarge);
195 }
196
197 Ok(())
198 }
199
200 #[inline(always)]
202 pub fn from_transaction(transaction: Transaction<'_>) -> Result<Self, OwnedTransactionError> {
203 Self::from_parts(
204 transaction.header,
205 transaction.read_slots,
206 transaction.write_slots,
207 transaction.payload,
208 transaction.seal,
209 )
210 }
211
212 pub fn from_buffer(buffer: SharedAlignedBuffer) -> Result<Self, OwnedTransactionError> {
214 if (buffer.len() as usize)
215 < size_of::<TransactionHeader>() + size_of::<SerializedTransactionLengths>()
216 {
217 return Err(OwnedTransactionError::NotEnoughBytes);
218 }
219
220 let lengths = unsafe {
222 buffer
223 .as_ptr()
224 .add(size_of::<TransactionHeader>())
225 .cast::<SerializedTransactionLengths>()
226 .read()
227 };
228 let SerializedTransactionLengths {
229 read_slots,
230 write_slots,
231 payload,
232 seal,
233 padding,
234 } = lengths;
235
236 if padding != [0; _] {
237 return Err(OwnedTransactionError::InvalidPadding);
238 }
239
240 if payload % u128::SIZE != 0 {
241 return Err(OwnedTransactionError::PayloadIsNotMultipleOfU128);
242 }
243
244 let expected = (size_of::<TransactionHeader>() as u32
245 + size_of::<SerializedTransactionLengths>() as u32)
246 .saturating_add(u32::from(read_slots))
247 .saturating_add(u32::from(write_slots))
248 .saturating_add(payload)
249 .saturating_add(seal);
250
251 if buffer.len() != expected {
252 return Err(OwnedTransactionError::UnexpectedNumberOfBytes {
253 actual: buffer.len(),
254 expected,
255 });
256 }
257
258 Ok(Self { buffer })
259 }
260
261 pub fn buffer(&self) -> &SharedAlignedBuffer {
263 &self.buffer
264 }
265
266 pub fn transaction(&self) -> Transaction<'_> {
268 unsafe { Transaction::from_bytes_unchecked(self.buffer.as_slice()) }
270 }
271}