1use crate::{EthMessage, EthVersion, NetworkPrimitives};
4use alloy_primitives::{Bytes, TxHash, B256, U128};
5use alloy_rlp::{
6 Decodable, Encodable, RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper,
7};
8use derive_more::{Constructor, Deref, DerefMut, From, IntoIterator};
9use reth_codecs_derive::{add_arbitrary_tests, generate_tests};
10use reth_primitives::TransactionSigned;
11use reth_primitives_traits::SignedTransaction;
12use std::{
13 collections::{HashMap, HashSet},
14 mem,
15 sync::Arc,
16};
17
18#[cfg(feature = "arbitrary")]
19use proptest::{collection::vec, prelude::*};
20#[cfg(feature = "arbitrary")]
21use proptest_arbitrary_interop::arb;
22
23#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper, Default)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
27#[add_arbitrary_tests(rlp)]
28pub struct NewBlockHashes(
29 pub Vec<BlockHashNumber>,
32);
33
34impl NewBlockHashes {
37 pub fn latest(&self) -> Option<&BlockHashNumber> {
39 self.0.iter().fold(None, |latest, block| {
40 if let Some(latest) = latest {
41 return if latest.number > block.number { Some(latest) } else { Some(block) }
42 }
43 Some(block)
44 })
45 }
46}
47
48#[derive(Clone, Debug, PartialEq, Eq, RlpEncodable, RlpDecodable, Default)]
50#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
51#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
52#[add_arbitrary_tests(rlp)]
53pub struct BlockHashNumber {
54 pub hash: B256,
56 pub number: u64,
58}
59
60impl From<Vec<BlockHashNumber>> for NewBlockHashes {
61 fn from(v: Vec<BlockHashNumber>) -> Self {
62 Self(v)
63 }
64}
65
66impl From<NewBlockHashes> for Vec<BlockHashNumber> {
67 fn from(v: NewBlockHashes) -> Self {
68 v.0
69 }
70}
71
72#[derive(Clone, Debug, PartialEq, Eq, RlpEncodable, RlpDecodable, Default)]
75#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
76#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
77pub struct NewBlock<B = reth_primitives::Block> {
78 pub block: B,
80 pub td: U128,
82}
83
84generate_tests!(#[rlp, 25] NewBlock<reth_primitives::Block>, EthNewBlockTests);
85
86#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper, Default)]
89#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
90#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
91#[add_arbitrary_tests(rlp, 10)]
92pub struct Transactions<T = TransactionSigned>(
93 pub Vec<T>,
95);
96
97impl<T: SignedTransaction> Transactions<T> {
98 pub fn has_eip4844(&self) -> bool {
100 self.0.iter().any(|tx| tx.is_eip4844())
101 }
102}
103
104impl<T> From<Vec<T>> for Transactions<T> {
105 fn from(txs: Vec<T>) -> Self {
106 Self(txs)
107 }
108}
109
110impl<T> From<Transactions<T>> for Vec<T> {
111 fn from(txs: Transactions<T>) -> Self {
112 txs.0
113 }
114}
115
116#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper)]
121#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
122#[add_arbitrary_tests(rlp, 20)]
123pub struct SharedTransactions<T = TransactionSigned>(
124 pub Vec<Arc<T>>,
126);
127
128#[derive(Clone, Debug, PartialEq, Eq)]
130pub enum NewPooledTransactionHashes {
131 Eth66(NewPooledTransactionHashes66),
133 Eth68(NewPooledTransactionHashes68),
137}
138
139impl NewPooledTransactionHashes {
142 pub const fn version(&self) -> EthVersion {
144 match self {
145 Self::Eth66(_) => EthVersion::Eth66,
146 Self::Eth68(_) => EthVersion::Eth68,
147 }
148 }
149
150 pub const fn is_valid_for_version(&self, version: EthVersion) -> bool {
152 match self {
153 Self::Eth66(_) => {
154 matches!(version, EthVersion::Eth67 | EthVersion::Eth66)
155 }
156 Self::Eth68(_) => {
157 matches!(version, EthVersion::Eth68)
158 }
159 }
160 }
161
162 pub fn iter_hashes(&self) -> impl Iterator<Item = &B256> + '_ {
164 match self {
165 Self::Eth66(msg) => msg.0.iter(),
166 Self::Eth68(msg) => msg.hashes.iter(),
167 }
168 }
169
170 pub const fn hashes(&self) -> &Vec<B256> {
172 match self {
173 Self::Eth66(msg) => &msg.0,
174 Self::Eth68(msg) => &msg.hashes,
175 }
176 }
177
178 pub fn hashes_mut(&mut self) -> &mut Vec<B256> {
180 match self {
181 Self::Eth66(msg) => &mut msg.0,
182 Self::Eth68(msg) => &mut msg.hashes,
183 }
184 }
185
186 pub fn into_hashes(self) -> Vec<B256> {
188 match self {
189 Self::Eth66(msg) => msg.0,
190 Self::Eth68(msg) => msg.hashes,
191 }
192 }
193
194 pub fn into_iter_hashes(self) -> impl Iterator<Item = B256> {
196 match self {
197 Self::Eth66(msg) => msg.0.into_iter(),
198 Self::Eth68(msg) => msg.hashes.into_iter(),
199 }
200 }
201
202 pub fn truncate(&mut self, len: usize) {
205 match self {
206 Self::Eth66(msg) => msg.0.truncate(len),
207 Self::Eth68(msg) => {
208 msg.types.truncate(len);
209 msg.sizes.truncate(len);
210 msg.hashes.truncate(len);
211 }
212 }
213 }
214
215 pub fn is_empty(&self) -> bool {
217 match self {
218 Self::Eth66(msg) => msg.0.is_empty(),
219 Self::Eth68(msg) => msg.hashes.is_empty(),
220 }
221 }
222
223 pub fn len(&self) -> usize {
225 match self {
226 Self::Eth66(msg) => msg.0.len(),
227 Self::Eth68(msg) => msg.hashes.len(),
228 }
229 }
230
231 pub const fn as_eth68(&self) -> Option<&NewPooledTransactionHashes68> {
233 match self {
234 Self::Eth66(_) => None,
235 Self::Eth68(msg) => Some(msg),
236 }
237 }
238
239 pub fn as_eth68_mut(&mut self) -> Option<&mut NewPooledTransactionHashes68> {
241 match self {
242 Self::Eth66(_) => None,
243 Self::Eth68(msg) => Some(msg),
244 }
245 }
246
247 pub fn as_eth66_mut(&mut self) -> Option<&mut NewPooledTransactionHashes66> {
249 match self {
250 Self::Eth66(msg) => Some(msg),
251 Self::Eth68(_) => None,
252 }
253 }
254
255 pub fn take_eth68(&mut self) -> Option<NewPooledTransactionHashes68> {
257 match self {
258 Self::Eth66(_) => None,
259 Self::Eth68(msg) => Some(mem::take(msg)),
260 }
261 }
262
263 pub fn take_eth66(&mut self) -> Option<NewPooledTransactionHashes66> {
265 match self {
266 Self::Eth66(msg) => Some(mem::take(msg)),
267 Self::Eth68(_) => None,
268 }
269 }
270}
271
272impl<N: NetworkPrimitives> From<NewPooledTransactionHashes> for EthMessage<N> {
273 fn from(value: NewPooledTransactionHashes) -> Self {
274 match value {
275 NewPooledTransactionHashes::Eth66(msg) => Self::NewPooledTransactionHashes66(msg),
276 NewPooledTransactionHashes::Eth68(msg) => Self::NewPooledTransactionHashes68(msg),
277 }
278 }
279}
280
281impl From<NewPooledTransactionHashes66> for NewPooledTransactionHashes {
282 fn from(hashes: NewPooledTransactionHashes66) -> Self {
283 Self::Eth66(hashes)
284 }
285}
286
287impl From<NewPooledTransactionHashes68> for NewPooledTransactionHashes {
288 fn from(hashes: NewPooledTransactionHashes68) -> Self {
289 Self::Eth68(hashes)
290 }
291}
292
293#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper, Default)]
296#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
297#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
298#[add_arbitrary_tests(rlp)]
299pub struct NewPooledTransactionHashes66(
300 pub Vec<B256>,
304);
305
306impl From<Vec<B256>> for NewPooledTransactionHashes66 {
307 fn from(v: Vec<B256>) -> Self {
308 Self(v)
309 }
310}
311
312#[derive(Clone, Debug, PartialEq, Eq, Default)]
315#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
316pub struct NewPooledTransactionHashes68 {
317 pub types: Vec<u8>,
341 pub sizes: Vec<usize>,
343 pub hashes: Vec<B256>,
345}
346
347#[cfg(feature = "arbitrary")]
348impl Arbitrary for NewPooledTransactionHashes68 {
349 type Parameters = ();
350 fn arbitrary_with(_args: ()) -> Self::Strategy {
351 let vec_length = any::<usize>().prop_map(|x| x % 100 + 1); vec_length
355 .prop_flat_map(|len| {
356 let types_vec =
358 vec(arb::<reth_primitives::TxType>().prop_map(|ty| ty as u8), len..=len);
359
360 let sizes_vec = vec(proptest::num::usize::ANY.prop_map(|x| x % 131072), len..=len);
362 let hashes_vec = vec(any::<B256>(), len..=len);
363
364 (types_vec, sizes_vec, hashes_vec)
365 })
366 .prop_map(|(types, sizes, hashes)| Self { types, sizes, hashes })
367 .boxed()
368 }
369
370 type Strategy = BoxedStrategy<Self>;
371}
372
373impl NewPooledTransactionHashes68 {
374 pub fn metadata_iter(&self) -> impl Iterator<Item = (&B256, (u8, usize))> {
376 self.hashes.iter().zip(self.types.iter().copied().zip(self.sizes.iter().copied()))
377 }
378}
379
380impl Encodable for NewPooledTransactionHashes68 {
381 fn encode(&self, out: &mut dyn bytes::BufMut) {
382 #[derive(RlpEncodable)]
383 struct EncodableNewPooledTransactionHashes68<'a> {
384 types: &'a [u8],
385 sizes: &'a Vec<usize>,
386 hashes: &'a Vec<B256>,
387 }
388
389 let encodable = EncodableNewPooledTransactionHashes68 {
390 types: &self.types[..],
391 sizes: &self.sizes,
392 hashes: &self.hashes,
393 };
394
395 encodable.encode(out);
396 }
397 fn length(&self) -> usize {
398 #[derive(RlpEncodable)]
399 struct EncodableNewPooledTransactionHashes68<'a> {
400 types: &'a [u8],
401 sizes: &'a Vec<usize>,
402 hashes: &'a Vec<B256>,
403 }
404
405 let encodable = EncodableNewPooledTransactionHashes68 {
406 types: &self.types[..],
407 sizes: &self.sizes,
408 hashes: &self.hashes,
409 };
410
411 encodable.length()
412 }
413}
414
415impl Decodable for NewPooledTransactionHashes68 {
416 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
417 #[derive(RlpDecodable)]
418 struct EncodableNewPooledTransactionHashes68 {
419 types: Bytes,
420 sizes: Vec<usize>,
421 hashes: Vec<B256>,
422 }
423
424 let encodable = EncodableNewPooledTransactionHashes68::decode(buf)?;
425 let msg = Self {
426 types: encodable.types.into(),
427 sizes: encodable.sizes,
428 hashes: encodable.hashes,
429 };
430
431 if msg.hashes.len() != msg.types.len() {
432 return Err(alloy_rlp::Error::ListLengthMismatch {
433 expected: msg.hashes.len(),
434 got: msg.types.len(),
435 })
436 }
437 if msg.hashes.len() != msg.sizes.len() {
438 return Err(alloy_rlp::Error::ListLengthMismatch {
439 expected: msg.hashes.len(),
440 got: msg.sizes.len(),
441 })
442 }
443
444 Ok(msg)
445 }
446}
447
448pub trait DedupPayload {
450 type Value;
452
453 fn is_empty(&self) -> bool;
455
456 fn len(&self) -> usize;
458
459 fn dedup(self) -> PartiallyValidData<Self::Value>;
461}
462
463pub type Eth68TxMetadata = Option<(u8, usize)>;
465
466impl DedupPayload for NewPooledTransactionHashes {
467 type Value = Eth68TxMetadata;
468
469 fn is_empty(&self) -> bool {
470 self.is_empty()
471 }
472
473 fn len(&self) -> usize {
474 self.len()
475 }
476
477 fn dedup(self) -> PartiallyValidData<Self::Value> {
478 match self {
479 Self::Eth66(msg) => msg.dedup(),
480 Self::Eth68(msg) => msg.dedup(),
481 }
482 }
483}
484
485impl DedupPayload for NewPooledTransactionHashes68 {
486 type Value = Eth68TxMetadata;
487
488 fn is_empty(&self) -> bool {
489 self.hashes.is_empty()
490 }
491
492 fn len(&self) -> usize {
493 self.hashes.len()
494 }
495
496 fn dedup(self) -> PartiallyValidData<Self::Value> {
497 let Self { hashes, mut sizes, mut types } = self;
498
499 let mut deduped_data = HashMap::with_capacity(hashes.len());
500
501 for hash in hashes.into_iter().rev() {
502 if let (Some(ty), Some(size)) = (types.pop(), sizes.pop()) {
503 deduped_data.insert(hash, Some((ty, size)));
504 }
505 }
506
507 PartiallyValidData::from_raw_data_eth68(deduped_data)
508 }
509}
510
511impl DedupPayload for NewPooledTransactionHashes66 {
512 type Value = Eth68TxMetadata;
513
514 fn is_empty(&self) -> bool {
515 self.0.is_empty()
516 }
517
518 fn len(&self) -> usize {
519 self.0.len()
520 }
521
522 fn dedup(self) -> PartiallyValidData<Self::Value> {
523 let Self(hashes) = self;
524
525 let mut deduped_data = HashMap::with_capacity(hashes.len());
526
527 let noop_value: Eth68TxMetadata = None;
528
529 for hash in hashes.into_iter().rev() {
530 deduped_data.insert(hash, noop_value);
531 }
532
533 PartiallyValidData::from_raw_data_eth66(deduped_data)
534 }
535}
536
537pub trait HandleMempoolData {
540 fn is_empty(&self) -> bool;
542
543 fn len(&self) -> usize;
545
546 fn retain_by_hash(&mut self, f: impl FnMut(&TxHash) -> bool);
548}
549
550pub trait HandleVersionedMempoolData {
552 fn msg_version(&self) -> EthVersion;
555}
556
557impl<T: SignedTransaction> HandleMempoolData for Vec<T> {
558 fn is_empty(&self) -> bool {
559 self.is_empty()
560 }
561
562 fn len(&self) -> usize {
563 self.len()
564 }
565
566 fn retain_by_hash(&mut self, mut f: impl FnMut(&TxHash) -> bool) {
567 self.retain(|tx| f(tx.tx_hash()))
568 }
569}
570
571macro_rules! handle_mempool_data_map_impl {
572 ($data_ty:ty, $(<$generic:ident>)?) => {
573 impl$(<$generic>)? HandleMempoolData for $data_ty {
574 fn is_empty(&self) -> bool {
575 self.data.is_empty()
576 }
577
578 fn len(&self) -> usize {
579 self.data.len()
580 }
581
582 fn retain_by_hash(&mut self, mut f: impl FnMut(&TxHash) -> bool) {
583 self.data.retain(|hash, _| f(hash));
584 }
585 }
586 };
587}
588
589#[derive(Debug, Deref, DerefMut, IntoIterator)]
592pub struct PartiallyValidData<V> {
593 #[deref]
594 #[deref_mut]
595 #[into_iterator]
596 data: HashMap<TxHash, V>,
597 version: Option<EthVersion>,
598}
599
600handle_mempool_data_map_impl!(PartiallyValidData<V>, <V>);
601
602impl<V> PartiallyValidData<V> {
603 pub const fn from_raw_data(data: HashMap<TxHash, V>, version: Option<EthVersion>) -> Self {
605 Self { data, version }
606 }
607
608 pub const fn from_raw_data_eth68(data: HashMap<TxHash, V>) -> Self {
610 Self::from_raw_data(data, Some(EthVersion::Eth68))
611 }
612
613 pub const fn from_raw_data_eth66(data: HashMap<TxHash, V>) -> Self {
615 Self::from_raw_data(data, Some(EthVersion::Eth66))
616 }
617
618 pub fn empty_eth68() -> Self {
621 Self::from_raw_data_eth68(HashMap::default())
622 }
623
624 pub fn empty_eth66() -> Self {
627 Self::from_raw_data_eth66(HashMap::default())
628 }
629
630 pub const fn msg_version(&self) -> Option<EthVersion> {
633 self.version
634 }
635
636 pub fn into_data(self) -> HashMap<TxHash, V> {
638 self.data
639 }
640}
641
642#[derive(Debug, Deref, DerefMut, IntoIterator, From)]
645pub struct ValidAnnouncementData {
646 #[deref]
647 #[deref_mut]
648 #[into_iterator]
649 data: HashMap<TxHash, Eth68TxMetadata>,
650 version: EthVersion,
651}
652
653handle_mempool_data_map_impl!(ValidAnnouncementData,);
654
655impl ValidAnnouncementData {
656 pub fn into_request_hashes(self) -> (RequestTxHashes, EthVersion) {
659 let hashes = self.data.into_keys().collect::<HashSet<_>>();
660
661 (RequestTxHashes::new(hashes), self.version)
662 }
663
664 pub fn from_partially_valid_data(data: PartiallyValidData<Eth68TxMetadata>) -> Self {
668 let PartiallyValidData { data, version } = data;
669
670 let version = version.expect("should have eth version for conversion");
671
672 Self { data, version }
673 }
674
675 pub fn into_data(self) -> HashMap<TxHash, Eth68TxMetadata> {
677 self.data
678 }
679}
680
681impl HandleVersionedMempoolData for ValidAnnouncementData {
682 fn msg_version(&self) -> EthVersion {
683 self.version
684 }
685}
686
687#[derive(Debug, Default, Deref, DerefMut, IntoIterator, Constructor)]
689pub struct RequestTxHashes {
690 #[deref]
691 #[deref_mut]
692 #[into_iterator(owned, ref)]
693 hashes: HashSet<TxHash>,
694}
695
696impl RequestTxHashes {
697 pub fn with_capacity(capacity: usize) -> Self {
702 Self::new(HashSet::with_capacity(capacity))
703 }
704
705 fn empty() -> Self {
707 Self::new(HashSet::default())
708 }
709
710 pub fn retain_count(&mut self, count: usize) -> Self {
712 let rest_capacity = self.hashes.len().saturating_sub(count);
713 if rest_capacity == 0 {
714 return Self::empty()
715 }
716 let mut rest = Self::with_capacity(rest_capacity);
717
718 let mut i = 0;
719 self.hashes.retain(|hash| {
720 if i >= count {
721 rest.insert(*hash);
722 return false
723 }
724 i += 1;
725
726 true
727 });
728
729 rest
730 }
731}
732
733impl FromIterator<(TxHash, Eth68TxMetadata)> for RequestTxHashes {
734 fn from_iter<I: IntoIterator<Item = (TxHash, Eth68TxMetadata)>>(iter: I) -> Self {
735 Self::new(iter.into_iter().map(|(hash, _)| hash).collect())
736 }
737}
738
739#[cfg(test)]
740mod tests {
741 use super::*;
742 use alloy_primitives::{b256, hex};
743 use std::str::FromStr;
744
745 fn test_encoding_vector<T: Encodable + Decodable + PartialEq + std::fmt::Debug>(
748 input: (T, &[u8]),
749 ) {
750 let (expected_decoded, expected_encoded) = input;
751 let mut encoded = Vec::new();
752 expected_decoded.encode(&mut encoded);
753
754 assert_eq!(hex::encode(&encoded), hex::encode(expected_encoded));
755
756 let decoded = T::decode(&mut encoded.as_ref()).unwrap();
757 assert_eq!(expected_decoded, decoded);
758 }
759
760 #[test]
761 fn can_return_latest_block() {
762 let mut blocks = NewBlockHashes(vec![BlockHashNumber { hash: B256::random(), number: 0 }]);
763 let latest = blocks.latest().unwrap();
764 assert_eq!(latest.number, 0);
765
766 blocks.0.push(BlockHashNumber { hash: B256::random(), number: 100 });
767 blocks.0.push(BlockHashNumber { hash: B256::random(), number: 2 });
768 let latest = blocks.latest().unwrap();
769 assert_eq!(latest.number, 100);
770 }
771
772 #[test]
773 fn eth_68_tx_hash_roundtrip() {
774 let vectors = vec![
775 (
776 NewPooledTransactionHashes68 { types: vec![], sizes: vec![], hashes: vec![] },
777 &hex!("c380c0c0")[..],
778 ),
779 (
780 NewPooledTransactionHashes68 {
781 types: vec![0x00],
782 sizes: vec![0x00],
783 hashes: vec![B256::from_str(
784 "0x0000000000000000000000000000000000000000000000000000000000000000",
785 )
786 .unwrap()],
787 },
788 &hex!("e500c180e1a00000000000000000000000000000000000000000000000000000000000000000")[..],
789 ),
790 (
791 NewPooledTransactionHashes68 {
792 types: vec![0x00, 0x00],
793 sizes: vec![0x00, 0x00],
794 hashes: vec![
795 B256::from_str(
796 "0x0000000000000000000000000000000000000000000000000000000000000000",
797 )
798 .unwrap(),
799 B256::from_str(
800 "0x0000000000000000000000000000000000000000000000000000000000000000",
801 )
802 .unwrap(),
803 ],
804 },
805 &hex!("f84a820000c28080f842a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000")[..],
806 ),
807 (
808 NewPooledTransactionHashes68 {
809 types: vec![0x02],
810 sizes: vec![0xb6],
811 hashes: vec![B256::from_str(
812 "0xfecbed04c7b88d8e7221a0a3f5dc33f220212347fc167459ea5cc9c3eb4c1124",
813 )
814 .unwrap()],
815 },
816 &hex!("e602c281b6e1a0fecbed04c7b88d8e7221a0a3f5dc33f220212347fc167459ea5cc9c3eb4c1124")[..],
817 ),
818 (
819 NewPooledTransactionHashes68 {
820 types: vec![0xff, 0xff],
821 sizes: vec![0xffffffff, 0xffffffff],
822 hashes: vec![
823 B256::from_str(
824 "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
825 )
826 .unwrap(),
827 B256::from_str(
828 "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
829 )
830 .unwrap(),
831 ],
832 },
833 &hex!("f85282ffffca84ffffffff84fffffffff842a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[..],
834 ),
835 (
836 NewPooledTransactionHashes68 {
837 types: vec![0xff, 0xff],
838 sizes: vec![0xffffffff, 0xffffffff],
839 hashes: vec![
840 B256::from_str(
841 "0xbeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafe",
842 )
843 .unwrap(),
844 B256::from_str(
845 "0xbeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafe",
846 )
847 .unwrap(),
848 ],
849 },
850 &hex!("f85282ffffca84ffffffff84fffffffff842a0beefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafea0beefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafe")[..],
851 ),
852 (
853 NewPooledTransactionHashes68 {
854 types: vec![0x10, 0x10],
855 sizes: vec![0xdeadc0de, 0xdeadc0de],
856 hashes: vec![
857 B256::from_str(
858 "0x3b9aca00f0671c9a2a1b817a0a78d3fe0c0f776cccb2a8c3c1b412a4f4e4d4e2",
859 )
860 .unwrap(),
861 B256::from_str(
862 "0x3b9aca00f0671c9a2a1b817a0a78d3fe0c0f776cccb2a8c3c1b412a4f4e4d4e2",
863 )
864 .unwrap(),
865 ],
866 },
867 &hex!("f852821010ca84deadc0de84deadc0def842a03b9aca00f0671c9a2a1b817a0a78d3fe0c0f776cccb2a8c3c1b412a4f4e4d4e2a03b9aca00f0671c9a2a1b817a0a78d3fe0c0f776cccb2a8c3c1b412a4f4e4d4e2")[..],
868 ),
869 (
870 NewPooledTransactionHashes68 {
871 types: vec![0x6f, 0x6f],
872 sizes: vec![0x7fffffff, 0x7fffffff],
873 hashes: vec![
874 B256::from_str(
875 "0x0000000000000000000000000000000000000000000000000000000000000002",
876 )
877 .unwrap(),
878 B256::from_str(
879 "0x0000000000000000000000000000000000000000000000000000000000000002",
880 )
881 .unwrap(),
882 ],
883 },
884 &hex!("f852826f6fca847fffffff847ffffffff842a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000002")[..],
885 ),
886 ];
887
888 for vector in vectors {
889 test_encoding_vector(vector);
890 }
891 }
892
893 #[test]
894 fn request_hashes_retain_count_keep_subset() {
895 let mut hashes = RequestTxHashes::new(
896 [
897 b256!("0000000000000000000000000000000000000000000000000000000000000001"),
898 b256!("0000000000000000000000000000000000000000000000000000000000000002"),
899 b256!("0000000000000000000000000000000000000000000000000000000000000003"),
900 b256!("0000000000000000000000000000000000000000000000000000000000000004"),
901 b256!("0000000000000000000000000000000000000000000000000000000000000005"),
902 ]
903 .into_iter()
904 .collect::<HashSet<_>>(),
905 );
906
907 let rest = hashes.retain_count(3);
908
909 assert_eq!(3, hashes.len());
910 assert_eq!(2, rest.len());
911 }
912
913 #[test]
914 fn request_hashes_retain_count_keep_all() {
915 let mut hashes = RequestTxHashes::new(
916 [
917 b256!("0000000000000000000000000000000000000000000000000000000000000001"),
918 b256!("0000000000000000000000000000000000000000000000000000000000000002"),
919 b256!("0000000000000000000000000000000000000000000000000000000000000003"),
920 b256!("0000000000000000000000000000000000000000000000000000000000000004"),
921 b256!("0000000000000000000000000000000000000000000000000000000000000005"),
922 ]
923 .into_iter()
924 .collect::<HashSet<_>>(),
925 );
926
927 let _ = hashes.retain_count(6);
928
929 assert_eq!(5, hashes.len());
930 }
931
932 #[test]
933 fn split_request_hashes_keep_none() {
934 let mut hashes = RequestTxHashes::new(
935 [
936 b256!("0000000000000000000000000000000000000000000000000000000000000001"),
937 b256!("0000000000000000000000000000000000000000000000000000000000000002"),
938 b256!("0000000000000000000000000000000000000000000000000000000000000003"),
939 b256!("0000000000000000000000000000000000000000000000000000000000000004"),
940 b256!("0000000000000000000000000000000000000000000000000000000000000005"),
941 ]
942 .into_iter()
943 .collect::<HashSet<_>>(),
944 );
945
946 let rest = hashes.retain_count(0);
947
948 assert_eq!(0, hashes.len());
949 assert_eq!(5, rest.len());
950 }
951}