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, 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::{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 Bytes {
401 #[inline]
402 fn to_compact<B>(&self, buf: &mut B) -> usize
403 where
404 B: bytes::BufMut + AsMut<[u8]>,
405 {
406 let len = self.len();
407 buf.put_slice(&self.0);
408 len
409 }
410
411 #[inline]
412 fn from_compact(mut buf: &[u8], len: usize) -> (Self, &[u8]) {
413 (buf.copy_to_bytes(len).into(), buf)
414 }
415}
416
417impl<const N: usize> Compact for [u8; N] {
418 #[inline]
419 fn to_compact<B>(&self, buf: &mut B) -> usize
420 where
421 B: bytes::BufMut + AsMut<[u8]>,
422 {
423 buf.put_slice(&self[..]);
424 N
425 }
426
427 #[inline]
428 fn from_compact(mut buf: &[u8], len: usize) -> (Self, &[u8]) {
429 if len == 0 {
430 return ([0; N], buf)
431 }
432
433 let v = buf[..N].try_into().unwrap();
434 buf.advance(N);
435 (v, buf)
436 }
437}
438
439#[macro_export]
441macro_rules! impl_compact_for_wrapped_bytes {
442 ($($name:tt),+) => {
443 $(
444 impl Compact for $name {
445 #[inline]
446 fn to_compact<B>(&self, buf: &mut B) -> usize
447 where
448 B: bytes::BufMut + AsMut<[u8]>
449 {
450 self.0.to_compact(buf)
451 }
452
453 #[inline]
454 fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
455 let (v, buf) = <[u8; core::mem::size_of::<$name>()]>::from_compact(buf, len);
456 (Self::from(v), buf)
457 }
458 }
459 )+
460 };
461}
462impl_compact_for_wrapped_bytes!(Address, Bloom);
463
464impl<const N: usize> Compact for FixedBytes<N> {
465 #[inline]
466 fn to_compact<B>(&self, buf: &mut B) -> usize
467 where
468 B: bytes::BufMut + AsMut<[u8]>,
469 {
470 self.0.to_compact(buf)
471 }
472
473 #[inline]
474 fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
475 let (v, buf) = <[u8; N]>::from_compact(buf, len);
476 (Self::from(v), buf)
477 }
478}
479
480impl Compact for bool {
481 #[inline]
483 fn to_compact<B>(&self, _: &mut B) -> usize
484 where
485 B: bytes::BufMut + AsMut<[u8]>,
486 {
487 *self as usize
488 }
489
490 #[inline]
492 fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
493 (len != 0, buf)
494 }
495}
496
497fn encode_varuint<B>(mut n: usize, buf: &mut B)
498where
499 B: bytes::BufMut + AsMut<[u8]>,
500{
501 while n >= 0x80 {
502 buf.put_u8((n as u8) | 0x80);
503 n >>= 7;
504 }
505 buf.put_u8(n as u8);
506}
507
508fn decode_varuint(buf: &[u8]) -> (usize, &[u8]) {
509 let mut value = 0;
510
511 for i in 0..33 {
512 let byte = buf[i];
513 value |= usize::from(byte & 0x7F) << (i * 7);
514 if byte < 0x80 {
515 return (value, &buf[i + 1..])
516 }
517 }
518
519 decode_varuint_panic();
520}
521
522#[inline(never)]
523#[cold]
524const fn decode_varuint_panic() -> ! {
525 panic!("could not decode varuint");
526}
527
528#[cfg(test)]
529mod tests {
530 use super::*;
531 use alloy_primitives::B256;
532 use serde::{Deserialize, Serialize};
533
534 #[test]
535 fn compact_bytes() {
536 let arr = [1, 2, 3, 4, 5];
537 let list = Bytes::copy_from_slice(&arr);
538 let mut buf = Vec::with_capacity(list.len() + 1);
539 assert_eq!(list.to_compact(&mut buf), list.len());
540
541 buf.push(1);
543
544 assert_eq!(&buf[..arr.len()], &arr);
545 assert_eq!(Bytes::from_compact(&buf, list.len()), (list, vec![1].as_slice()));
546 }
547
548 #[test]
549 fn compact_address() {
550 let mut buf = Vec::with_capacity(21);
551 assert_eq!(Address::ZERO.to_compact(&mut buf), 20);
552 assert_eq!(buf, vec![0; 20]);
553
554 buf.push(1);
556
557 assert_eq!(Address::from_compact(&buf, 1000), (Address::ZERO, vec![1u8].as_slice()));
559 }
560
561 #[test]
562 fn compact_b256() {
563 let mut buf = Vec::with_capacity(32 + 1);
564 assert_eq!(B256::ZERO.to_compact(&mut buf), 32);
565 assert_eq!(buf, vec![0; 32]);
566
567 buf.push(1);
569
570 assert_eq!(B256::from_compact(&buf, 1000), (B256::ZERO, vec![1u8].as_slice()));
572 }
573
574 #[test]
575 fn compact_bool() {
576 let _vtrue = true;
577 let mut buf = vec![];
578
579 assert_eq!(true.to_compact(&mut buf), 1);
580 assert_eq!(buf.len(), 0);
582
583 assert_eq!(false.to_compact(&mut buf), 0);
584 assert_eq!(buf.len(), 0);
585
586 let buf = vec![100u8];
587
588 assert_eq!(bool::from_compact(&buf, 1), (true, buf.as_slice()));
590 assert_eq!(bool::from_compact(&buf, 0), (false, buf.as_slice()));
591 }
592
593 #[test]
594 fn compact_option() {
595 let opt = Some(B256::ZERO);
596 let mut buf = Vec::with_capacity(1 + 32);
597
598 assert_eq!(None::<B256>.to_compact(&mut buf), 0);
599 assert_eq!(opt.to_compact(&mut buf), 1);
600 assert_eq!(buf.len(), 1 + 32);
601
602 assert_eq!(Option::<B256>::from_compact(&buf, 1), (opt, vec![].as_slice()));
603
604 assert_eq!(Option::<B256>::from_compact(&buf, 0), (None, buf.as_slice()));
606
607 let mut buf = Vec::with_capacity(32);
608 assert_eq!(opt.specialized_to_compact(&mut buf), 1);
609 assert_eq!(buf.len(), 32);
610 assert_eq!(Option::<B256>::specialized_from_compact(&buf, 1), (opt, vec![].as_slice()));
611 }
612
613 #[test]
614 fn compact_vec() {
615 let list = vec![B256::ZERO, B256::ZERO];
616 let mut buf = vec![];
617
618 assert_eq!(list.to_compact(&mut buf), 0);
620
621 buf.extend([1u8, 2]);
623
624 let mut remaining_buf = buf.as_slice();
625 remaining_buf.advance(1 + 1 + 32 + 1 + 32);
626
627 assert_eq!(Vec::<B256>::from_compact(&buf, 0), (list, remaining_buf));
628 assert_eq!(remaining_buf, &[1u8, 2]);
629 }
630
631 #[test]
632 fn compact_u256() {
633 let mut buf = vec![];
634
635 assert_eq!(U256::ZERO.to_compact(&mut buf), 0);
636 assert!(buf.is_empty());
637 assert_eq!(U256::from_compact(&buf, 0), (U256::ZERO, vec![].as_slice()));
638
639 assert_eq!(U256::from(2).to_compact(&mut buf), 1);
640 assert_eq!(buf, vec![2u8]);
641 assert_eq!(U256::from_compact(&buf, 1), (U256::from(2), vec![].as_slice()));
642 }
643
644 #[test]
645 fn compact_u64() {
646 let mut buf = vec![];
647
648 assert_eq!(0u64.to_compact(&mut buf), 0);
649 assert!(buf.is_empty());
650 assert_eq!(u64::from_compact(&buf, 0), (0u64, vec![].as_slice()));
651
652 assert_eq!(2u64.to_compact(&mut buf), 1);
653 assert_eq!(buf, vec![2u8]);
654 assert_eq!(u64::from_compact(&buf, 1), (2u64, vec![].as_slice()));
655
656 let mut buf = Vec::with_capacity(8);
657
658 assert_eq!(0xffffffffffffffffu64.to_compact(&mut buf), 8);
659 assert_eq!(&buf, &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]);
660 assert_eq!(u64::from_compact(&buf, 8), (0xffffffffffffffffu64, vec![].as_slice()));
661 }
662
663 #[test]
664 fn variable_uint() {
665 proptest::proptest!(|(val: usize)| {
666 let mut buf = vec![];
667 encode_varuint(val, &mut buf);
668 let (decoded, read_buf) = decode_varuint(&buf);
669 assert_eq!(val, decoded);
670 assert!(!read_buf.has_remaining());
671 });
672 }
673
674 #[test]
675 fn compact_slice() {
676 let vec_list = vec![B256::ZERO, B256::random(), B256::random(), B256::ZERO];
677
678 {
680 let mut vec_buf = vec![];
681 assert_eq!(vec_list.to_compact(&mut vec_buf), 0);
682
683 let mut slice_buf = vec![];
684 assert_eq!(vec_list.as_slice().to_compact(&mut slice_buf), 0);
685
686 assert_eq!(vec_buf, slice_buf);
687 }
688
689 {
691 let mut vec_buf = vec![];
692 assert_eq!(vec_list.specialized_to_compact(&mut vec_buf), 0);
693
694 let mut slice_buf = vec![];
695 assert_eq!(vec_list.as_slice().specialized_to_compact(&mut slice_buf), 0);
696
697 assert_eq!(vec_buf, slice_buf);
698 }
699 }
700
701 #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Compact, arbitrary::Arbitrary)]
702 #[add_arbitrary_tests(crate, compact)]
703 #[reth_codecs(crate = "crate")]
704 struct TestStruct {
705 f_u64: u64,
706 f_u256: U256,
707 f_bool_t: bool,
708 f_bool_f: bool,
709 f_option_none: Option<B256>,
710 f_option_some: Option<B256>,
711 f_option_some_u64: Option<u64>,
712 f_vec_empty: Vec<Address>,
713 f_vec_some: Vec<Address>,
714 }
715
716 impl Default for TestStruct {
717 fn default() -> Self {
718 Self {
719 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], }
729 }
730 }
731
732 #[test]
733 fn compact_test_struct() {
734 let test = TestStruct::default();
735 const EXPECTED_SIZE: usize = 2 + 1 +
737 1 +
738 32 +
740 1 + 2 +
741 1 +
742 1 + 20 * 2;
743 let mut buf = Vec::with_capacity(EXPECTED_SIZE);
744 assert_eq!(test.to_compact(&mut buf), EXPECTED_SIZE);
745
746 assert_eq!(
747 TestStruct::from_compact(&buf, buf.len()),
748 (TestStruct::default(), vec![].as_slice())
749 );
750 }
751
752 #[derive(
753 Debug, PartialEq, Clone, Default, Serialize, Deserialize, Compact, arbitrary::Arbitrary,
754 )]
755 #[add_arbitrary_tests(crate, compact)]
756 #[reth_codecs(crate = "crate")]
757 enum TestEnum {
758 #[default]
759 Var0,
760 Var1(TestStruct),
761 Var2(u64),
762 }
763
764 #[cfg(test)]
765 #[allow(dead_code)]
766 #[test_fuzz::test_fuzz]
767 fn compact_test_enum_all_variants(var0: TestEnum, var1: TestEnum, var2: TestEnum) {
768 let mut buf = vec![];
769 var0.to_compact(&mut buf);
770 assert_eq!(TestEnum::from_compact(&buf, buf.len()).0, var0);
771
772 let mut buf = vec![];
773 var1.to_compact(&mut buf);
774 assert_eq!(TestEnum::from_compact(&buf, buf.len()).0, var1);
775
776 let mut buf = vec![];
777 var2.to_compact(&mut buf);
778 assert_eq!(TestEnum::from_compact(&buf, buf.len()).0, var2);
779 }
780
781 #[test]
782 fn compact_test_enum() {
783 let var0 = TestEnum::Var0;
784 let var1 = TestEnum::Var1(TestStruct::default());
785 let var2 = TestEnum::Var2(1u64);
786
787 compact_test_enum_all_variants(var0, var1, var2);
788 }
789}