1use crate::eip4844::{
2 utils::WholeFe, Blob, BYTES_PER_BLOB, FIELD_ELEMENTS_PER_BLOB, FIELD_ELEMENT_BYTES_USIZE,
3};
4use alloc::vec::Vec;
5use core::cmp;
6
7#[cfg(any(feature = "kzg", feature = "arbitrary"))]
8use crate::eip4844::BlobTransactionSidecar;
9#[cfg(feature = "kzg")]
10use crate::{eip4844::env_settings::EnvKzgSettings, eip7594::BlobTransactionSidecarEip7594};
11
12#[cfg(feature = "kzg")]
18pub trait BuildableSidecar {
19 fn build_with_settings(
21 blobs: Vec<Blob>,
22 settings: &c_kzg::KzgSettings,
23 ) -> Result<Self, c_kzg::Error>
24 where
25 Self: Sized;
26
27 fn build(blobs: Vec<Blob>) -> Result<Self, c_kzg::Error>
30 where
31 Self: Sized,
32 {
33 Self::build_with_settings(blobs, EnvKzgSettings::Default.get())
34 }
35}
36
37#[cfg(feature = "kzg")]
38impl BuildableSidecar for BlobTransactionSidecar {
39 fn build_with_settings(
40 blobs: Vec<Blob>,
41 settings: &c_kzg::KzgSettings,
42 ) -> Result<Self, c_kzg::Error> {
43 Self::try_from_blobs_with_settings(blobs, settings)
44 }
45}
46
47#[cfg(feature = "kzg")]
48impl BuildableSidecar for BlobTransactionSidecarEip7594 {
49 fn build_with_settings(
50 blobs: Vec<Blob>,
51 settings: &c_kzg::KzgSettings,
52 ) -> Result<Self, c_kzg::Error> {
53 Self::try_from_blobs_with_settings(blobs, settings)
54 }
55}
56
57#[derive(Clone, Debug)]
61pub struct PartialSidecar {
62 blobs: Vec<Blob>,
64 fe: usize,
66}
67
68impl Default for PartialSidecar {
69 fn default() -> Self {
70 Self::new()
71 }
72}
73
74impl PartialSidecar {
75 pub fn new() -> Self {
80 Self::with_capacity(2)
81 }
82
83 pub fn with_capacity(capacity: usize) -> Self {
86 let mut blobs = Vec::with_capacity(capacity);
87 blobs.push(Blob::new([0u8; BYTES_PER_BLOB]));
88 Self { blobs, fe: 0 }
89 }
90
91 #[allow(clippy::missing_const_for_fn)]
93 pub fn blobs(&self) -> &[Blob] {
94 &self.blobs
95 }
96
97 const fn free_fe(&self) -> usize {
99 self.blobs.len() * FIELD_ELEMENTS_PER_BLOB as usize - self.fe
100 }
101
102 pub const fn len(&self) -> usize {
107 self.fe * 32
108 }
109
110 pub const fn is_empty(&self) -> bool {
112 self.fe == 0
113 }
114
115 fn push_empty_blob(&mut self) {
117 self.blobs.push(Blob::new([0u8; BYTES_PER_BLOB]));
118 }
119
120 pub fn alloc_fes(&mut self, required_fe: usize) {
122 while self.free_fe() < required_fe {
123 self.push_empty_blob()
124 }
125 }
126
127 const fn fe_in_current_blob(&self) -> usize {
129 self.fe % FIELD_ELEMENTS_PER_BLOB as usize
130 }
131
132 const fn first_unused_fe_index_in_current_blob(&self) -> usize {
134 self.fe_in_current_blob()
135 }
136
137 fn current_blob_mut(&mut self) -> &mut Blob {
139 let last_unused_blob_index = self.fe / FIELD_ELEMENTS_PER_BLOB as usize;
140 self.blobs.get_mut(last_unused_blob_index).expect("never empty")
141 }
142
143 fn fe_at_mut(&mut self, index: usize) -> &mut [u8] {
146 &mut self.current_blob_mut()[index * 32..(index + 1) * 32]
147 }
148
149 fn next_unused_fe_mut(&mut self) -> &mut [u8] {
151 self.fe_at_mut(self.first_unused_fe_index_in_current_blob())
152 }
153
154 pub fn ingest_valid_fe(&mut self, data: WholeFe<'_>) {
156 self.alloc_fes(1);
157 self.next_unused_fe_mut().copy_from_slice(data.as_ref());
158 self.fe += 1;
159 }
160
161 pub fn ingest_partial_fe(&mut self, data: &[u8]) {
168 self.alloc_fes(1);
169 let fe = self.next_unused_fe_mut();
170 fe[1..1 + data.len()].copy_from_slice(data);
171 self.fe += 1;
172 }
173}
174
175pub trait SidecarCoder {
189 fn required_fe(&self, data: &[u8]) -> usize;
192
193 fn code(&mut self, builder: &mut PartialSidecar, data: &[u8]);
195
196 fn finish(self, builder: &mut PartialSidecar);
200
201 fn decode_all(&mut self, blobs: &[Blob]) -> Option<Vec<Vec<u8>>>;
203}
204
205#[derive(Clone, Copy, Debug, Default)]
230#[non_exhaustive]
231pub struct SimpleCoder;
232
233impl SimpleCoder {
234 fn decode_one<'a>(mut fes: impl Iterator<Item = WholeFe<'a>>) -> Result<Option<Vec<u8>>, ()> {
240 let Some(first) = fes.next() else {
241 return Ok(None);
242 };
243 let mut num_bytes = u64::from_be_bytes(first.as_ref()[1..9].try_into().unwrap()) as usize;
244
245 if num_bytes == 0 {
247 return Ok(None);
248 }
249
250 const MAX_ALLOCATION_SIZE: usize = 2_097_152; if num_bytes > MAX_ALLOCATION_SIZE {
253 return Err(());
254 }
255
256 let mut res = Vec::with_capacity(num_bytes);
257 while num_bytes > 0 {
258 let to_copy = cmp::min(31, num_bytes);
259 let fe = fes.next().ok_or(())?;
260 res.extend_from_slice(&fe.as_ref()[1..1 + to_copy]);
261 num_bytes -= to_copy;
262 }
263 Ok(Some(res))
264 }
265}
266
267impl SidecarCoder for SimpleCoder {
268 fn required_fe(&self, data: &[u8]) -> usize {
269 data.len().div_ceil(31) + 1
270 }
271
272 fn code(&mut self, builder: &mut PartialSidecar, mut data: &[u8]) {
273 if data.is_empty() {
274 return;
275 }
276
277 builder.ingest_partial_fe(&(data.len() as u64).to_be_bytes());
279
280 while !data.is_empty() {
282 let (left, right) = data.split_at(cmp::min(31, data.len()));
283 builder.ingest_partial_fe(left);
284 data = right
285 }
286 }
287
288 fn finish(self, _builder: &mut PartialSidecar) {}
290
291 fn decode_all(&mut self, blobs: &[Blob]) -> Option<Vec<Vec<u8>>> {
292 if blobs.is_empty() {
293 return None;
294 }
295
296 if blobs
297 .iter()
298 .flat_map(|blob| blob.chunks(FIELD_ELEMENT_BYTES_USIZE).map(WholeFe::new))
299 .any(|fe| fe.is_none())
300 {
301 return None;
302 }
303
304 let mut fes = blobs
305 .iter()
306 .flat_map(|blob| blob.chunks(FIELD_ELEMENT_BYTES_USIZE).map(WholeFe::new_unchecked));
307
308 let mut res = Vec::new();
309 loop {
310 match Self::decode_one(&mut fes) {
311 Ok(Some(data)) => res.push(data),
312 Ok(None) => break,
313 Err(()) => return None,
314 }
315 }
316 Some(res)
317 }
318}
319
320#[derive(Clone, Debug)]
328pub struct SidecarBuilder<T = SimpleCoder> {
329 inner: PartialSidecar,
331 coder: T,
333}
334
335impl<T> Default for SidecarBuilder<T>
336where
337 T: Default + SidecarCoder,
338{
339 fn default() -> Self {
340 Self::new()
341 }
342}
343
344#[cfg(feature = "arbitrary")]
345impl<'a, T: arbitrary::Arbitrary<'a> + Clone> SidecarBuilder<T> {
346 pub fn build_arbitrary(&self) -> BlobTransactionSidecar {
348 <BlobTransactionSidecar as arbitrary::Arbitrary>::arbitrary(
349 &mut arbitrary::Unstructured::new(&[]),
350 )
351 .unwrap()
352 }
353}
354
355impl<T: SidecarCoder + Default> SidecarBuilder<T> {
356 pub fn new() -> Self {
362 T::default().into()
363 }
364
365 pub fn from_slice(data: &[u8]) -> Self {
368 Self::from_coder_and_data(T::default(), data)
369 }
370
371 pub fn with_capacity(capacity: usize) -> Self {
374 Self::from_coder_and_capacity(T::default(), capacity)
375 }
376}
377
378impl<T: SidecarCoder> SidecarBuilder<T> {
379 pub fn from_coder_and_capacity(coder: T, capacity: usize) -> Self {
382 Self { inner: PartialSidecar::with_capacity(capacity), coder }
383 }
384
385 pub const fn len(&self) -> usize {
390 self.inner.len()
391 }
392
393 pub const fn is_empty(&self) -> bool {
395 self.inner.is_empty()
396 }
397
398 pub fn from_coder_and_data(coder: T, data: &[u8]) -> Self {
400 let required_fe = coder.required_fe(data);
401 let mut this = Self::from_coder_and_capacity(
402 coder,
403 required_fe.div_ceil(FIELD_ELEMENTS_PER_BLOB as usize),
404 );
405 this.ingest(data);
406 this
407 }
408
409 pub fn ingest(&mut self, data: &[u8]) {
411 self.inner.alloc_fes(self.coder.required_fe(data));
412 self.coder.code(&mut self.inner, data);
413 }
414
415 #[cfg(feature = "kzg")]
423 pub fn build<U: BuildableSidecar>(self) -> Result<U, c_kzg::Error> {
424 self.build_with_settings(EnvKzgSettings::Default.get())
425 }
426
427 #[cfg(feature = "kzg")]
434 pub fn build_with_settings<U: BuildableSidecar>(
435 self,
436 settings: &c_kzg::KzgSettings,
437 ) -> Result<U, c_kzg::Error> {
438 U::build_with_settings(self.inner.blobs, settings)
439 }
440
441 #[cfg(feature = "kzg")]
443 pub fn build_4844_with_settings(
444 self,
445 settings: &c_kzg::KzgSettings,
446 ) -> Result<BlobTransactionSidecar, c_kzg::Error> {
447 BlobTransactionSidecar::build_with_settings(self.inner.blobs, settings)
448 }
449
450 #[cfg(feature = "kzg")]
453 pub fn build_4844(self) -> Result<BlobTransactionSidecar, c_kzg::Error> {
454 self.build_4844_with_settings(EnvKzgSettings::Default.get())
455 }
456
457 pub fn take(self) -> Vec<Blob> {
459 self.inner.blobs
460 }
461
462 #[cfg(feature = "kzg")]
465 pub fn build_7594(self) -> Result<BlobTransactionSidecarEip7594, c_kzg::Error> {
466 self.build_7594_with_settings(EnvKzgSettings::Default.get())
467 }
468
469 #[cfg(feature = "kzg")]
471 pub fn build_7594_with_settings(
472 self,
473 settings: &c_kzg::KzgSettings,
474 ) -> Result<BlobTransactionSidecarEip7594, c_kzg::Error> {
475 BlobTransactionSidecarEip7594::build_with_settings(self.inner.blobs, settings)
476 }
477}
478
479impl<T: SidecarCoder> From<T> for SidecarBuilder<T> {
480 fn from(coder: T) -> Self {
487 Self::from_coder_and_capacity(coder, 1)
488 }
489}
490
491impl<T, R> FromIterator<R> for SidecarBuilder<T>
492where
493 T: SidecarCoder + Default,
494 R: AsRef<[u8]>,
495{
496 fn from_iter<I: IntoIterator<Item = R>>(iter: I) -> Self {
497 let mut this = Self::new();
498 for data in iter {
499 this.ingest(data.as_ref());
500 }
501 this
502 }
503}
504
505#[cfg(test)]
506mod tests {
507 use super::*;
508 use crate::eip4844::USABLE_BYTES_PER_BLOB;
509
510 #[test]
511 fn ingestion_strategy() {
512 let mut builder = PartialSidecar::new();
513 let data = &[
514 vec![1u8; 32],
515 vec![2u8; 372],
516 vec![3u8; 17],
517 vec![4u8; 5],
518 vec![5u8; 126_945],
519 vec![6u8; 2 * 126_945],
520 ];
521
522 data.iter().for_each(|data| SimpleCoder.code(&mut builder, data.as_slice()));
523
524 let decoded = SimpleCoder.decode_all(builder.blobs()).unwrap();
525 assert_eq!(decoded, data);
526 }
527
528 #[test]
529 fn big_ingestion_strategy() {
530 let data = vec![1u8; 126_945];
531 let builder = SidecarBuilder::<SimpleCoder>::from_slice(&data);
532
533 let blobs = builder.take();
534 let decoded = SimpleCoder.decode_all(&blobs).unwrap().concat();
535
536 assert_eq!(decoded, data);
537 }
538
539 #[test]
540 fn decode_all_rejects_invalid_data() {
541 assert_eq!(SimpleCoder.decode_all(&[]), None);
542 assert_eq!(SimpleCoder.decode_all(&[Blob::new([0xffu8; BYTES_PER_BLOB])]), None);
543 }
544
545 #[test]
546 fn it_ingests() {
547 let data = [
549 vec![1u8; 32],
550 vec![2u8; 372],
551 vec![3u8; 17],
552 vec![4u8; 5],
553 vec![5u8; USABLE_BYTES_PER_BLOB + 2],
554 ];
555
556 let mut builder = data.iter().collect::<SidecarBuilder<SimpleCoder>>();
557
558 let expected_fe = data.iter().map(|d| SimpleCoder.required_fe(d)).sum::<usize>();
559 assert_eq!(builder.len(), expected_fe * 32);
560
561 builder.ingest(b"hello");
563 assert_eq!(builder.len(), expected_fe * 32 + 64);
564 }
565}