1#![doc(
12 html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
13 html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
14 issue_tracker_base_url = "https://github.com/SeismicSystems/seismic-reth/issues/"
15)]
16#![cfg_attr(not(test), warn(unused_crate_dependencies))]
17#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
18#![cfg_attr(not(feature = "std"), no_std)]
19
20extern crate alloc;
21
22pub use reth_codecs_derive::*;
23use serde as _;
24
25use alloy_primitives::{aliases::U96, Address, Bloom, Bytes, FixedBytes, U256};
26use bytes::{Buf, BufMut};
27
28use alloc::{
29 borrow::{Cow, ToOwned},
30 vec::Vec,
31};
32
33#[cfg(feature = "test-utils")]
34pub mod alloy;
35
36#[cfg(not(feature = "test-utils"))]
37#[cfg(any(test, feature = "alloy"))]
38mod alloy;
39
40pub mod txtype;
41
42#[cfg(any(test, feature = "test-utils"))]
43pub mod test_utils;
44
45#[doc(hidden)]
47#[path = "private.rs"]
48pub mod __private;
49
50pub trait Compact: Sized {
74 fn to_compact<B>(&self, buf: &mut B) -> usize
76 where
77 B: bytes::BufMut + AsMut<[u8]>;
78
79 fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]);
86
87 #[inline]
89 fn specialized_to_compact<B>(&self, buf: &mut B) -> usize
90 where
91 B: bytes::BufMut + AsMut<[u8]>,
92 {
93 self.to_compact(buf)
94 }
95
96 #[inline]
98 fn specialized_from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
99 Self::from_compact(buf, len)
100 }
101}
102
103impl Compact for alloc::string::String {
104 fn to_compact<B>(&self, buf: &mut B) -> usize
105 where
106 B: bytes::BufMut + AsMut<[u8]>,
107 {
108 self.as_bytes().to_compact(buf)
109 }
110
111 fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
112 let (vec, buf) = Vec::<u8>::from_compact(buf, len);
113 let string = Self::from_utf8(vec).unwrap(); (string, buf)
115 }
116}
117
118impl<T: Compact> Compact for &T {
119 fn to_compact<B>(&self, buf: &mut B) -> usize
120 where
121 B: BufMut + AsMut<[u8]>,
122 {
123 (*self).to_compact(buf)
124 }
125
126 fn from_compact(_: &[u8], _: usize) -> (Self, &[u8]) {
127 unimplemented!()
128 }
129}
130
131pub type CompactPlaceholder = ();
133
134impl Compact for CompactPlaceholder {
135 #[inline]
136 fn to_compact<B>(&self, _: &mut B) -> usize
137 where
138 B: bytes::BufMut + AsMut<[u8]>,
139 {
140 0
141 }
142
143 #[inline]
144 fn from_compact(buf: &[u8], _: usize) -> (Self, &[u8]) {
145 ((), buf)
146 }
147}
148
149macro_rules! impl_uint_compact {
150 ($($name:tt),+) => {
151 $(
152 impl Compact for $name {
153 #[inline]
154 fn to_compact<B>(&self, buf: &mut B) -> usize
155 where B: bytes::BufMut + AsMut<[u8]>
156 {
157 let leading = self.leading_zeros() as usize / 8;
158 buf.put_slice(&self.to_be_bytes()[leading..]);
159 core::mem::size_of::<$name>() - leading
160 }
161
162 #[inline]
163 fn from_compact(mut buf: &[u8], len: usize) -> (Self, &[u8]) {
164 if len == 0 {
165 return (0, buf);
166 }
167
168 let mut arr = [0; core::mem::size_of::<$name>()];
169 arr[core::mem::size_of::<$name>() - len..].copy_from_slice(&buf[..len]);
170 buf.advance(len);
171 ($name::from_be_bytes(arr), buf)
172 }
173 }
174 )+
175 };
176}
177
178impl_uint_compact!(u8, u64, u128);
179
180impl<T> Compact for Vec<T>
181where
182 T: Compact,
183{
184 #[inline]
186 fn to_compact<B>(&self, buf: &mut B) -> usize
187 where
188 B: bytes::BufMut + AsMut<[u8]>,
189 {
190 self.as_slice().to_compact(buf)
191 }
192
193 #[inline]
194 fn from_compact(buf: &[u8], _: usize) -> (Self, &[u8]) {
195 let (length, mut buf) = decode_varuint(buf);
196 let mut list = Self::with_capacity(length);
197 for _ in 0..length {
198 let len;
199 (len, buf) = decode_varuint(buf);
200
201 let (element, _) = T::from_compact(&buf[..len], len);
202 buf.advance(len);
203
204 list.push(element);
205 }
206
207 (list, buf)
208 }
209
210 #[inline]
212 fn specialized_to_compact<B>(&self, buf: &mut B) -> usize
213 where
214 B: bytes::BufMut + AsMut<[u8]>,
215 {
216 self.as_slice().specialized_to_compact(buf)
217 }
218
219 #[inline]
221 fn specialized_from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
222 let (length, mut buf) = decode_varuint(buf);
223 let mut list = Self::with_capacity(length);
224
225 for _ in 0..length {
226 let element;
227 (element, buf) = T::from_compact(buf, len);
228 list.push(element);
229 }
230
231 (list, buf)
232 }
233}
234
235impl<T> Compact for &[T]
236where
237 T: Compact,
238{
239 #[inline]
241 fn to_compact<B>(&self, buf: &mut B) -> usize
242 where
243 B: bytes::BufMut + AsMut<[u8]>,
244 {
245 encode_varuint(self.len(), buf);
246
247 let mut tmp: Vec<u8> = Vec::with_capacity(64);
248
249 for element in *self {
250 tmp.clear();
251
252 let length = element.to_compact(&mut tmp);
254 encode_varuint(length, buf);
255
256 buf.put_slice(&tmp);
257 }
258
259 0
260 }
261
262 #[inline]
263 fn from_compact(_: &[u8], _: usize) -> (Self, &[u8]) {
264 unimplemented!()
265 }
266
267 #[inline]
269 fn specialized_to_compact<B>(&self, buf: &mut B) -> usize
270 where
271 B: bytes::BufMut + AsMut<[u8]>,
272 {
273 encode_varuint(self.len(), buf);
274 for element in *self {
275 element.to_compact(buf);
276 }
277 0
278 }
279
280 #[inline]
281 fn specialized_from_compact(_: &[u8], _: usize) -> (Self, &[u8]) {
282 unimplemented!()
283 }
284}
285
286impl<T> Compact for Option<T>
287where
288 T: Compact,
289{
290 #[inline]
292 fn to_compact<B>(&self, buf: &mut B) -> usize
293 where
294 B: bytes::BufMut + AsMut<[u8]>,
295 {
296 let Some(element) = self else { return 0 };
297
298 let mut tmp = Vec::with_capacity(64);
300 let length = element.to_compact(&mut tmp);
301
302 encode_varuint(length, buf);
303
304 buf.put_slice(&tmp);
305
306 1
307 }
308
309 #[inline]
310 fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
311 if len == 0 {
312 return (None, buf)
313 }
314
315 let (len, mut buf) = decode_varuint(buf);
316
317 let (element, _) = T::from_compact(&buf[..len], len);
318 buf.advance(len);
319
320 (Some(element), buf)
321 }
322
323 #[inline]
325 fn specialized_to_compact<B>(&self, buf: &mut B) -> usize
326 where
327 B: bytes::BufMut + AsMut<[u8]>,
328 {
329 if let Some(element) = self {
330 element.to_compact(buf);
331 1
332 } else {
333 0
334 }
335 }
336
337 #[inline]
339 fn specialized_from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
340 if len == 0 {
341 return (None, buf)
342 }
343
344 let (element, buf) = T::from_compact(buf, len);
345 (Some(element), buf)
346 }
347}
348
349impl<T: Compact + ToOwned<Owned = T>> Compact for Cow<'_, T> {
350 fn to_compact<B>(&self, buf: &mut B) -> usize
351 where
352 B: bytes::BufMut + AsMut<[u8]>,
353 {
354 self.as_ref().to_compact(buf)
355 }
356
357 fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
358 let (element, buf) = T::from_compact(buf, len);
359 (Cow::Owned(element), buf)
360 }
361
362 fn specialized_to_compact<B>(&self, buf: &mut B) -> usize
363 where
364 B: bytes::BufMut + AsMut<[u8]>,
365 {
366 self.as_ref().specialized_to_compact(buf)
367 }
368
369 fn specialized_from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
370 let (element, buf) = T::specialized_from_compact(buf, len);
371 (Cow::Owned(element), buf)
372 }
373}
374
375impl Compact for U256 {
376 #[inline]
377 fn to_compact<B>(&self, buf: &mut B) -> usize
378 where
379 B: bytes::BufMut + AsMut<[u8]>,
380 {
381 let inner = self.to_be_bytes::<32>();
382 let size = 32 - (self.leading_zeros() / 8);
383 buf.put_slice(&inner[32 - size..]);
384 size
385 }
386
387 #[inline]
388 fn from_compact(mut buf: &[u8], len: usize) -> (Self, &[u8]) {
389 if len == 0 {
390 return (Self::ZERO, buf)
391 }
392
393 let mut arr = [0; 32];
394 arr[(32 - len)..].copy_from_slice(&buf[..len]);
395 buf.advance(len);
396 (Self::from_be_bytes(arr), buf)
397 }
398}
399
400impl Compact for U96 {
401 #[inline]
402 fn to_compact<B>(&self, buf: &mut B) -> usize
403 where
404 B: bytes::BufMut + AsMut<[u8]>,
405 {
406 let inner = self.to_be_bytes::<12>();
407 let size = 12 - (self.leading_zeros() / 8);
408 buf.put_slice(&inner[12 - size..]);
409 size
410 }
411
412 #[inline]
413 fn from_compact(mut buf: &[u8], len: usize) -> (Self, &[u8]) {
414 if len == 0 {
415 return (Self::ZERO, buf)
416 }
417
418 let mut arr = [0; 12];
419 arr[(12 - len)..].copy_from_slice(&buf[..len]);
420 buf.advance(len);
421 (Self::from_be_bytes(arr), buf)
422 }
423}
424
425impl Compact for Bytes {
426 #[inline]
427 fn to_compact<B>(&self, buf: &mut B) -> usize
428 where
429 B: bytes::BufMut + AsMut<[u8]>,
430 {
431 let len = self.len();
432 buf.put_slice(&self.0);
433 len
434 }
435
436 #[inline]
437 fn from_compact(mut buf: &[u8], len: usize) -> (Self, &[u8]) {
438 (buf.copy_to_bytes(len).into(), buf)
439 }
440}
441
442impl<const N: usize> Compact for [u8; N] {
443 #[inline]
444 fn to_compact<B>(&self, buf: &mut B) -> usize
445 where
446 B: bytes::BufMut + AsMut<[u8]>,
447 {
448 buf.put_slice(&self[..]);
449 N
450 }
451
452 #[inline]
453 fn from_compact(mut buf: &[u8], len: usize) -> (Self, &[u8]) {
454 if len == 0 {
455 return ([0; N], buf)
456 }
457
458 let v = buf[..N].try_into().unwrap();
459 buf.advance(N);
460 (v, buf)
461 }
462}
463
464#[macro_export]
466macro_rules! impl_compact_for_wrapped_bytes {
467 ($($name:tt),+) => {
468 $(
469 impl Compact for $name {
470 #[inline]
471 fn to_compact<B>(&self, buf: &mut B) -> usize
472 where
473 B: bytes::BufMut + AsMut<[u8]>
474 {
475 self.0.to_compact(buf)
476 }
477
478 #[inline]
479 fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
480 let (v, buf) = <[u8; core::mem::size_of::<$name>()]>::from_compact(buf, len);
481 (Self::from(v), buf)
482 }
483 }
484 )+
485 };
486}
487impl_compact_for_wrapped_bytes!(Address, Bloom);
488
489impl<const N: usize> Compact for FixedBytes<N> {
490 #[inline]
491 fn to_compact<B>(&self, buf: &mut B) -> usize
492 where
493 B: bytes::BufMut + AsMut<[u8]>,
494 {
495 self.0.to_compact(buf)
496 }
497
498 #[inline]
499 fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
500 let (v, buf) = <[u8; N]>::from_compact(buf, len);
501 (Self::from(v), buf)
502 }
503}
504
505impl Compact for bool {
506 #[inline]
508 fn to_compact<B>(&self, _: &mut B) -> usize
509 where
510 B: bytes::BufMut + AsMut<[u8]>,
511 {
512 *self as usize
513 }
514
515 #[inline]
517 fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
518 (len != 0, buf)
519 }
520}
521
522fn encode_varuint<B>(mut n: usize, buf: &mut B)
523where
524 B: bytes::BufMut + AsMut<[u8]>,
525{
526 while n >= 0x80 {
527 buf.put_u8((n as u8) | 0x80);
528 n >>= 7;
529 }
530 buf.put_u8(n as u8);
531}
532
533fn decode_varuint(buf: &[u8]) -> (usize, &[u8]) {
534 let mut value = 0;
535
536 for i in 0..33 {
537 let byte = buf[i];
538 value |= usize::from(byte & 0x7F) << (i * 7);
539 if byte < 0x80 {
540 return (value, &buf[i + 1..])
541 }
542 }
543
544 decode_varuint_panic();
545}
546
547#[inline(never)]
548#[cold]
549const fn decode_varuint_panic() -> ! {
550 panic!("could not decode varuint");
551}
552
553#[cfg(test)]
554mod tests {
555 use super::*;
556 use alloy_primitives::B256;
557 use serde::{Deserialize, Serialize};
558
559 #[test]
560 fn compact_bytes() {
561 let arr = [1, 2, 3, 4, 5];
562 let list = Bytes::copy_from_slice(&arr);
563 let mut buf = Vec::with_capacity(list.len() + 1);
564 assert_eq!(list.to_compact(&mut buf), list.len());
565
566 buf.push(1);
568
569 assert_eq!(&buf[..arr.len()], &arr);
570 assert_eq!(Bytes::from_compact(&buf, list.len()), (list, vec![1].as_slice()));
571 }
572
573 #[test]
574 fn compact_address() {
575 let mut buf = Vec::with_capacity(21);
576 assert_eq!(Address::ZERO.to_compact(&mut buf), 20);
577 assert_eq!(buf, vec![0; 20]);
578
579 buf.push(1);
581
582 assert_eq!(Address::from_compact(&buf, 1000), (Address::ZERO, vec![1u8].as_slice()));
584 }
585
586 #[test]
587 fn compact_b256() {
588 let mut buf = Vec::with_capacity(32 + 1);
589 assert_eq!(B256::ZERO.to_compact(&mut buf), 32);
590 assert_eq!(buf, vec![0; 32]);
591
592 buf.push(1);
594
595 assert_eq!(B256::from_compact(&buf, 1000), (B256::ZERO, vec![1u8].as_slice()));
597 }
598
599 #[test]
600 fn compact_bool() {
601 let _vtrue = true;
602 let mut buf = vec![];
603
604 assert_eq!(true.to_compact(&mut buf), 1);
605 assert_eq!(buf.len(), 0);
607
608 assert_eq!(false.to_compact(&mut buf), 0);
609 assert_eq!(buf.len(), 0);
610
611 let buf = vec![100u8];
612
613 assert_eq!(bool::from_compact(&buf, 1), (true, buf.as_slice()));
615 assert_eq!(bool::from_compact(&buf, 0), (false, buf.as_slice()));
616 }
617
618 #[test]
619 fn compact_option() {
620 let opt = Some(B256::ZERO);
621 let mut buf = Vec::with_capacity(1 + 32);
622
623 assert_eq!(None::<B256>.to_compact(&mut buf), 0);
624 assert_eq!(opt.to_compact(&mut buf), 1);
625 assert_eq!(buf.len(), 1 + 32);
626
627 assert_eq!(Option::<B256>::from_compact(&buf, 1), (opt, vec![].as_slice()));
628
629 assert_eq!(Option::<B256>::from_compact(&buf, 0), (None, buf.as_slice()));
631
632 let mut buf = Vec::with_capacity(32);
633 assert_eq!(opt.specialized_to_compact(&mut buf), 1);
634 assert_eq!(buf.len(), 32);
635 assert_eq!(Option::<B256>::specialized_from_compact(&buf, 1), (opt, vec![].as_slice()));
636 }
637
638 #[test]
639 fn compact_vec() {
640 let list = vec![B256::ZERO, B256::ZERO];
641 let mut buf = vec![];
642
643 assert_eq!(list.to_compact(&mut buf), 0);
645
646 buf.extend([1u8, 2]);
648
649 let mut remaining_buf = buf.as_slice();
650 remaining_buf.advance(1 + 1 + 32 + 1 + 32);
651
652 assert_eq!(Vec::<B256>::from_compact(&buf, 0), (list, remaining_buf));
653 assert_eq!(remaining_buf, &[1u8, 2]);
654 }
655
656 #[test]
657 fn compact_u256() {
658 let mut buf = vec![];
659
660 assert_eq!(U256::ZERO.to_compact(&mut buf), 0);
661 assert!(buf.is_empty());
662 assert_eq!(U256::from_compact(&buf, 0), (U256::ZERO, vec![].as_slice()));
663
664 assert_eq!(U256::from(2).to_compact(&mut buf), 1);
665 assert_eq!(buf, vec![2u8]);
666 assert_eq!(U256::from_compact(&buf, 1), (U256::from(2), vec![].as_slice()));
667 }
668
669 #[test]
670 fn compact_u64() {
671 let mut buf = vec![];
672
673 assert_eq!(0u64.to_compact(&mut buf), 0);
674 assert!(buf.is_empty());
675 assert_eq!(u64::from_compact(&buf, 0), (0u64, vec![].as_slice()));
676
677 assert_eq!(2u64.to_compact(&mut buf), 1);
678 assert_eq!(buf, vec![2u8]);
679 assert_eq!(u64::from_compact(&buf, 1), (2u64, vec![].as_slice()));
680
681 let mut buf = Vec::with_capacity(8);
682
683 assert_eq!(0xffffffffffffffffu64.to_compact(&mut buf), 8);
684 assert_eq!(&buf, &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]);
685 assert_eq!(u64::from_compact(&buf, 8), (0xffffffffffffffffu64, vec![].as_slice()));
686 }
687
688 #[test]
689 fn variable_uint() {
690 proptest::proptest!(|(val: usize)| {
691 let mut buf = vec![];
692 encode_varuint(val, &mut buf);
693 let (decoded, read_buf) = decode_varuint(&buf);
694 assert_eq!(val, decoded);
695 assert!(!read_buf.has_remaining());
696 });
697 }
698
699 #[test]
700 fn compact_slice() {
701 let vec_list = vec![B256::ZERO, B256::random(), B256::random(), B256::ZERO];
702
703 {
705 let mut vec_buf = vec![];
706 assert_eq!(vec_list.to_compact(&mut vec_buf), 0);
707
708 let mut slice_buf = vec![];
709 assert_eq!(vec_list.as_slice().to_compact(&mut slice_buf), 0);
710
711 assert_eq!(vec_buf, slice_buf);
712 }
713
714 {
716 let mut vec_buf = vec![];
717 assert_eq!(vec_list.specialized_to_compact(&mut vec_buf), 0);
718
719 let mut slice_buf = vec![];
720 assert_eq!(vec_list.as_slice().specialized_to_compact(&mut slice_buf), 0);
721
722 assert_eq!(vec_buf, slice_buf);
723 }
724 }
725
726 #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Compact, arbitrary::Arbitrary)]
727 #[add_arbitrary_tests(crate, compact)]
728 #[reth_codecs(crate = "crate")]
729 struct TestStruct {
730 f_u64: u64,
731 f_u256: U256,
732 f_bool_t: bool,
733 f_bool_f: bool,
734 f_option_none: Option<B256>,
735 f_option_some: Option<B256>,
736 f_option_some_u64: Option<u64>,
737 f_vec_empty: Vec<Address>,
738 f_vec_some: Vec<Address>,
739 }
740
741 impl Default for TestStruct {
742 fn default() -> Self {
743 Self {
744 f_u64: 1u64, f_u256: U256::from(1u64), f_bool_f: false, f_bool_t: true, f_option_none: None, f_option_some: Some(B256::ZERO), f_option_some_u64: Some(0xffffu64), f_vec_empty: vec![], f_vec_some: vec![Address::ZERO, Address::ZERO], }
754 }
755 }
756
757 #[test]
758 fn compact_test_struct() {
759 let test = TestStruct::default();
760 const EXPECTED_SIZE: usize = 2 + 1 +
762 1 +
763 32 +
765 1 + 2 +
766 1 +
767 1 + 20 * 2;
768 let mut buf = Vec::with_capacity(EXPECTED_SIZE);
769 assert_eq!(test.to_compact(&mut buf), EXPECTED_SIZE);
770
771 assert_eq!(
772 TestStruct::from_compact(&buf, buf.len()),
773 (TestStruct::default(), vec![].as_slice())
774 );
775 }
776
777 #[derive(
778 Debug, PartialEq, Clone, Default, Serialize, Deserialize, Compact, arbitrary::Arbitrary,
779 )]
780 #[add_arbitrary_tests(crate, compact)]
781 #[reth_codecs(crate = "crate")]
782 enum TestEnum {
783 #[default]
784 Var0,
785 Var1(TestStruct),
786 Var2(u64),
787 }
788
789 #[cfg(test)]
790 #[allow(dead_code)]
791 #[test_fuzz::test_fuzz]
792 fn compact_test_enum_all_variants(var0: TestEnum, var1: TestEnum, var2: TestEnum) {
793 let mut buf = vec![];
794 var0.to_compact(&mut buf);
795 assert_eq!(TestEnum::from_compact(&buf, buf.len()).0, var0);
796
797 let mut buf = vec![];
798 var1.to_compact(&mut buf);
799 assert_eq!(TestEnum::from_compact(&buf, buf.len()).0, var1);
800
801 let mut buf = vec![];
802 var2.to_compact(&mut buf);
803 assert_eq!(TestEnum::from_compact(&buf, buf.len()).0, var2);
804 }
805
806 #[test]
807 fn compact_test_enum() {
808 let var0 = TestEnum::Var0;
809 let var1 = TestEnum::Var1(TestStruct::default());
810 let var2 = TestEnum::Var2(1u64);
811
812 compact_test_enum_all_variants(var0, var1, var2);
813 }
814}