1use crate::{EthMessage, EthVersion, NetworkPrimitives};
4use alloc::{sync::Arc, vec::Vec};
5use alloy_primitives::{
6 map::{B256Map, B256Set},
7 Bytes, TxHash, B128, B256, U128,
8};
9use alloy_rlp::{
10 Decodable, Encodable, Header, RlpDecodable, RlpDecodableWrapper, RlpEncodable,
11 RlpEncodableWrapper,
12};
13use core::{fmt::Debug, mem};
14use derive_more::{Constructor, Deref, DerefMut, From, IntoIterator};
15use reth_codecs_derive::{add_arbitrary_tests, generate_tests};
16use reth_ethereum_primitives::TransactionSigned;
17use reth_primitives_traits::{Block, InMemorySize, SignedTransaction};
18
19#[derive(
21 Clone,
22 Debug,
23 PartialEq,
24 Eq,
25 RlpEncodableWrapper,
26 RlpDecodableWrapper,
27 Default,
28 Deref,
29 DerefMut,
30 IntoIterator,
31)]
32#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
33#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
34#[add_arbitrary_tests(rlp)]
35pub struct NewBlockHashes(
36 pub Vec<BlockHashNumber>,
39);
40
41impl NewBlockHashes {
44 pub fn latest(&self) -> Option<&BlockHashNumber> {
46 self.iter().max_by_key(|b| b.number)
47 }
48}
49
50#[derive(Clone, Debug, PartialEq, Eq, RlpEncodable, RlpDecodable, Default)]
52#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
53#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
54#[add_arbitrary_tests(rlp)]
55pub struct BlockHashNumber {
56 pub hash: B256,
58 pub number: u64,
60}
61
62impl From<Vec<BlockHashNumber>> for NewBlockHashes {
63 fn from(v: Vec<BlockHashNumber>) -> Self {
64 Self(v)
65 }
66}
67
68impl From<NewBlockHashes> for Vec<BlockHashNumber> {
69 fn from(v: NewBlockHashes) -> Self {
70 v.0
71 }
72}
73
74pub trait NewBlockPayload:
76 Encodable + Decodable + Clone + Eq + Debug + Send + Sync + Unpin + 'static
77{
78 type Block: Block;
80
81 fn block(&self) -> &Self::Block;
83}
84
85#[derive(Clone, Debug, PartialEq, Eq, RlpEncodable, RlpDecodable, Default)]
88#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
89#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
90pub struct NewBlock<B = reth_ethereum_primitives::Block> {
91 pub block: B,
93 pub td: U128,
95}
96
97impl<B: Block + 'static> NewBlockPayload for NewBlock<B> {
98 type Block = B;
99
100 fn block(&self) -> &Self::Block {
101 &self.block
102 }
103}
104
105generate_tests!(#[rlp, 25] NewBlock<reth_ethereum_primitives::Block>, EthNewBlockTests);
106
107#[derive(
110 Clone,
111 Debug,
112 PartialEq,
113 Eq,
114 RlpEncodableWrapper,
115 RlpDecodableWrapper,
116 Default,
117 Deref,
118 IntoIterator,
119)]
120#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
121#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
122#[add_arbitrary_tests(rlp, 10)]
123pub struct Transactions<T = TransactionSigned>(
124 pub Vec<T>,
126);
127
128impl<T: SignedTransaction> Transactions<T> {
129 pub fn has_eip4844(&self) -> bool {
131 self.iter().any(|tx| tx.is_eip4844())
132 }
133}
134
135impl<T> From<Vec<T>> for Transactions<T> {
136 fn from(txs: Vec<T>) -> Self {
137 Self(txs)
138 }
139}
140
141impl<T> From<Transactions<T>> for Vec<T> {
142 fn from(txs: Transactions<T>) -> Self {
143 txs.0
144 }
145}
146
147impl<T: Decodable + InMemorySize> Transactions<T> {
148 pub fn decode_with_memory_budget(
152 buf: &mut &[u8],
153 memory_budget: usize,
154 ) -> alloy_rlp::Result<Self> {
155 decode_list_with_memory_budget(buf, memory_budget).map(Self)
156 }
157}
158
159pub fn decode_list_with_memory_budget<T: Decodable + InMemorySize>(
162 buf: &mut &[u8],
163 memory_budget: usize,
164) -> alloy_rlp::Result<Vec<T>> {
165 let header = Header::decode(buf)?;
166 if !header.list {
167 return Err(alloy_rlp::Error::UnexpectedString);
168 }
169 if buf.len() < header.payload_length {
170 return Err(alloy_rlp::Error::InputTooShort);
171 }
172
173 let (payload, rest) = buf.split_at(header.payload_length);
174 let mut payload = payload;
175
176 let mut txs = Vec::new();
177 let mut total_size = 0usize;
178
179 while !payload.is_empty() {
180 let item = T::decode(&mut payload)?;
181 total_size = total_size.saturating_add(item.size());
182
183 if total_size > memory_budget {
184 break;
185 }
186
187 txs.push(item);
188 }
189
190 *buf = rest;
191 Ok(txs)
192}
193
194#[derive(
199 Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper, Deref, IntoIterator,
200)]
201#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
202#[add_arbitrary_tests(rlp, 20)]
203pub struct SharedTransactions<T = TransactionSigned>(
204 pub Vec<Arc<T>>,
206);
207
208#[derive(Clone, Debug, PartialEq, Eq)]
210#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
211pub enum NewPooledTransactionHashes {
212 Eth66(NewPooledTransactionHashes66),
214 Eth68(NewPooledTransactionHashes68),
218 Eth72(NewPooledTransactionHashes72),
225}
226
227impl NewPooledTransactionHashes {
230 pub const fn version(&self) -> EthVersion {
232 match self {
233 Self::Eth66(_) => EthVersion::Eth66,
234 Self::Eth68(_) => EthVersion::Eth68,
235 Self::Eth72(_) => EthVersion::Eth72,
236 }
237 }
238
239 pub const fn is_valid_for_version(&self, version: EthVersion) -> bool {
241 match self {
242 Self::Eth66(_) => {
243 matches!(version, EthVersion::Eth67 | EthVersion::Eth66)
244 }
245 Self::Eth68(_) => {
246 matches!(
247 version,
248 EthVersion::Eth68 | EthVersion::Eth69 | EthVersion::Eth70 | EthVersion::Eth71
249 )
250 }
251 Self::Eth72(_) => {
252 matches!(version, EthVersion::Eth72)
253 }
254 }
255 }
256
257 pub fn iter_hashes(&self) -> impl Iterator<Item = &B256> + '_ {
259 match self {
260 Self::Eth66(msg) => msg.iter(),
261 Self::Eth68(msg) => msg.hashes.iter(),
262 Self::Eth72(msg) => msg.hashes.iter(),
263 }
264 }
265
266 pub const fn hashes(&self) -> &Vec<B256> {
268 match self {
269 Self::Eth66(msg) => &msg.0,
270 Self::Eth68(msg) => &msg.hashes,
271 Self::Eth72(msg) => &msg.hashes,
272 }
273 }
274
275 pub const fn hashes_mut(&mut self) -> &mut Vec<B256> {
277 match self {
278 Self::Eth66(msg) => &mut msg.0,
279 Self::Eth68(msg) => &mut msg.hashes,
280 Self::Eth72(msg) => &mut msg.hashes,
281 }
282 }
283
284 pub fn into_hashes(self) -> Vec<B256> {
286 match self {
287 Self::Eth66(msg) => msg.0,
288 Self::Eth68(msg) => msg.hashes,
289 Self::Eth72(msg) => msg.hashes,
290 }
291 }
292
293 pub fn into_iter_hashes(self) -> impl Iterator<Item = B256> {
295 match self {
296 Self::Eth66(msg) => msg.into_iter(),
297 Self::Eth68(msg) => msg.hashes.into_iter(),
298 Self::Eth72(msg) => msg.hashes.into_iter(),
299 }
300 }
301
302 pub fn truncate(&mut self, len: usize) {
305 match self {
306 Self::Eth66(msg) => msg.truncate(len),
307 Self::Eth68(msg) => {
308 msg.types.truncate(len);
309 msg.sizes.truncate(len);
310 msg.hashes.truncate(len);
311 }
312 Self::Eth72(msg) => {
313 msg.types.truncate(len);
314 msg.sizes.truncate(len);
315 msg.hashes.truncate(len);
316 }
317 }
318 }
319
320 pub const fn is_empty(&self) -> bool {
322 match self {
323 Self::Eth66(msg) => msg.0.is_empty(),
324 Self::Eth68(msg) => msg.hashes.is_empty(),
325 Self::Eth72(msg) => msg.hashes.is_empty(),
326 }
327 }
328
329 pub const fn len(&self) -> usize {
331 match self {
332 Self::Eth66(msg) => msg.0.len(),
333 Self::Eth68(msg) => msg.hashes.len(),
334 Self::Eth72(msg) => msg.hashes.len(),
335 }
336 }
337
338 pub const fn as_eth72(&self) -> Option<&NewPooledTransactionHashes72> {
340 match self {
341 Self::Eth66(_) | Self::Eth68(_) => None,
342 Self::Eth72(msg) => Some(msg),
343 }
344 }
345
346 pub const fn as_eth72_mut(&mut self) -> Option<&mut NewPooledTransactionHashes72> {
348 match self {
349 Self::Eth66(_) | Self::Eth68(_) => None,
350 Self::Eth72(msg) => Some(msg),
351 }
352 }
353
354 pub const fn as_eth68(&self) -> Option<&NewPooledTransactionHashes68> {
356 match self {
357 Self::Eth66(_) | Self::Eth72(_) => None,
358 Self::Eth68(msg) => Some(msg),
359 }
360 }
361
362 pub const fn as_eth68_mut(&mut self) -> Option<&mut NewPooledTransactionHashes68> {
364 match self {
365 Self::Eth66(_) | Self::Eth72(_) => None,
366 Self::Eth68(msg) => Some(msg),
367 }
368 }
369
370 pub const fn as_eth66_mut(&mut self) -> Option<&mut NewPooledTransactionHashes66> {
372 match self {
373 Self::Eth66(msg) => Some(msg),
374 Self::Eth68(_) | Self::Eth72(_) => None,
375 }
376 }
377
378 pub fn take_eth68(&mut self) -> Option<NewPooledTransactionHashes68> {
380 match self {
381 Self::Eth66(_) | Self::Eth72(_) => None,
382 Self::Eth68(msg) => Some(mem::take(msg)),
383 }
384 }
385
386 pub fn take_eth66(&mut self) -> Option<NewPooledTransactionHashes66> {
388 match self {
389 Self::Eth66(msg) => Some(mem::take(msg)),
390 Self::Eth68(_) | Self::Eth72(_) => None,
391 }
392 }
393}
394
395impl<N: NetworkPrimitives> From<NewPooledTransactionHashes> for EthMessage<N> {
396 fn from(value: NewPooledTransactionHashes) -> Self {
397 match value {
398 NewPooledTransactionHashes::Eth66(msg) => Self::NewPooledTransactionHashes66(msg),
399 NewPooledTransactionHashes::Eth68(msg) => Self::NewPooledTransactionHashes68(msg),
400 NewPooledTransactionHashes::Eth72(msg) => Self::NewPooledTransactionHashes72(msg),
401 }
402 }
403}
404
405impl From<NewPooledTransactionHashes66> for NewPooledTransactionHashes {
406 fn from(hashes: NewPooledTransactionHashes66) -> Self {
407 Self::Eth66(hashes)
408 }
409}
410
411impl From<NewPooledTransactionHashes68> for NewPooledTransactionHashes {
412 fn from(hashes: NewPooledTransactionHashes68) -> Self {
413 Self::Eth68(hashes)
414 }
415}
416
417impl From<NewPooledTransactionHashes72> for NewPooledTransactionHashes {
418 fn from(hashes: NewPooledTransactionHashes72) -> Self {
419 Self::Eth72(hashes)
420 }
421}
422
423#[derive(
426 Clone,
427 Debug,
428 PartialEq,
429 Eq,
430 RlpEncodableWrapper,
431 RlpDecodableWrapper,
432 Default,
433 Deref,
434 DerefMut,
435 IntoIterator,
436)]
437#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
438#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
439#[add_arbitrary_tests(rlp)]
440pub struct NewPooledTransactionHashes66(
441 pub Vec<B256>,
445);
446
447impl NewPooledTransactionHashes66 {
448 pub fn with_capacity(capacity: usize) -> Self {
450 Self(Vec::with_capacity(capacity))
451 }
452}
453
454impl From<Vec<B256>> for NewPooledTransactionHashes66 {
455 fn from(v: Vec<B256>) -> Self {
456 Self(v)
457 }
458}
459
460#[derive(Clone, Debug, PartialEq, Eq, Default)]
463#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
464pub struct NewPooledTransactionHashes68 {
465 pub types: Vec<u8>,
489 pub sizes: Vec<usize>,
491 pub hashes: Vec<B256>,
493}
494
495#[cfg(feature = "arbitrary")]
496impl proptest::prelude::Arbitrary for NewPooledTransactionHashes68 {
497 type Parameters = ();
498 fn arbitrary_with(_args: ()) -> Self::Strategy {
499 use proptest::{collection::vec, prelude::*};
500 let vec_length = any::<usize>().prop_map(|x| x % 100 + 1); vec_length
504 .prop_flat_map(|len| {
505 let types_vec = vec(
507 proptest_arbitrary_interop::arb::<reth_ethereum_primitives::TxType>()
508 .prop_map(|ty| ty as u8),
509 len..=len,
510 );
511
512 let sizes_vec = vec(proptest::num::usize::ANY.prop_map(|x| x % 131072), len..=len);
514 let hashes_vec = vec(any::<B256>(), len..=len);
515
516 (types_vec, sizes_vec, hashes_vec)
517 })
518 .prop_map(|(types, sizes, hashes)| Self { types, sizes, hashes })
519 .boxed()
520 }
521
522 type Strategy = proptest::prelude::BoxedStrategy<Self>;
523}
524
525impl NewPooledTransactionHashes68 {
526 pub fn with_capacity(capacity: usize) -> Self {
528 Self {
529 types: Vec::with_capacity(capacity),
530 sizes: Vec::with_capacity(capacity),
531 hashes: Vec::with_capacity(capacity),
532 }
533 }
534
535 pub fn metadata_iter(&self) -> impl Iterator<Item = (&B256, (u8, usize))> {
537 self.hashes.iter().zip(self.types.iter().copied().zip(self.sizes.iter().copied()))
538 }
539
540 pub fn push<T: SignedTransaction>(&mut self, tx: &T) {
542 self.hashes.push(*tx.tx_hash());
543 self.sizes.push(tx.encode_2718_len());
544 self.types.push(tx.ty());
545 }
546
547 pub fn extend<'a, T: SignedTransaction>(&mut self, txs: impl IntoIterator<Item = &'a T>) {
549 for tx in txs {
550 self.push(tx);
551 }
552 }
553
554 pub fn shrink_to_fit(&mut self) {
556 self.hashes.shrink_to_fit();
557 self.sizes.shrink_to_fit();
558 self.types.shrink_to_fit()
559 }
560
561 pub fn with_transaction<T: SignedTransaction>(mut self, tx: &T) -> Self {
563 self.push(tx);
564 self
565 }
566
567 pub fn with_transactions<'a, T: SignedTransaction>(
569 mut self,
570 txs: impl IntoIterator<Item = &'a T>,
571 ) -> Self {
572 self.extend(txs);
573 self
574 }
575}
576
577impl Encodable for NewPooledTransactionHashes68 {
578 fn encode(&self, out: &mut dyn bytes::BufMut) {
579 #[derive(RlpEncodable)]
580 struct EncodableNewPooledTransactionHashes68<'a> {
581 types: &'a [u8],
582 sizes: &'a Vec<usize>,
583 hashes: &'a Vec<B256>,
584 }
585
586 let encodable = EncodableNewPooledTransactionHashes68 {
587 types: &self.types[..],
588 sizes: &self.sizes,
589 hashes: &self.hashes,
590 };
591
592 encodable.encode(out);
593 }
594 fn length(&self) -> usize {
595 #[derive(RlpEncodable)]
596 struct EncodableNewPooledTransactionHashes68<'a> {
597 types: &'a [u8],
598 sizes: &'a Vec<usize>,
599 hashes: &'a Vec<B256>,
600 }
601
602 let encodable = EncodableNewPooledTransactionHashes68 {
603 types: &self.types[..],
604 sizes: &self.sizes,
605 hashes: &self.hashes,
606 };
607
608 encodable.length()
609 }
610}
611
612impl Decodable for NewPooledTransactionHashes68 {
613 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
614 #[derive(RlpDecodable)]
615 struct EncodableNewPooledTransactionHashes68 {
616 types: Bytes,
617 sizes: Vec<usize>,
618 hashes: Vec<B256>,
619 }
620
621 let encodable = EncodableNewPooledTransactionHashes68::decode(buf)?;
622 let msg = Self {
623 types: encodable.types.into(),
624 sizes: encodable.sizes,
625 hashes: encodable.hashes,
626 };
627
628 if msg.hashes.len() != msg.types.len() {
629 return Err(alloy_rlp::Error::ListLengthMismatch {
630 expected: msg.hashes.len(),
631 got: msg.types.len(),
632 })
633 }
634 if msg.hashes.len() != msg.sizes.len() {
635 return Err(alloy_rlp::Error::ListLengthMismatch {
636 expected: msg.hashes.len(),
637 got: msg.sizes.len(),
638 })
639 }
640
641 Ok(msg)
642 }
643}
644
645#[derive(Clone, Debug, PartialEq, Eq, Default)]
648#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
649pub struct NewPooledTransactionHashes72 {
650 pub types: Vec<u8>,
659 pub sizes: Vec<usize>,
661 pub hashes: Vec<B256>,
663 pub cell_mask: Option<B128>,
670}
671
672#[cfg(feature = "arbitrary")]
673impl proptest::prelude::Arbitrary for NewPooledTransactionHashes72 {
674 type Parameters = ();
675 fn arbitrary_with(_args: ()) -> Self::Strategy {
676 use proptest::{collection::vec, prelude::*};
677 let vec_length = any::<usize>().prop_map(|x| x % 100 + 1); vec_length
681 .prop_flat_map(|len| {
682 let types_vec = vec(
684 proptest_arbitrary_interop::arb::<reth_ethereum_primitives::TxType>()
685 .prop_map(|ty| ty as u8),
686 len..=len,
687 );
688
689 let sizes_vec = vec(proptest::num::usize::ANY.prop_map(|x| x % 131072), len..=len);
691 let hashes_vec = vec(any::<B256>(), len..=len);
692 let cell_mask = any::<Option<B128>>();
693
694 (types_vec, sizes_vec, hashes_vec, cell_mask)
695 })
696 .prop_map(|(types, sizes, hashes, cell_mask)| Self { types, sizes, hashes, cell_mask })
697 .boxed()
698 }
699
700 type Strategy = proptest::prelude::BoxedStrategy<Self>;
701}
702
703impl NewPooledTransactionHashes72 {
704 pub fn with_capacity(capacity: usize) -> Self {
706 Self {
707 types: Vec::with_capacity(capacity),
708 sizes: Vec::with_capacity(capacity),
709 hashes: Vec::with_capacity(capacity),
710 cell_mask: None,
711 }
712 }
713
714 pub fn metadata_iter(&self) -> impl Iterator<Item = (&B256, (u8, usize))> {
716 self.hashes.iter().zip(self.types.iter().copied().zip(self.sizes.iter().copied()))
717 }
718
719 pub fn push<T: SignedTransaction>(&mut self, tx: &T) {
721 self.hashes.push(*tx.tx_hash());
722 self.sizes.push(tx.encode_2718_len());
723 self.types.push(tx.ty());
724 }
725
726 pub fn extend<'a, T: SignedTransaction>(&mut self, txs: impl IntoIterator<Item = &'a T>) {
728 for tx in txs {
729 self.push(tx);
730 }
731 }
732
733 pub fn shrink_to_fit(&mut self) {
735 self.hashes.shrink_to_fit();
736 self.sizes.shrink_to_fit();
737 self.types.shrink_to_fit()
738 }
739
740 pub fn with_transaction<T: SignedTransaction>(mut self, tx: &T) -> Self {
742 self.push(tx);
743 self
744 }
745
746 pub fn with_transactions<'a, T: SignedTransaction>(
748 mut self,
749 txs: impl IntoIterator<Item = &'a T>,
750 ) -> Self {
751 self.extend(txs);
752 self
753 }
754
755 fn payload_length(&self) -> usize {
756 self.types.as_slice().length() +
757 self.sizes.length() +
758 self.hashes.length() +
759 self.cell_mask.as_ref().map_or(1, Encodable::length)
760 }
761}
762
763impl Encodable for NewPooledTransactionHashes72 {
764 fn encode(&self, out: &mut dyn bytes::BufMut) {
765 Header { list: true, payload_length: self.payload_length() }.encode(out);
766 self.types.as_slice().encode(out);
767 self.sizes.encode(out);
768 self.hashes.encode(out);
769 if let Some(cell_mask) = &self.cell_mask {
770 cell_mask.encode(out);
771 } else {
772 out.put_u8(alloy_rlp::EMPTY_STRING_CODE);
773 }
774 }
775
776 fn length(&self) -> usize {
777 Header { list: true, payload_length: self.payload_length() }.length_with_payload()
778 }
779}
780
781impl Decodable for NewPooledTransactionHashes72 {
782 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
783 let Header { list, payload_length } = Header::decode(buf)?;
784 if !list {
785 return Err(alloy_rlp::Error::UnexpectedString)
786 }
787 if buf.len() < payload_length {
788 return Err(alloy_rlp::Error::InputTooShort)
789 }
790
791 let (mut payload, rest) = buf.split_at(payload_length);
792 let types = Bytes::decode(&mut payload)?;
793 let sizes = Vec::<usize>::decode(&mut payload)?;
794 let hashes = Vec::<B256>::decode(&mut payload)?;
795 let Some(first_byte) = payload.first().copied() else {
796 return Err(alloy_rlp::Error::InputTooShort)
797 };
798 let cell_mask = if first_byte == alloy_rlp::EMPTY_STRING_CODE {
799 payload = &payload[1..];
800 None
801 } else {
802 Some(B128::decode(&mut payload)?)
803 };
804
805 if !payload.is_empty() {
806 return Err(alloy_rlp::Error::ListLengthMismatch {
807 expected: payload_length,
808 got: payload_length - payload.len(),
809 })
810 }
811
812 let msg = Self { types: types.into(), sizes, hashes, cell_mask };
813
814 if msg.hashes.len() != msg.types.len() {
815 return Err(alloy_rlp::Error::ListLengthMismatch {
816 expected: msg.hashes.len(),
817 got: msg.types.len(),
818 })
819 }
820 if msg.hashes.len() != msg.sizes.len() {
821 return Err(alloy_rlp::Error::ListLengthMismatch {
822 expected: msg.hashes.len(),
823 got: msg.sizes.len(),
824 })
825 }
826
827 *buf = rest;
828
829 Ok(msg)
830 }
831}
832
833pub trait DedupPayload {
835 type Value;
837
838 fn is_empty(&self) -> bool;
840
841 fn len(&self) -> usize;
843
844 fn dedup(self) -> PartiallyValidData<Self::Value>;
846}
847
848pub type Eth68TxMetadata = Option<(u8, usize)>;
850
851impl DedupPayload for NewPooledTransactionHashes {
852 type Value = Eth68TxMetadata;
853
854 fn is_empty(&self) -> bool {
855 self.is_empty()
856 }
857
858 fn len(&self) -> usize {
859 self.len()
860 }
861
862 fn dedup(self) -> PartiallyValidData<Self::Value> {
863 match self {
864 Self::Eth66(msg) => msg.dedup(),
865 Self::Eth68(msg) => msg.dedup(),
866 Self::Eth72(msg) => msg.dedup(),
867 }
868 }
869}
870
871impl DedupPayload for NewPooledTransactionHashes72 {
872 type Value = Eth68TxMetadata;
873
874 fn is_empty(&self) -> bool {
875 self.hashes.is_empty()
876 }
877
878 fn len(&self) -> usize {
879 self.hashes.len()
880 }
881
882 fn dedup(self) -> PartiallyValidData<Self::Value> {
883 let Self { hashes, mut sizes, mut types, .. } = self;
884
885 let mut deduped_data = B256Map::with_capacity_and_hasher(hashes.len(), Default::default());
886
887 for hash in hashes.into_iter().rev() {
888 if let (Some(ty), Some(size)) = (types.pop(), sizes.pop()) {
889 deduped_data.insert(hash, Some((ty, size)));
890 }
891 }
892
893 PartiallyValidData::from_raw_data_eth72(deduped_data)
894 }
895}
896
897impl DedupPayload for NewPooledTransactionHashes68 {
898 type Value = Eth68TxMetadata;
899
900 fn is_empty(&self) -> bool {
901 self.hashes.is_empty()
902 }
903
904 fn len(&self) -> usize {
905 self.hashes.len()
906 }
907
908 fn dedup(self) -> PartiallyValidData<Self::Value> {
909 let Self { hashes, mut sizes, mut types } = self;
910
911 let mut deduped_data = B256Map::with_capacity_and_hasher(hashes.len(), Default::default());
912
913 for hash in hashes.into_iter().rev() {
914 if let (Some(ty), Some(size)) = (types.pop(), sizes.pop()) {
915 deduped_data.insert(hash, Some((ty, size)));
916 }
917 }
918
919 PartiallyValidData::from_raw_data_eth68(deduped_data)
920 }
921}
922
923impl DedupPayload for NewPooledTransactionHashes66 {
924 type Value = Eth68TxMetadata;
925
926 fn is_empty(&self) -> bool {
927 self.0.is_empty()
928 }
929
930 fn len(&self) -> usize {
931 self.0.len()
932 }
933
934 fn dedup(self) -> PartiallyValidData<Self::Value> {
935 let Self(hashes) = self;
936
937 let mut deduped_data = B256Map::with_capacity_and_hasher(hashes.len(), Default::default());
938
939 let noop_value: Eth68TxMetadata = None;
940
941 for hash in hashes.into_iter().rev() {
942 deduped_data.insert(hash, noop_value);
943 }
944
945 PartiallyValidData::from_raw_data_eth66(deduped_data)
946 }
947}
948
949pub trait HandleMempoolData {
952 fn is_empty(&self) -> bool;
954
955 fn len(&self) -> usize;
957
958 fn retain_by_hash(&mut self, f: impl FnMut(&TxHash) -> bool);
960}
961
962pub trait HandleVersionedMempoolData {
964 fn msg_version(&self) -> EthVersion;
967}
968
969impl<T: SignedTransaction> HandleMempoolData for Vec<T> {
970 fn is_empty(&self) -> bool {
971 self.is_empty()
972 }
973
974 fn len(&self) -> usize {
975 self.len()
976 }
977
978 fn retain_by_hash(&mut self, mut f: impl FnMut(&TxHash) -> bool) {
979 self.retain(|tx| f(tx.tx_hash()))
980 }
981}
982
983macro_rules! handle_mempool_data_map_impl {
984 ($data_ty:ty, $(<$generic:ident>)?) => {
985 impl$(<$generic>)? HandleMempoolData for $data_ty {
986 fn is_empty(&self) -> bool {
987 self.data.is_empty()
988 }
989
990 fn len(&self) -> usize {
991 self.data.len()
992 }
993
994 fn retain_by_hash(&mut self, mut f: impl FnMut(&TxHash) -> bool) {
995 self.data.retain(|hash, _| f(hash));
996 }
997 }
998 };
999}
1000
1001#[derive(Debug, Deref, DerefMut, IntoIterator)]
1004pub struct PartiallyValidData<V> {
1005 #[deref]
1006 #[deref_mut]
1007 #[into_iterator]
1008 data: B256Map<V>,
1009 version: Option<EthVersion>,
1010}
1011
1012handle_mempool_data_map_impl!(PartiallyValidData<V>, <V>);
1013
1014impl<V> PartiallyValidData<V> {
1015 pub const fn from_raw_data(data: B256Map<V>, version: Option<EthVersion>) -> Self {
1017 Self { data, version }
1018 }
1019
1020 pub const fn from_raw_data_eth72(data: B256Map<V>) -> Self {
1022 Self::from_raw_data(data, Some(EthVersion::Eth72))
1023 }
1024
1025 pub const fn from_raw_data_eth68(data: B256Map<V>) -> Self {
1027 Self::from_raw_data(data, Some(EthVersion::Eth68))
1028 }
1029
1030 pub const fn from_raw_data_eth66(data: B256Map<V>) -> Self {
1032 Self::from_raw_data(data, Some(EthVersion::Eth66))
1033 }
1034
1035 pub fn empty_eth72() -> Self {
1038 Self::from_raw_data_eth72(B256Map::default())
1039 }
1040
1041 pub fn empty_eth68() -> Self {
1044 Self::from_raw_data_eth68(B256Map::default())
1045 }
1046
1047 pub fn empty_eth66() -> Self {
1050 Self::from_raw_data_eth66(B256Map::default())
1051 }
1052
1053 pub const fn msg_version(&self) -> Option<EthVersion> {
1056 self.version
1057 }
1058
1059 pub fn into_data(self) -> B256Map<V> {
1061 self.data
1062 }
1063}
1064
1065#[derive(Debug, Deref, DerefMut, IntoIterator, From)]
1068pub struct ValidAnnouncementData {
1069 #[deref]
1070 #[deref_mut]
1071 #[into_iterator]
1072 data: B256Map<Eth68TxMetadata>,
1073 version: EthVersion,
1074}
1075
1076handle_mempool_data_map_impl!(ValidAnnouncementData,);
1077
1078impl ValidAnnouncementData {
1079 pub fn into_request_hashes(self) -> (RequestTxHashes, EthVersion) {
1082 let hashes = self.data.into_keys().collect::<B256Set>();
1083
1084 (RequestTxHashes::new(hashes), self.version)
1085 }
1086
1087 pub fn from_partially_valid_data(data: PartiallyValidData<Eth68TxMetadata>) -> Self {
1091 let PartiallyValidData { data, version } = data;
1092
1093 let version = version.expect("should have eth version for conversion");
1094
1095 Self { data, version }
1096 }
1097
1098 pub fn into_data(self) -> B256Map<Eth68TxMetadata> {
1100 self.data
1101 }
1102}
1103
1104impl HandleVersionedMempoolData for ValidAnnouncementData {
1105 fn msg_version(&self) -> EthVersion {
1106 self.version
1107 }
1108}
1109
1110#[derive(Debug, Default, Deref, DerefMut, IntoIterator, Constructor)]
1112pub struct RequestTxHashes {
1113 #[deref]
1114 #[deref_mut]
1115 #[into_iterator(owned, ref)]
1116 hashes: B256Set,
1117}
1118
1119impl RequestTxHashes {
1120 pub fn with_capacity(capacity: usize) -> Self {
1125 Self::new(B256Set::with_capacity_and_hasher(capacity, Default::default()))
1126 }
1127
1128 fn empty() -> Self {
1130 Self::new(B256Set::default())
1131 }
1132
1133 pub fn retain_count(&mut self, count: usize) -> Self {
1135 let rest_capacity = self.hashes.len().saturating_sub(count);
1136 if rest_capacity == 0 {
1137 return Self::empty()
1138 }
1139 let mut rest = Self::with_capacity(rest_capacity);
1140
1141 let mut i = 0;
1142 self.hashes.retain(|hash| {
1143 if i >= count {
1144 rest.insert(*hash);
1145 return false
1146 }
1147 i += 1;
1148
1149 true
1150 });
1151
1152 rest
1153 }
1154}
1155
1156impl FromIterator<(TxHash, Eth68TxMetadata)> for RequestTxHashes {
1157 fn from_iter<I: IntoIterator<Item = (TxHash, Eth68TxMetadata)>>(iter: I) -> Self {
1158 Self::new(iter.into_iter().map(|(hash, _)| hash).collect())
1159 }
1160}
1161
1162#[derive(Clone, Debug, PartialEq, Eq, Default, RlpEncodable, RlpDecodable)]
1165#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1166#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
1167pub struct BlockRangeUpdate {
1168 pub earliest: u64,
1170 pub latest: u64,
1172 pub latest_hash: B256,
1174}
1175
1176impl InMemorySize for NewPooledTransactionHashes {
1177 fn size(&self) -> usize {
1178 match self {
1179 Self::Eth66(msg) => msg.0.len() * core::mem::size_of::<B256>(),
1180 Self::Eth68(msg) => {
1181 msg.types.len() * core::mem::size_of::<u8>() +
1182 msg.sizes.len() * core::mem::size_of::<usize>() +
1183 msg.hashes.len() * core::mem::size_of::<B256>()
1184 }
1185 Self::Eth72(msg) => {
1186 msg.types.len() * core::mem::size_of::<u8>() +
1187 msg.sizes.len() * core::mem::size_of::<usize>() +
1188 msg.hashes.len() * core::mem::size_of::<B256>() +
1189 core::mem::size_of::<B128>()
1190 }
1191 }
1192 }
1193}
1194
1195#[cfg(test)]
1196mod tests {
1197 use super::*;
1198 use alloy_consensus::{transaction::TxHashRef, Typed2718};
1199 use alloy_eips::eip2718::Encodable2718;
1200 use alloy_primitives::{b256, hex, Signature, U256};
1201 use reth_ethereum_primitives::{Transaction, TransactionSigned};
1202 use std::str::FromStr;
1203
1204 fn test_encoding_vector<T: Encodable + Decodable + PartialEq + core::fmt::Debug>(
1207 input: (T, &[u8]),
1208 ) {
1209 let (expected_decoded, expected_encoded) = input;
1210 let mut encoded = Vec::new();
1211 expected_decoded.encode(&mut encoded);
1212
1213 assert_eq!(hex::encode(&encoded), hex::encode(expected_encoded));
1214
1215 let decoded = T::decode(&mut encoded.as_ref()).unwrap();
1216 assert_eq!(expected_decoded, decoded);
1217 }
1218
1219 #[test]
1220 fn can_return_latest_block() {
1221 let mut blocks = NewBlockHashes(vec![BlockHashNumber { hash: B256::random(), number: 0 }]);
1222 let latest = blocks.latest().unwrap();
1223 assert_eq!(latest.number, 0);
1224
1225 blocks.push(BlockHashNumber { hash: B256::random(), number: 100 });
1226 blocks.push(BlockHashNumber { hash: B256::random(), number: 2 });
1227 let latest = blocks.latest().unwrap();
1228 assert_eq!(latest.number, 100);
1229 }
1230
1231 #[test]
1232 fn eth_68_tx_hash_roundtrip() {
1233 let vectors = vec![
1234 (
1235 NewPooledTransactionHashes68 { types: vec![], sizes: vec![], hashes: vec![] },
1236 &hex!("c380c0c0")[..],
1237 ),
1238 (
1239 NewPooledTransactionHashes68 {
1240 types: vec![0x00],
1241 sizes: vec![0x00],
1242 hashes: vec![
1243 B256::from_str(
1244 "0x0000000000000000000000000000000000000000000000000000000000000000",
1245 )
1246 .unwrap(),
1247 ],
1248 },
1249 &hex!(
1250 "e500c180e1a00000000000000000000000000000000000000000000000000000000000000000"
1251 )[..],
1252 ),
1253 (
1254 NewPooledTransactionHashes68 {
1255 types: vec![0x00, 0x00],
1256 sizes: vec![0x00, 0x00],
1257 hashes: vec![
1258 B256::from_str(
1259 "0x0000000000000000000000000000000000000000000000000000000000000000",
1260 )
1261 .unwrap(),
1262 B256::from_str(
1263 "0x0000000000000000000000000000000000000000000000000000000000000000",
1264 )
1265 .unwrap(),
1266 ],
1267 },
1268 &hex!(
1269 "f84a820000c28080f842a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000"
1270 )[..],
1271 ),
1272 (
1273 NewPooledTransactionHashes68 {
1274 types: vec![0x02],
1275 sizes: vec![0xb6],
1276 hashes: vec![
1277 B256::from_str(
1278 "0xfecbed04c7b88d8e7221a0a3f5dc33f220212347fc167459ea5cc9c3eb4c1124",
1279 )
1280 .unwrap(),
1281 ],
1282 },
1283 &hex!(
1284 "e602c281b6e1a0fecbed04c7b88d8e7221a0a3f5dc33f220212347fc167459ea5cc9c3eb4c1124"
1285 )[..],
1286 ),
1287 (
1288 NewPooledTransactionHashes68 {
1289 types: vec![0xff, 0xff],
1290 sizes: vec![0xffffffff, 0xffffffff],
1291 hashes: vec![
1292 B256::from_str(
1293 "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
1294 )
1295 .unwrap(),
1296 B256::from_str(
1297 "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
1298 )
1299 .unwrap(),
1300 ],
1301 },
1302 &hex!(
1303 "f85282ffffca84ffffffff84fffffffff842a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
1304 )[..],
1305 ),
1306 (
1307 NewPooledTransactionHashes68 {
1308 types: vec![0xff, 0xff],
1309 sizes: vec![0xffffffff, 0xffffffff],
1310 hashes: vec![
1311 B256::from_str(
1312 "0xbeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafe",
1313 )
1314 .unwrap(),
1315 B256::from_str(
1316 "0xbeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafe",
1317 )
1318 .unwrap(),
1319 ],
1320 },
1321 &hex!(
1322 "f85282ffffca84ffffffff84fffffffff842a0beefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafea0beefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafe"
1323 )[..],
1324 ),
1325 (
1326 NewPooledTransactionHashes68 {
1327 types: vec![0x10, 0x10],
1328 sizes: vec![0xdeadc0de, 0xdeadc0de],
1329 hashes: vec![
1330 B256::from_str(
1331 "0x3b9aca00f0671c9a2a1b817a0a78d3fe0c0f776cccb2a8c3c1b412a4f4e4d4e2",
1332 )
1333 .unwrap(),
1334 B256::from_str(
1335 "0x3b9aca00f0671c9a2a1b817a0a78d3fe0c0f776cccb2a8c3c1b412a4f4e4d4e2",
1336 )
1337 .unwrap(),
1338 ],
1339 },
1340 &hex!(
1341 "f852821010ca84deadc0de84deadc0def842a03b9aca00f0671c9a2a1b817a0a78d3fe0c0f776cccb2a8c3c1b412a4f4e4d4e2a03b9aca00f0671c9a2a1b817a0a78d3fe0c0f776cccb2a8c3c1b412a4f4e4d4e2"
1342 )[..],
1343 ),
1344 (
1345 NewPooledTransactionHashes68 {
1346 types: vec![0x6f, 0x6f],
1347 sizes: vec![0x7fffffff, 0x7fffffff],
1348 hashes: vec![
1349 B256::from_str(
1350 "0x0000000000000000000000000000000000000000000000000000000000000002",
1351 )
1352 .unwrap(),
1353 B256::from_str(
1354 "0x0000000000000000000000000000000000000000000000000000000000000002",
1355 )
1356 .unwrap(),
1357 ],
1358 },
1359 &hex!(
1360 "f852826f6fca847fffffff847ffffffff842a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000002"
1361 )[..],
1362 ),
1363 ];
1364
1365 for vector in vectors {
1366 test_encoding_vector(vector);
1367 }
1368 }
1369
1370 #[test]
1371 fn eth_72_tx_hash_roundtrip() {
1372 let vectors = vec![
1373 (
1374 NewPooledTransactionHashes72 {
1375 types: vec![],
1376 sizes: vec![],
1377 hashes: vec![],
1378 cell_mask: None,
1379 },
1380 &hex!("c480c0c080")[..],
1381 ),
1382 (
1383 NewPooledTransactionHashes72 {
1384 types: vec![],
1385 sizes: vec![],
1386 hashes: vec![],
1387 cell_mask: Some(B128::repeat_byte(0x11)),
1388 },
1389 &hex!("d480c0c09011111111111111111111111111111111")[..],
1390 ),
1391 ];
1392
1393 for vector in vectors {
1394 test_encoding_vector(vector);
1395 }
1396 }
1397
1398 #[test]
1399 fn eth_72_rejects_missing_cell_mask() {
1400 let encoded_eth68_payload = hex!("c380c0c0");
1401
1402 let result = NewPooledTransactionHashes72::decode(&mut encoded_eth68_payload.as_ref());
1403
1404 assert!(matches!(result, Err(alloy_rlp::Error::InputTooShort)));
1405 }
1406
1407 #[test]
1408 fn request_hashes_retain_count_keep_subset() {
1409 let mut hashes = RequestTxHashes::new(
1410 [
1411 b256!("0x0000000000000000000000000000000000000000000000000000000000000001"),
1412 b256!("0x0000000000000000000000000000000000000000000000000000000000000002"),
1413 b256!("0x0000000000000000000000000000000000000000000000000000000000000003"),
1414 b256!("0x0000000000000000000000000000000000000000000000000000000000000004"),
1415 b256!("0x0000000000000000000000000000000000000000000000000000000000000005"),
1416 ]
1417 .into_iter()
1418 .collect::<B256Set>(),
1419 );
1420
1421 let rest = hashes.retain_count(3);
1422
1423 assert_eq!(3, hashes.len());
1424 assert_eq!(2, rest.len());
1425 }
1426
1427 #[test]
1428 fn request_hashes_retain_count_keep_all() {
1429 let mut hashes = RequestTxHashes::new(
1430 [
1431 b256!("0x0000000000000000000000000000000000000000000000000000000000000001"),
1432 b256!("0x0000000000000000000000000000000000000000000000000000000000000002"),
1433 b256!("0x0000000000000000000000000000000000000000000000000000000000000003"),
1434 b256!("0x0000000000000000000000000000000000000000000000000000000000000004"),
1435 b256!("0x0000000000000000000000000000000000000000000000000000000000000005"),
1436 ]
1437 .into_iter()
1438 .collect::<B256Set>(),
1439 );
1440
1441 let _ = hashes.retain_count(6);
1442
1443 assert_eq!(5, hashes.len());
1444 }
1445
1446 #[test]
1447 fn split_request_hashes_keep_none() {
1448 let mut hashes = RequestTxHashes::new(
1449 [
1450 b256!("0x0000000000000000000000000000000000000000000000000000000000000001"),
1451 b256!("0x0000000000000000000000000000000000000000000000000000000000000002"),
1452 b256!("0x0000000000000000000000000000000000000000000000000000000000000003"),
1453 b256!("0x0000000000000000000000000000000000000000000000000000000000000004"),
1454 b256!("0x0000000000000000000000000000000000000000000000000000000000000005"),
1455 ]
1456 .into_iter()
1457 .collect::<B256Set>(),
1458 );
1459
1460 let rest = hashes.retain_count(0);
1461
1462 assert_eq!(0, hashes.len());
1463 assert_eq!(5, rest.len());
1464 }
1465
1466 fn signed_transaction() -> impl SignedTransaction {
1467 TransactionSigned::new_unhashed(
1468 Transaction::Legacy(Default::default()),
1469 Signature::new(
1470 U256::from_str(
1471 "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12",
1472 )
1473 .unwrap(),
1474 U256::from_str(
1475 "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10",
1476 )
1477 .unwrap(),
1478 false,
1479 ),
1480 )
1481 }
1482
1483 #[test]
1484 fn test_pooled_tx_hashes_68_push() {
1485 let tx = signed_transaction();
1486 let mut tx_hashes =
1487 NewPooledTransactionHashes68 { types: vec![], sizes: vec![], hashes: vec![] };
1488 tx_hashes.push(&tx);
1489 assert_eq!(tx_hashes.types.len(), 1);
1490 assert_eq!(tx_hashes.sizes.len(), 1);
1491 assert_eq!(tx_hashes.hashes.len(), 1);
1492 assert_eq!(tx_hashes.types[0], tx.ty());
1493 assert_eq!(tx_hashes.sizes[0], tx.encode_2718_len());
1494 assert_eq!(tx_hashes.hashes[0], *tx.tx_hash());
1495 }
1496
1497 #[test]
1498 fn test_pooled_tx_hashes_68_extend() {
1499 let tx = signed_transaction();
1500 let txs = vec![tx.clone(), tx.clone()];
1501 let mut tx_hashes =
1502 NewPooledTransactionHashes68 { types: vec![], sizes: vec![], hashes: vec![] };
1503 tx_hashes.extend(&txs);
1504 assert_eq!(tx_hashes.types.len(), 2);
1505 assert_eq!(tx_hashes.sizes.len(), 2);
1506 assert_eq!(tx_hashes.hashes.len(), 2);
1507 assert_eq!(tx_hashes.types[0], tx.ty());
1508 assert_eq!(tx_hashes.sizes[0], tx.encode_2718_len());
1509 assert_eq!(tx_hashes.hashes[0], *tx.tx_hash());
1510 assert_eq!(tx_hashes.types[1], tx.ty());
1511 assert_eq!(tx_hashes.sizes[1], tx.encode_2718_len());
1512 assert_eq!(tx_hashes.hashes[1], *tx.tx_hash());
1513 }
1514
1515 #[test]
1516 fn test_pooled_tx_hashes_68_with_transaction() {
1517 let tx = signed_transaction();
1518 let tx_hashes =
1519 NewPooledTransactionHashes68 { types: vec![], sizes: vec![], hashes: vec![] }
1520 .with_transaction(&tx);
1521 assert_eq!(tx_hashes.types.len(), 1);
1522 assert_eq!(tx_hashes.sizes.len(), 1);
1523 assert_eq!(tx_hashes.hashes.len(), 1);
1524 assert_eq!(tx_hashes.types[0], tx.ty());
1525 assert_eq!(tx_hashes.sizes[0], tx.encode_2718_len());
1526 assert_eq!(tx_hashes.hashes[0], *tx.tx_hash());
1527 }
1528
1529 #[test]
1530 fn test_pooled_tx_hashes_68_with_transactions() {
1531 let tx = signed_transaction();
1532 let txs = vec![tx.clone(), tx.clone()];
1533 let tx_hashes =
1534 NewPooledTransactionHashes68 { types: vec![], sizes: vec![], hashes: vec![] }
1535 .with_transactions(&txs);
1536 assert_eq!(tx_hashes.types.len(), 2);
1537 assert_eq!(tx_hashes.sizes.len(), 2);
1538 assert_eq!(tx_hashes.hashes.len(), 2);
1539 assert_eq!(tx_hashes.types[0], tx.ty());
1540 assert_eq!(tx_hashes.sizes[0], tx.encode_2718_len());
1541 assert_eq!(tx_hashes.hashes[0], *tx.tx_hash());
1542 assert_eq!(tx_hashes.types[1], tx.ty());
1543 assert_eq!(tx_hashes.sizes[1], tx.encode_2718_len());
1544 assert_eq!(tx_hashes.hashes[1], *tx.tx_hash());
1545 }
1546}