1use crate::{EthMessage, EthVersion, NetworkPrimitives};
4use alloc::{sync::Arc, vec::Vec};
5use alloy_primitives::{
6 map::{HashMap, HashSet},
7 Bytes, TxHash, B256, U128,
8};
9use alloy_rlp::{
10 Decodable, Encodable, RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper,
11};
12use core::mem;
13use derive_more::{Constructor, Deref, DerefMut, From, IntoIterator};
14use reth_codecs_derive::{add_arbitrary_tests, generate_tests};
15use reth_ethereum_primitives::TransactionSigned;
16use reth_primitives_traits::SignedTransaction;
17
18#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper, Default)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
21#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
22#[add_arbitrary_tests(rlp)]
23pub struct NewBlockHashes(
24 pub Vec<BlockHashNumber>,
27);
28
29impl NewBlockHashes {
32 pub fn latest(&self) -> Option<&BlockHashNumber> {
34 self.0.iter().fold(None, |latest, block| {
35 if let Some(latest) = latest {
36 return if latest.number > block.number { Some(latest) } else { Some(block) }
37 }
38 Some(block)
39 })
40 }
41}
42
43#[derive(Clone, Debug, PartialEq, Eq, RlpEncodable, RlpDecodable, Default)]
45#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
46#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
47#[add_arbitrary_tests(rlp)]
48pub struct BlockHashNumber {
49 pub hash: B256,
51 pub number: u64,
53}
54
55impl From<Vec<BlockHashNumber>> for NewBlockHashes {
56 fn from(v: Vec<BlockHashNumber>) -> Self {
57 Self(v)
58 }
59}
60
61impl From<NewBlockHashes> for Vec<BlockHashNumber> {
62 fn from(v: NewBlockHashes) -> Self {
63 v.0
64 }
65}
66
67#[derive(Clone, Debug, PartialEq, Eq, RlpEncodable, RlpDecodable, Default)]
70#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
71#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
72pub struct NewBlock<B = reth_ethereum_primitives::Block> {
73 pub block: B,
75 pub td: U128,
77}
78
79generate_tests!(#[rlp, 25] NewBlock<reth_ethereum_primitives::Block>, EthNewBlockTests);
80
81#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper, Default)]
84#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
85#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
86#[add_arbitrary_tests(rlp, 10)]
87pub struct Transactions<T = TransactionSigned>(
88 pub Vec<T>,
90);
91
92impl<T: SignedTransaction> Transactions<T> {
93 pub fn has_eip4844(&self) -> bool {
95 self.0.iter().any(|tx| tx.is_eip4844())
96 }
97}
98
99impl<T> From<Vec<T>> for Transactions<T> {
100 fn from(txs: Vec<T>) -> Self {
101 Self(txs)
102 }
103}
104
105impl<T> From<Transactions<T>> for Vec<T> {
106 fn from(txs: Transactions<T>) -> Self {
107 txs.0
108 }
109}
110
111#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper)]
116#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
117#[add_arbitrary_tests(rlp, 20)]
118pub struct SharedTransactions<T = TransactionSigned>(
119 pub Vec<Arc<T>>,
121);
122
123#[derive(Clone, Debug, PartialEq, Eq)]
125#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
126pub enum NewPooledTransactionHashes {
127 Eth66(NewPooledTransactionHashes66),
129 Eth68(NewPooledTransactionHashes68),
133}
134
135impl NewPooledTransactionHashes {
138 pub const fn version(&self) -> EthVersion {
140 match self {
141 Self::Eth66(_) => EthVersion::Eth66,
142 Self::Eth68(_) => EthVersion::Eth68,
143 }
144 }
145
146 pub const fn is_valid_for_version(&self, version: EthVersion) -> bool {
148 match self {
149 Self::Eth66(_) => {
150 matches!(version, EthVersion::Eth67 | EthVersion::Eth66)
151 }
152 Self::Eth68(_) => {
153 matches!(version, EthVersion::Eth68)
154 }
155 }
156 }
157
158 pub fn iter_hashes(&self) -> impl Iterator<Item = &B256> + '_ {
160 match self {
161 Self::Eth66(msg) => msg.0.iter(),
162 Self::Eth68(msg) => msg.hashes.iter(),
163 }
164 }
165
166 pub const fn hashes(&self) -> &Vec<B256> {
168 match self {
169 Self::Eth66(msg) => &msg.0,
170 Self::Eth68(msg) => &msg.hashes,
171 }
172 }
173
174 pub const fn hashes_mut(&mut self) -> &mut Vec<B256> {
176 match self {
177 Self::Eth66(msg) => &mut msg.0,
178 Self::Eth68(msg) => &mut msg.hashes,
179 }
180 }
181
182 pub fn into_hashes(self) -> Vec<B256> {
184 match self {
185 Self::Eth66(msg) => msg.0,
186 Self::Eth68(msg) => msg.hashes,
187 }
188 }
189
190 pub fn into_iter_hashes(self) -> impl Iterator<Item = B256> {
192 match self {
193 Self::Eth66(msg) => msg.0.into_iter(),
194 Self::Eth68(msg) => msg.hashes.into_iter(),
195 }
196 }
197
198 pub fn truncate(&mut self, len: usize) {
201 match self {
202 Self::Eth66(msg) => msg.0.truncate(len),
203 Self::Eth68(msg) => {
204 msg.types.truncate(len);
205 msg.sizes.truncate(len);
206 msg.hashes.truncate(len);
207 }
208 }
209 }
210
211 pub fn is_empty(&self) -> bool {
213 match self {
214 Self::Eth66(msg) => msg.0.is_empty(),
215 Self::Eth68(msg) => msg.hashes.is_empty(),
216 }
217 }
218
219 pub fn len(&self) -> usize {
221 match self {
222 Self::Eth66(msg) => msg.0.len(),
223 Self::Eth68(msg) => msg.hashes.len(),
224 }
225 }
226
227 pub const fn as_eth68(&self) -> Option<&NewPooledTransactionHashes68> {
229 match self {
230 Self::Eth66(_) => None,
231 Self::Eth68(msg) => Some(msg),
232 }
233 }
234
235 pub const fn as_eth68_mut(&mut self) -> Option<&mut NewPooledTransactionHashes68> {
237 match self {
238 Self::Eth66(_) => None,
239 Self::Eth68(msg) => Some(msg),
240 }
241 }
242
243 pub const fn as_eth66_mut(&mut self) -> Option<&mut NewPooledTransactionHashes66> {
245 match self {
246 Self::Eth66(msg) => Some(msg),
247 Self::Eth68(_) => None,
248 }
249 }
250
251 pub fn take_eth68(&mut self) -> Option<NewPooledTransactionHashes68> {
253 match self {
254 Self::Eth66(_) => None,
255 Self::Eth68(msg) => Some(mem::take(msg)),
256 }
257 }
258
259 pub fn take_eth66(&mut self) -> Option<NewPooledTransactionHashes66> {
261 match self {
262 Self::Eth66(msg) => Some(mem::take(msg)),
263 Self::Eth68(_) => None,
264 }
265 }
266}
267
268impl<N: NetworkPrimitives> From<NewPooledTransactionHashes> for EthMessage<N> {
269 fn from(value: NewPooledTransactionHashes) -> Self {
270 match value {
271 NewPooledTransactionHashes::Eth66(msg) => Self::NewPooledTransactionHashes66(msg),
272 NewPooledTransactionHashes::Eth68(msg) => Self::NewPooledTransactionHashes68(msg),
273 }
274 }
275}
276
277impl From<NewPooledTransactionHashes66> for NewPooledTransactionHashes {
278 fn from(hashes: NewPooledTransactionHashes66) -> Self {
279 Self::Eth66(hashes)
280 }
281}
282
283impl From<NewPooledTransactionHashes68> for NewPooledTransactionHashes {
284 fn from(hashes: NewPooledTransactionHashes68) -> Self {
285 Self::Eth68(hashes)
286 }
287}
288
289#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper, Default)]
292#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
293#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
294#[add_arbitrary_tests(rlp)]
295pub struct NewPooledTransactionHashes66(
296 pub Vec<B256>,
300);
301
302impl From<Vec<B256>> for NewPooledTransactionHashes66 {
303 fn from(v: Vec<B256>) -> Self {
304 Self(v)
305 }
306}
307
308#[derive(Clone, Debug, PartialEq, Eq, Default)]
311#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
312pub struct NewPooledTransactionHashes68 {
313 pub types: Vec<u8>,
337 pub sizes: Vec<usize>,
339 pub hashes: Vec<B256>,
341}
342
343#[cfg(feature = "arbitrary")]
344impl proptest::prelude::Arbitrary for NewPooledTransactionHashes68 {
345 type Parameters = ();
346 fn arbitrary_with(_args: ()) -> Self::Strategy {
347 use proptest::{collection::vec, prelude::*};
348 let vec_length = any::<usize>().prop_map(|x| x % 100 + 1); vec_length
352 .prop_flat_map(|len| {
353 let types_vec = vec(
355 proptest_arbitrary_interop::arb::<reth_ethereum_primitives::TxType>()
356 .prop_map(|ty| ty as u8),
357 len..=len,
358 );
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 = proptest::prelude::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 pub fn push<T: SignedTransaction>(&mut self, tx: &T) {
381 self.hashes.push(*tx.tx_hash());
382 self.sizes.push(tx.encode_2718_len());
383 self.types.push(tx.ty());
384 }
385
386 pub fn extend<'a, T: SignedTransaction>(&mut self, txs: impl IntoIterator<Item = &'a T>) {
388 for tx in txs {
389 self.push(tx);
390 }
391 }
392
393 pub fn with_transaction<T: SignedTransaction>(mut self, tx: &T) -> Self {
395 self.push(tx);
396 self
397 }
398
399 pub fn with_transactions<'a, T: SignedTransaction>(
401 mut self,
402 txs: impl IntoIterator<Item = &'a T>,
403 ) -> Self {
404 self.extend(txs);
405 self
406 }
407}
408
409impl Encodable for NewPooledTransactionHashes68 {
410 fn encode(&self, out: &mut dyn bytes::BufMut) {
411 #[derive(RlpEncodable)]
412 struct EncodableNewPooledTransactionHashes68<'a> {
413 types: &'a [u8],
414 sizes: &'a Vec<usize>,
415 hashes: &'a Vec<B256>,
416 }
417
418 let encodable = EncodableNewPooledTransactionHashes68 {
419 types: &self.types[..],
420 sizes: &self.sizes,
421 hashes: &self.hashes,
422 };
423
424 encodable.encode(out);
425 }
426 fn length(&self) -> usize {
427 #[derive(RlpEncodable)]
428 struct EncodableNewPooledTransactionHashes68<'a> {
429 types: &'a [u8],
430 sizes: &'a Vec<usize>,
431 hashes: &'a Vec<B256>,
432 }
433
434 let encodable = EncodableNewPooledTransactionHashes68 {
435 types: &self.types[..],
436 sizes: &self.sizes,
437 hashes: &self.hashes,
438 };
439
440 encodable.length()
441 }
442}
443
444impl Decodable for NewPooledTransactionHashes68 {
445 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
446 #[derive(RlpDecodable)]
447 struct EncodableNewPooledTransactionHashes68 {
448 types: Bytes,
449 sizes: Vec<usize>,
450 hashes: Vec<B256>,
451 }
452
453 let encodable = EncodableNewPooledTransactionHashes68::decode(buf)?;
454 let msg = Self {
455 types: encodable.types.into(),
456 sizes: encodable.sizes,
457 hashes: encodable.hashes,
458 };
459
460 if msg.hashes.len() != msg.types.len() {
461 return Err(alloy_rlp::Error::ListLengthMismatch {
462 expected: msg.hashes.len(),
463 got: msg.types.len(),
464 })
465 }
466 if msg.hashes.len() != msg.sizes.len() {
467 return Err(alloy_rlp::Error::ListLengthMismatch {
468 expected: msg.hashes.len(),
469 got: msg.sizes.len(),
470 })
471 }
472
473 Ok(msg)
474 }
475}
476
477pub trait DedupPayload {
479 type Value;
481
482 fn is_empty(&self) -> bool;
484
485 fn len(&self) -> usize;
487
488 fn dedup(self) -> PartiallyValidData<Self::Value>;
490}
491
492pub type Eth68TxMetadata = Option<(u8, usize)>;
494
495impl DedupPayload for NewPooledTransactionHashes {
496 type Value = Eth68TxMetadata;
497
498 fn is_empty(&self) -> bool {
499 self.is_empty()
500 }
501
502 fn len(&self) -> usize {
503 self.len()
504 }
505
506 fn dedup(self) -> PartiallyValidData<Self::Value> {
507 match self {
508 Self::Eth66(msg) => msg.dedup(),
509 Self::Eth68(msg) => msg.dedup(),
510 }
511 }
512}
513
514impl DedupPayload for NewPooledTransactionHashes68 {
515 type Value = Eth68TxMetadata;
516
517 fn is_empty(&self) -> bool {
518 self.hashes.is_empty()
519 }
520
521 fn len(&self) -> usize {
522 self.hashes.len()
523 }
524
525 fn dedup(self) -> PartiallyValidData<Self::Value> {
526 let Self { hashes, mut sizes, mut types } = self;
527
528 let mut deduped_data = HashMap::with_capacity_and_hasher(hashes.len(), Default::default());
529
530 for hash in hashes.into_iter().rev() {
531 if let (Some(ty), Some(size)) = (types.pop(), sizes.pop()) {
532 deduped_data.insert(hash, Some((ty, size)));
533 }
534 }
535
536 PartiallyValidData::from_raw_data_eth68(deduped_data)
537 }
538}
539
540impl DedupPayload for NewPooledTransactionHashes66 {
541 type Value = Eth68TxMetadata;
542
543 fn is_empty(&self) -> bool {
544 self.0.is_empty()
545 }
546
547 fn len(&self) -> usize {
548 self.0.len()
549 }
550
551 fn dedup(self) -> PartiallyValidData<Self::Value> {
552 let Self(hashes) = self;
553
554 let mut deduped_data = HashMap::with_capacity_and_hasher(hashes.len(), Default::default());
555
556 let noop_value: Eth68TxMetadata = None;
557
558 for hash in hashes.into_iter().rev() {
559 deduped_data.insert(hash, noop_value);
560 }
561
562 PartiallyValidData::from_raw_data_eth66(deduped_data)
563 }
564}
565
566pub trait HandleMempoolData {
569 fn is_empty(&self) -> bool;
571
572 fn len(&self) -> usize;
574
575 fn retain_by_hash(&mut self, f: impl FnMut(&TxHash) -> bool);
577}
578
579pub trait HandleVersionedMempoolData {
581 fn msg_version(&self) -> EthVersion;
584}
585
586impl<T: SignedTransaction> HandleMempoolData for Vec<T> {
587 fn is_empty(&self) -> bool {
588 self.is_empty()
589 }
590
591 fn len(&self) -> usize {
592 self.len()
593 }
594
595 fn retain_by_hash(&mut self, mut f: impl FnMut(&TxHash) -> bool) {
596 self.retain(|tx| f(tx.tx_hash()))
597 }
598}
599
600macro_rules! handle_mempool_data_map_impl {
601 ($data_ty:ty, $(<$generic:ident>)?) => {
602 impl$(<$generic>)? HandleMempoolData for $data_ty {
603 fn is_empty(&self) -> bool {
604 self.data.is_empty()
605 }
606
607 fn len(&self) -> usize {
608 self.data.len()
609 }
610
611 fn retain_by_hash(&mut self, mut f: impl FnMut(&TxHash) -> bool) {
612 self.data.retain(|hash, _| f(hash));
613 }
614 }
615 };
616}
617
618#[derive(Debug, Deref, DerefMut, IntoIterator)]
621pub struct PartiallyValidData<V> {
622 #[deref]
623 #[deref_mut]
624 #[into_iterator]
625 data: HashMap<TxHash, V>,
626 version: Option<EthVersion>,
627}
628
629handle_mempool_data_map_impl!(PartiallyValidData<V>, <V>);
630
631impl<V> PartiallyValidData<V> {
632 pub const fn from_raw_data(data: HashMap<TxHash, V>, version: Option<EthVersion>) -> Self {
634 Self { data, version }
635 }
636
637 pub const fn from_raw_data_eth68(data: HashMap<TxHash, V>) -> Self {
639 Self::from_raw_data(data, Some(EthVersion::Eth68))
640 }
641
642 pub const fn from_raw_data_eth66(data: HashMap<TxHash, V>) -> Self {
644 Self::from_raw_data(data, Some(EthVersion::Eth66))
645 }
646
647 pub fn empty_eth68() -> Self {
650 Self::from_raw_data_eth68(HashMap::default())
651 }
652
653 pub fn empty_eth66() -> Self {
656 Self::from_raw_data_eth66(HashMap::default())
657 }
658
659 pub const fn msg_version(&self) -> Option<EthVersion> {
662 self.version
663 }
664
665 pub fn into_data(self) -> HashMap<TxHash, V> {
667 self.data
668 }
669}
670
671#[derive(Debug, Deref, DerefMut, IntoIterator, From)]
674pub struct ValidAnnouncementData {
675 #[deref]
676 #[deref_mut]
677 #[into_iterator]
678 data: HashMap<TxHash, Eth68TxMetadata>,
679 version: EthVersion,
680}
681
682handle_mempool_data_map_impl!(ValidAnnouncementData,);
683
684impl ValidAnnouncementData {
685 pub fn into_request_hashes(self) -> (RequestTxHashes, EthVersion) {
688 let hashes = self.data.into_keys().collect::<HashSet<_>>();
689
690 (RequestTxHashes::new(hashes), self.version)
691 }
692
693 pub fn from_partially_valid_data(data: PartiallyValidData<Eth68TxMetadata>) -> Self {
697 let PartiallyValidData { data, version } = data;
698
699 let version = version.expect("should have eth version for conversion");
700
701 Self { data, version }
702 }
703
704 pub fn into_data(self) -> HashMap<TxHash, Eth68TxMetadata> {
706 self.data
707 }
708}
709
710impl HandleVersionedMempoolData for ValidAnnouncementData {
711 fn msg_version(&self) -> EthVersion {
712 self.version
713 }
714}
715
716#[derive(Debug, Default, Deref, DerefMut, IntoIterator, Constructor)]
718pub struct RequestTxHashes {
719 #[deref]
720 #[deref_mut]
721 #[into_iterator(owned, ref)]
722 hashes: HashSet<TxHash>,
723}
724
725impl RequestTxHashes {
726 pub fn with_capacity(capacity: usize) -> Self {
731 Self::new(HashSet::with_capacity_and_hasher(capacity, Default::default()))
732 }
733
734 fn empty() -> Self {
736 Self::new(HashSet::default())
737 }
738
739 pub fn retain_count(&mut self, count: usize) -> Self {
741 let rest_capacity = self.hashes.len().saturating_sub(count);
742 if rest_capacity == 0 {
743 return Self::empty()
744 }
745 let mut rest = Self::with_capacity(rest_capacity);
746
747 let mut i = 0;
748 self.hashes.retain(|hash| {
749 if i >= count {
750 rest.insert(*hash);
751 return false
752 }
753 i += 1;
754
755 true
756 });
757
758 rest
759 }
760}
761
762impl FromIterator<(TxHash, Eth68TxMetadata)> for RequestTxHashes {
763 fn from_iter<I: IntoIterator<Item = (TxHash, Eth68TxMetadata)>>(iter: I) -> Self {
764 Self::new(iter.into_iter().map(|(hash, _)| hash).collect())
765 }
766}
767
768#[cfg(test)]
769mod tests {
770 use super::*;
771 use alloy_consensus::Typed2718;
772 use alloy_eips::eip2718::Encodable2718;
773 use alloy_primitives::{b256, hex, Signature, U256};
774 use reth_ethereum_primitives::{Transaction, TransactionSigned};
775 use std::str::FromStr;
776
777 fn test_encoding_vector<T: Encodable + Decodable + PartialEq + core::fmt::Debug>(
780 input: (T, &[u8]),
781 ) {
782 let (expected_decoded, expected_encoded) = input;
783 let mut encoded = Vec::new();
784 expected_decoded.encode(&mut encoded);
785
786 assert_eq!(hex::encode(&encoded), hex::encode(expected_encoded));
787
788 let decoded = T::decode(&mut encoded.as_ref()).unwrap();
789 assert_eq!(expected_decoded, decoded);
790 }
791
792 #[test]
793 fn can_return_latest_block() {
794 let mut blocks = NewBlockHashes(vec![BlockHashNumber { hash: B256::random(), number: 0 }]);
795 let latest = blocks.latest().unwrap();
796 assert_eq!(latest.number, 0);
797
798 blocks.0.push(BlockHashNumber { hash: B256::random(), number: 100 });
799 blocks.0.push(BlockHashNumber { hash: B256::random(), number: 2 });
800 let latest = blocks.latest().unwrap();
801 assert_eq!(latest.number, 100);
802 }
803
804 #[test]
805 fn eth_68_tx_hash_roundtrip() {
806 let vectors = vec![
807 (
808 NewPooledTransactionHashes68 { types: vec![], sizes: vec![], hashes: vec![] },
809 &hex!("c380c0c0")[..],
810 ),
811 (
812 NewPooledTransactionHashes68 {
813 types: vec![0x00],
814 sizes: vec![0x00],
815 hashes: vec![
816 B256::from_str(
817 "0x0000000000000000000000000000000000000000000000000000000000000000",
818 )
819 .unwrap(),
820 ],
821 },
822 &hex!(
823 "e500c180e1a00000000000000000000000000000000000000000000000000000000000000000"
824 )[..],
825 ),
826 (
827 NewPooledTransactionHashes68 {
828 types: vec![0x00, 0x00],
829 sizes: vec![0x00, 0x00],
830 hashes: vec![
831 B256::from_str(
832 "0x0000000000000000000000000000000000000000000000000000000000000000",
833 )
834 .unwrap(),
835 B256::from_str(
836 "0x0000000000000000000000000000000000000000000000000000000000000000",
837 )
838 .unwrap(),
839 ],
840 },
841 &hex!(
842 "f84a820000c28080f842a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000"
843 )[..],
844 ),
845 (
846 NewPooledTransactionHashes68 {
847 types: vec![0x02],
848 sizes: vec![0xb6],
849 hashes: vec![
850 B256::from_str(
851 "0xfecbed04c7b88d8e7221a0a3f5dc33f220212347fc167459ea5cc9c3eb4c1124",
852 )
853 .unwrap(),
854 ],
855 },
856 &hex!(
857 "e602c281b6e1a0fecbed04c7b88d8e7221a0a3f5dc33f220212347fc167459ea5cc9c3eb4c1124"
858 )[..],
859 ),
860 (
861 NewPooledTransactionHashes68 {
862 types: vec![0xff, 0xff],
863 sizes: vec![0xffffffff, 0xffffffff],
864 hashes: vec![
865 B256::from_str(
866 "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
867 )
868 .unwrap(),
869 B256::from_str(
870 "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
871 )
872 .unwrap(),
873 ],
874 },
875 &hex!(
876 "f85282ffffca84ffffffff84fffffffff842a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
877 )[..],
878 ),
879 (
880 NewPooledTransactionHashes68 {
881 types: vec![0xff, 0xff],
882 sizes: vec![0xffffffff, 0xffffffff],
883 hashes: vec![
884 B256::from_str(
885 "0xbeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafe",
886 )
887 .unwrap(),
888 B256::from_str(
889 "0xbeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafe",
890 )
891 .unwrap(),
892 ],
893 },
894 &hex!(
895 "f85282ffffca84ffffffff84fffffffff842a0beefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafea0beefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafe"
896 )[..],
897 ),
898 (
899 NewPooledTransactionHashes68 {
900 types: vec![0x10, 0x10],
901 sizes: vec![0xdeadc0de, 0xdeadc0de],
902 hashes: vec![
903 B256::from_str(
904 "0x3b9aca00f0671c9a2a1b817a0a78d3fe0c0f776cccb2a8c3c1b412a4f4e4d4e2",
905 )
906 .unwrap(),
907 B256::from_str(
908 "0x3b9aca00f0671c9a2a1b817a0a78d3fe0c0f776cccb2a8c3c1b412a4f4e4d4e2",
909 )
910 .unwrap(),
911 ],
912 },
913 &hex!(
914 "f852821010ca84deadc0de84deadc0def842a03b9aca00f0671c9a2a1b817a0a78d3fe0c0f776cccb2a8c3c1b412a4f4e4d4e2a03b9aca00f0671c9a2a1b817a0a78d3fe0c0f776cccb2a8c3c1b412a4f4e4d4e2"
915 )[..],
916 ),
917 (
918 NewPooledTransactionHashes68 {
919 types: vec![0x6f, 0x6f],
920 sizes: vec![0x7fffffff, 0x7fffffff],
921 hashes: vec![
922 B256::from_str(
923 "0x0000000000000000000000000000000000000000000000000000000000000002",
924 )
925 .unwrap(),
926 B256::from_str(
927 "0x0000000000000000000000000000000000000000000000000000000000000002",
928 )
929 .unwrap(),
930 ],
931 },
932 &hex!(
933 "f852826f6fca847fffffff847ffffffff842a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000002"
934 )[..],
935 ),
936 ];
937
938 for vector in vectors {
939 test_encoding_vector(vector);
940 }
941 }
942
943 #[test]
944 fn request_hashes_retain_count_keep_subset() {
945 let mut hashes = RequestTxHashes::new(
946 [
947 b256!("0x0000000000000000000000000000000000000000000000000000000000000001"),
948 b256!("0x0000000000000000000000000000000000000000000000000000000000000002"),
949 b256!("0x0000000000000000000000000000000000000000000000000000000000000003"),
950 b256!("0x0000000000000000000000000000000000000000000000000000000000000004"),
951 b256!("0x0000000000000000000000000000000000000000000000000000000000000005"),
952 ]
953 .into_iter()
954 .collect::<HashSet<_>>(),
955 );
956
957 let rest = hashes.retain_count(3);
958
959 assert_eq!(3, hashes.len());
960 assert_eq!(2, rest.len());
961 }
962
963 #[test]
964 fn request_hashes_retain_count_keep_all() {
965 let mut hashes = RequestTxHashes::new(
966 [
967 b256!("0x0000000000000000000000000000000000000000000000000000000000000001"),
968 b256!("0x0000000000000000000000000000000000000000000000000000000000000002"),
969 b256!("0x0000000000000000000000000000000000000000000000000000000000000003"),
970 b256!("0x0000000000000000000000000000000000000000000000000000000000000004"),
971 b256!("0x0000000000000000000000000000000000000000000000000000000000000005"),
972 ]
973 .into_iter()
974 .collect::<HashSet<_>>(),
975 );
976
977 let _ = hashes.retain_count(6);
978
979 assert_eq!(5, hashes.len());
980 }
981
982 #[test]
983 fn split_request_hashes_keep_none() {
984 let mut hashes = RequestTxHashes::new(
985 [
986 b256!("0x0000000000000000000000000000000000000000000000000000000000000001"),
987 b256!("0x0000000000000000000000000000000000000000000000000000000000000002"),
988 b256!("0x0000000000000000000000000000000000000000000000000000000000000003"),
989 b256!("0x0000000000000000000000000000000000000000000000000000000000000004"),
990 b256!("0x0000000000000000000000000000000000000000000000000000000000000005"),
991 ]
992 .into_iter()
993 .collect::<HashSet<_>>(),
994 );
995
996 let rest = hashes.retain_count(0);
997
998 assert_eq!(0, hashes.len());
999 assert_eq!(5, rest.len());
1000 }
1001
1002 fn signed_transaction() -> impl SignedTransaction {
1003 TransactionSigned::new_unhashed(
1004 Transaction::Legacy(Default::default()),
1005 Signature::new(
1006 U256::from_str(
1007 "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12",
1008 )
1009 .unwrap(),
1010 U256::from_str(
1011 "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10",
1012 )
1013 .unwrap(),
1014 false,
1015 ),
1016 )
1017 }
1018
1019 #[test]
1020 fn test_pooled_tx_hashes_68_push() {
1021 let tx = signed_transaction();
1022 let mut tx_hashes =
1023 NewPooledTransactionHashes68 { types: vec![], sizes: vec![], hashes: vec![] };
1024 tx_hashes.push(&tx);
1025 assert_eq!(tx_hashes.types.len(), 1);
1026 assert_eq!(tx_hashes.sizes.len(), 1);
1027 assert_eq!(tx_hashes.hashes.len(), 1);
1028 assert_eq!(tx_hashes.types[0], tx.ty());
1029 assert_eq!(tx_hashes.sizes[0], tx.encode_2718_len());
1030 assert_eq!(tx_hashes.hashes[0], *tx.tx_hash());
1031 }
1032
1033 #[test]
1034 fn test_pooled_tx_hashes_68_extend() {
1035 let tx = signed_transaction();
1036 let txs = vec![tx.clone(), tx.clone()];
1037 let mut tx_hashes =
1038 NewPooledTransactionHashes68 { types: vec![], sizes: vec![], hashes: vec![] };
1039 tx_hashes.extend(&txs);
1040 assert_eq!(tx_hashes.types.len(), 2);
1041 assert_eq!(tx_hashes.sizes.len(), 2);
1042 assert_eq!(tx_hashes.hashes.len(), 2);
1043 assert_eq!(tx_hashes.types[0], tx.ty());
1044 assert_eq!(tx_hashes.sizes[0], tx.encode_2718_len());
1045 assert_eq!(tx_hashes.hashes[0], *tx.tx_hash());
1046 assert_eq!(tx_hashes.types[1], tx.ty());
1047 assert_eq!(tx_hashes.sizes[1], tx.encode_2718_len());
1048 assert_eq!(tx_hashes.hashes[1], *tx.tx_hash());
1049 }
1050
1051 #[test]
1052 fn test_pooled_tx_hashes_68_with_transaction() {
1053 let tx = signed_transaction();
1054 let tx_hashes =
1055 NewPooledTransactionHashes68 { types: vec![], sizes: vec![], hashes: vec![] }
1056 .with_transaction(&tx);
1057 assert_eq!(tx_hashes.types.len(), 1);
1058 assert_eq!(tx_hashes.sizes.len(), 1);
1059 assert_eq!(tx_hashes.hashes.len(), 1);
1060 assert_eq!(tx_hashes.types[0], tx.ty());
1061 assert_eq!(tx_hashes.sizes[0], tx.encode_2718_len());
1062 assert_eq!(tx_hashes.hashes[0], *tx.tx_hash());
1063 }
1064
1065 #[test]
1066 fn test_pooled_tx_hashes_68_with_transactions() {
1067 let tx = signed_transaction();
1068 let txs = vec![tx.clone(), tx.clone()];
1069 let tx_hashes =
1070 NewPooledTransactionHashes68 { types: vec![], sizes: vec![], hashes: vec![] }
1071 .with_transactions(&txs);
1072 assert_eq!(tx_hashes.types.len(), 2);
1073 assert_eq!(tx_hashes.sizes.len(), 2);
1074 assert_eq!(tx_hashes.hashes.len(), 2);
1075 assert_eq!(tx_hashes.types[0], tx.ty());
1076 assert_eq!(tx_hashes.sizes[0], tx.encode_2718_len());
1077 assert_eq!(tx_hashes.hashes[0], *tx.tx_hash());
1078 assert_eq!(tx_hashes.types[1], tx.ty());
1079 assert_eq!(tx_hashes.sizes[1], tx.encode_2718_len());
1080 assert_eq!(tx_hashes.hashes[1], *tx.tx_hash());
1081 }
1082}