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/paradigmxyz/reth/issues/"
15)]
16#![cfg_attr(not(test), warn(unused_crate_dependencies))]
17#![cfg_attr(docsrs, feature(doc_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::{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"))]
38pub mod 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, buf) = decode_varuint(buf);
316
317 let (element, buf) = T::from_compact(buf, len);
318
319 (Some(element), buf)
320 }
321
322 #[inline]
324 fn specialized_to_compact<B>(&self, buf: &mut B) -> usize
325 where
326 B: bytes::BufMut + AsMut<[u8]>,
327 {
328 if let Some(element) = self {
329 element.to_compact(buf);
330 1
331 } else {
332 0
333 }
334 }
335
336 #[inline]
338 fn specialized_from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
339 if len == 0 {
340 return (None, buf)
341 }
342
343 let (element, buf) = T::from_compact(buf, len);
344 (Some(element), buf)
345 }
346}
347
348impl<T: Compact + ToOwned<Owned = T>> Compact for Cow<'_, T> {
349 fn to_compact<B>(&self, buf: &mut B) -> usize
350 where
351 B: bytes::BufMut + AsMut<[u8]>,
352 {
353 self.as_ref().to_compact(buf)
354 }
355
356 fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
357 let (element, buf) = T::from_compact(buf, len);
358 (Cow::Owned(element), buf)
359 }
360
361 fn specialized_to_compact<B>(&self, buf: &mut B) -> usize
362 where
363 B: bytes::BufMut + AsMut<[u8]>,
364 {
365 self.as_ref().specialized_to_compact(buf)
366 }
367
368 fn specialized_from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
369 let (element, buf) = T::specialized_from_compact(buf, len);
370 (Cow::Owned(element), buf)
371 }
372}
373
374impl Compact for U256 {
375 #[inline]
376 fn to_compact<B>(&self, buf: &mut B) -> usize
377 where
378 B: bytes::BufMut + AsMut<[u8]>,
379 {
380 let inner = self.to_be_bytes::<32>();
381 let size = 32 - (self.leading_zeros() / 8);
382 buf.put_slice(&inner[32 - size..]);
383 size
384 }
385
386 #[inline]
387 fn from_compact(mut buf: &[u8], len: usize) -> (Self, &[u8]) {
388 if len == 0 {
389 return (Self::ZERO, buf)
390 }
391
392 let mut arr = [0; 32];
393 arr[(32 - len)..].copy_from_slice(&buf[..len]);
394 buf.advance(len);
395 (Self::from_be_bytes(arr), buf)
396 }
397}
398
399impl Compact for Bytes {
400 #[inline]
401 fn to_compact<B>(&self, buf: &mut B) -> usize
402 where
403 B: bytes::BufMut + AsMut<[u8]>,
404 {
405 let len = self.len();
406 buf.put_slice(&self.0);
407 len
408 }
409
410 #[inline]
411 fn from_compact(mut buf: &[u8], len: usize) -> (Self, &[u8]) {
412 (buf.copy_to_bytes(len).into(), buf)
413 }
414}
415
416impl<const N: usize> Compact for [u8; N] {
417 #[inline]
418 fn to_compact<B>(&self, buf: &mut B) -> usize
419 where
420 B: bytes::BufMut + AsMut<[u8]>,
421 {
422 buf.put_slice(&self[..]);
423 N
424 }
425
426 #[inline]
427 fn from_compact(mut buf: &[u8], len: usize) -> (Self, &[u8]) {
428 if len == 0 {
429 return ([0; N], buf)
430 }
431
432 let v = buf[..N].try_into().unwrap();
433 buf.advance(N);
434 (v, buf)
435 }
436}
437
438#[macro_export]
440macro_rules! impl_compact_for_wrapped_bytes {
441 ($($name:tt),+) => {
442 $(
443 impl Compact for $name {
444 #[inline]
445 fn to_compact<B>(&self, buf: &mut B) -> usize
446 where
447 B: bytes::BufMut + AsMut<[u8]>
448 {
449 self.0.to_compact(buf)
450 }
451
452 #[inline]
453 fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
454 let (v, buf) = <[u8; core::mem::size_of::<$name>()]>::from_compact(buf, len);
455 (Self::from(v), buf)
456 }
457 }
458 )+
459 };
460}
461impl_compact_for_wrapped_bytes!(Address, Bloom);
462
463impl<const N: usize> Compact for FixedBytes<N> {
464 #[inline]
465 fn to_compact<B>(&self, buf: &mut B) -> usize
466 where
467 B: bytes::BufMut + AsMut<[u8]>,
468 {
469 self.0.to_compact(buf)
470 }
471
472 #[inline]
473 fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
474 let (v, buf) = <[u8; N]>::from_compact(buf, len);
475 (Self::from(v), buf)
476 }
477}
478
479impl Compact for bool {
480 #[inline]
482 fn to_compact<B>(&self, _: &mut B) -> usize
483 where
484 B: bytes::BufMut + AsMut<[u8]>,
485 {
486 *self as usize
487 }
488
489 #[inline]
491 fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
492 (len != 0, buf)
493 }
494}
495
496fn encode_varuint<B>(mut n: usize, buf: &mut B)
497where
498 B: bytes::BufMut + AsMut<[u8]>,
499{
500 while n >= 0x80 {
501 buf.put_u8((n as u8) | 0x80);
502 n >>= 7;
503 }
504 buf.put_u8(n as u8);
505}
506
507fn decode_varuint(buf: &[u8]) -> (usize, &[u8]) {
508 let mut value = 0;
509
510 for i in 0..33 {
511 let byte = buf[i];
512 value |= usize::from(byte & 0x7F) << (i * 7);
513 if byte < 0x80 {
514 return (value, &buf[i + 1..])
515 }
516 }
517
518 decode_varuint_panic();
519}
520
521#[inline(never)]
522#[cold]
523const fn decode_varuint_panic() -> ! {
524 panic!("could not decode varuint");
525}
526
527#[cfg(test)]
528mod tests {
529 use super::*;
530 use alloy_primitives::B256;
531 use serde::{Deserialize, Serialize};
532
533 #[test]
534 fn compact_bytes() {
535 let arr = [1, 2, 3, 4, 5];
536 let list = Bytes::copy_from_slice(&arr);
537 let mut buf = Vec::with_capacity(list.len() + 1);
538 assert_eq!(list.to_compact(&mut buf), list.len());
539
540 buf.push(1);
542
543 assert_eq!(&buf[..arr.len()], &arr);
544 assert_eq!(Bytes::from_compact(&buf, list.len()), (list, vec![1].as_slice()));
545 }
546
547 #[test]
548 fn compact_address() {
549 let mut buf = Vec::with_capacity(21);
550 assert_eq!(Address::ZERO.to_compact(&mut buf), 20);
551 assert_eq!(buf, vec![0; 20]);
552
553 buf.push(1);
555
556 assert_eq!(Address::from_compact(&buf, 1000), (Address::ZERO, vec![1u8].as_slice()));
558 }
559
560 #[test]
561 fn compact_b256() {
562 let mut buf = Vec::with_capacity(32 + 1);
563 assert_eq!(B256::ZERO.to_compact(&mut buf), 32);
564 assert_eq!(buf, vec![0; 32]);
565
566 buf.push(1);
568
569 assert_eq!(B256::from_compact(&buf, 1000), (B256::ZERO, vec![1u8].as_slice()));
571 }
572
573 #[test]
574 fn compact_bool() {
575 let _vtrue = true;
576 let mut buf = vec![];
577
578 assert_eq!(true.to_compact(&mut buf), 1);
579 assert_eq!(buf.len(), 0);
581
582 assert_eq!(false.to_compact(&mut buf), 0);
583 assert_eq!(buf.len(), 0);
584
585 let buf = vec![100u8];
586
587 assert_eq!(bool::from_compact(&buf, 1), (true, buf.as_slice()));
589 assert_eq!(bool::from_compact(&buf, 0), (false, buf.as_slice()));
590 }
591
592 #[test]
593 fn compact_option() {
594 let opt = Some(B256::ZERO);
595 let mut buf = Vec::with_capacity(1 + 32);
596
597 assert_eq!(None::<B256>.to_compact(&mut buf), 0);
598 assert_eq!(opt.to_compact(&mut buf), 1);
599 assert_eq!(buf.len(), 1 + 32);
600
601 assert_eq!(Option::<B256>::from_compact(&buf, 1), (opt, vec![].as_slice()));
602
603 assert_eq!(Option::<B256>::from_compact(&buf, 0), (None, buf.as_slice()));
605
606 let mut buf = Vec::with_capacity(32);
607 assert_eq!(opt.specialized_to_compact(&mut buf), 1);
608 assert_eq!(buf.len(), 32);
609 assert_eq!(Option::<B256>::specialized_from_compact(&buf, 1), (opt, vec![].as_slice()));
610 }
611
612 #[test]
613 fn compact_vec() {
614 let list = vec![B256::ZERO, B256::ZERO];
615 let mut buf = vec![];
616
617 assert_eq!(list.to_compact(&mut buf), 0);
619
620 buf.extend([1u8, 2]);
622
623 let mut remaining_buf = buf.as_slice();
624 remaining_buf.advance(1 + 1 + 32 + 1 + 32);
625
626 assert_eq!(Vec::<B256>::from_compact(&buf, 0), (list, remaining_buf));
627 assert_eq!(remaining_buf, &[1u8, 2]);
628 }
629
630 #[test]
631 fn compact_u256() {
632 let mut buf = vec![];
633
634 assert_eq!(U256::ZERO.to_compact(&mut buf), 0);
635 assert!(buf.is_empty());
636 assert_eq!(U256::from_compact(&buf, 0), (U256::ZERO, vec![].as_slice()));
637
638 assert_eq!(U256::from(2).to_compact(&mut buf), 1);
639 assert_eq!(buf, vec![2u8]);
640 assert_eq!(U256::from_compact(&buf, 1), (U256::from(2), vec![].as_slice()));
641 }
642
643 #[test]
644 fn compact_u64() {
645 let mut buf = vec![];
646
647 assert_eq!(0u64.to_compact(&mut buf), 0);
648 assert!(buf.is_empty());
649 assert_eq!(u64::from_compact(&buf, 0), (0u64, vec![].as_slice()));
650
651 assert_eq!(2u64.to_compact(&mut buf), 1);
652 assert_eq!(buf, vec![2u8]);
653 assert_eq!(u64::from_compact(&buf, 1), (2u64, vec![].as_slice()));
654
655 let mut buf = Vec::with_capacity(8);
656
657 assert_eq!(0xffffffffffffffffu64.to_compact(&mut buf), 8);
658 assert_eq!(&buf, &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]);
659 assert_eq!(u64::from_compact(&buf, 8), (0xffffffffffffffffu64, vec![].as_slice()));
660 }
661
662 #[test]
663 fn variable_uint() {
664 proptest::proptest!(|(val: usize)| {
665 let mut buf = vec![];
666 encode_varuint(val, &mut buf);
667 let (decoded, read_buf) = decode_varuint(&buf);
668 assert_eq!(val, decoded);
669 assert!(!read_buf.has_remaining());
670 });
671 }
672
673 #[test]
674 fn compact_slice() {
675 let vec_list = vec![B256::ZERO, B256::random(), B256::random(), B256::ZERO];
676
677 {
679 let mut vec_buf = vec![];
680 assert_eq!(vec_list.to_compact(&mut vec_buf), 0);
681
682 let mut slice_buf = vec![];
683 assert_eq!(vec_list.as_slice().to_compact(&mut slice_buf), 0);
684
685 assert_eq!(vec_buf, slice_buf);
686 }
687
688 {
690 let mut vec_buf = vec![];
691 assert_eq!(vec_list.specialized_to_compact(&mut vec_buf), 0);
692
693 let mut slice_buf = vec![];
694 assert_eq!(vec_list.as_slice().specialized_to_compact(&mut slice_buf), 0);
695
696 assert_eq!(vec_buf, slice_buf);
697 }
698 }
699
700 #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Compact, arbitrary::Arbitrary)]
701 #[add_arbitrary_tests(crate, compact)]
702 #[reth_codecs(crate = "crate")]
703 struct TestStruct {
704 f_u64: u64,
705 f_u256: U256,
706 f_bool_t: bool,
707 f_bool_f: bool,
708 f_option_none: Option<B256>,
709 f_option_some: Option<B256>,
710 f_option_some_u64: Option<u64>,
711 f_vec_empty: Vec<Address>,
712 f_vec_some: Vec<Address>,
713 }
714
715 impl Default for TestStruct {
716 fn default() -> Self {
717 Self {
718 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], }
728 }
729 }
730
731 #[test]
732 fn compact_test_struct() {
733 let test = TestStruct::default();
734 const EXPECTED_SIZE: usize = 2 + 1 +
736 1 +
737 32 +
739 1 + 2 +
740 1 +
741 1 + 20 * 2;
742 let mut buf = Vec::with_capacity(EXPECTED_SIZE);
743 assert_eq!(test.to_compact(&mut buf), EXPECTED_SIZE);
744
745 assert_eq!(
746 TestStruct::from_compact(&buf, buf.len()),
747 (TestStruct::default(), vec![].as_slice())
748 );
749 }
750
751 #[derive(
752 Debug, PartialEq, Clone, Default, Serialize, Deserialize, Compact, arbitrary::Arbitrary,
753 )]
754 #[add_arbitrary_tests(crate, compact)]
755 #[reth_codecs(crate = "crate")]
756 enum TestEnum {
757 #[default]
758 Var0,
759 Var1(TestStruct),
760 Var2(u64),
761 }
762
763 #[cfg(test)]
764 #[test_fuzz::test_fuzz]
765 fn compact_test_enum_all_variants(var0: TestEnum, var1: TestEnum, var2: TestEnum) {
766 let mut buf = vec![];
767 var0.to_compact(&mut buf);
768 assert_eq!(TestEnum::from_compact(&buf, buf.len()).0, var0);
769
770 let mut buf = vec![];
771 var1.to_compact(&mut buf);
772 assert_eq!(TestEnum::from_compact(&buf, buf.len()).0, var1);
773
774 let mut buf = vec![];
775 var2.to_compact(&mut buf);
776 assert_eq!(TestEnum::from_compact(&buf, buf.len()).0, var2);
777 }
778
779 #[test]
780 fn compact_test_enum() {
781 let var0 = TestEnum::Var0;
782 let var1 = TestEnum::Var1(TestStruct::default());
783 let var2 = TestEnum::Var2(1u64);
784
785 compact_test_enum_all_variants(var0, var1, var2);
786 }
787}