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::{fmt::Debug, 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::{Block, 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
67pub trait NewBlockPayload:
69 Encodable + Decodable + Clone + Eq + Debug + Send + Sync + Unpin + 'static
70{
71 type Block: Block;
73
74 fn block(&self) -> &Self::Block;
76}
77
78#[derive(Clone, Debug, PartialEq, Eq, RlpEncodable, RlpDecodable, Default)]
81#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
82#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
83pub struct NewBlock<B = reth_ethereum_primitives::Block> {
84 pub block: B,
86 pub td: U128,
88}
89
90impl<B: Block + 'static> NewBlockPayload for NewBlock<B> {
91 type Block = B;
92
93 fn block(&self) -> &Self::Block {
94 &self.block
95 }
96}
97
98generate_tests!(#[rlp, 25] NewBlock<reth_ethereum_primitives::Block>, EthNewBlockTests);
99
100#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper, Default)]
103#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
104#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
105#[add_arbitrary_tests(rlp, 10)]
106pub struct Transactions<T = TransactionSigned>(
107 pub Vec<T>,
109);
110
111impl<T: SignedTransaction> Transactions<T> {
112 pub fn has_eip4844(&self) -> bool {
114 self.0.iter().any(|tx| tx.is_eip4844())
115 }
116}
117
118impl<T> From<Vec<T>> for Transactions<T> {
119 fn from(txs: Vec<T>) -> Self {
120 Self(txs)
121 }
122}
123
124impl<T> From<Transactions<T>> for Vec<T> {
125 fn from(txs: Transactions<T>) -> Self {
126 txs.0
127 }
128}
129
130#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper)]
135#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
136#[add_arbitrary_tests(rlp, 20)]
137pub struct SharedTransactions<T = TransactionSigned>(
138 pub Vec<Arc<T>>,
140);
141
142#[derive(Clone, Debug, PartialEq, Eq)]
144#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
145pub enum NewPooledTransactionHashes {
146 Eth66(NewPooledTransactionHashes66),
148 Eth68(NewPooledTransactionHashes68),
152}
153
154impl NewPooledTransactionHashes {
157 pub const fn version(&self) -> EthVersion {
159 match self {
160 Self::Eth66(_) => EthVersion::Eth66,
161 Self::Eth68(_) => EthVersion::Eth68,
162 }
163 }
164
165 pub const fn is_valid_for_version(&self, version: EthVersion) -> bool {
167 match self {
168 Self::Eth66(_) => {
169 matches!(version, EthVersion::Eth67 | EthVersion::Eth66)
170 }
171 Self::Eth68(_) => {
172 matches!(version, EthVersion::Eth68 | EthVersion::Eth69 | EthVersion::Eth70)
173 }
174 }
175 }
176
177 pub fn iter_hashes(&self) -> impl Iterator<Item = &B256> + '_ {
179 match self {
180 Self::Eth66(msg) => msg.0.iter(),
181 Self::Eth68(msg) => msg.hashes.iter(),
182 }
183 }
184
185 pub const fn hashes(&self) -> &Vec<B256> {
187 match self {
188 Self::Eth66(msg) => &msg.0,
189 Self::Eth68(msg) => &msg.hashes,
190 }
191 }
192
193 pub const fn hashes_mut(&mut self) -> &mut Vec<B256> {
195 match self {
196 Self::Eth66(msg) => &mut msg.0,
197 Self::Eth68(msg) => &mut msg.hashes,
198 }
199 }
200
201 pub fn into_hashes(self) -> Vec<B256> {
203 match self {
204 Self::Eth66(msg) => msg.0,
205 Self::Eth68(msg) => msg.hashes,
206 }
207 }
208
209 pub fn into_iter_hashes(self) -> impl Iterator<Item = B256> {
211 match self {
212 Self::Eth66(msg) => msg.0.into_iter(),
213 Self::Eth68(msg) => msg.hashes.into_iter(),
214 }
215 }
216
217 pub fn truncate(&mut self, len: usize) {
220 match self {
221 Self::Eth66(msg) => msg.0.truncate(len),
222 Self::Eth68(msg) => {
223 msg.types.truncate(len);
224 msg.sizes.truncate(len);
225 msg.hashes.truncate(len);
226 }
227 }
228 }
229
230 pub const fn is_empty(&self) -> bool {
232 match self {
233 Self::Eth66(msg) => msg.0.is_empty(),
234 Self::Eth68(msg) => msg.hashes.is_empty(),
235 }
236 }
237
238 pub const fn len(&self) -> usize {
240 match self {
241 Self::Eth66(msg) => msg.0.len(),
242 Self::Eth68(msg) => msg.hashes.len(),
243 }
244 }
245
246 pub const fn as_eth68(&self) -> Option<&NewPooledTransactionHashes68> {
248 match self {
249 Self::Eth66(_) => None,
250 Self::Eth68(msg) => Some(msg),
251 }
252 }
253
254 pub const fn as_eth68_mut(&mut self) -> Option<&mut NewPooledTransactionHashes68> {
256 match self {
257 Self::Eth66(_) => None,
258 Self::Eth68(msg) => Some(msg),
259 }
260 }
261
262 pub const fn as_eth66_mut(&mut self) -> Option<&mut NewPooledTransactionHashes66> {
264 match self {
265 Self::Eth66(msg) => Some(msg),
266 Self::Eth68(_) => None,
267 }
268 }
269
270 pub fn take_eth68(&mut self) -> Option<NewPooledTransactionHashes68> {
272 match self {
273 Self::Eth66(_) => None,
274 Self::Eth68(msg) => Some(mem::take(msg)),
275 }
276 }
277
278 pub fn take_eth66(&mut self) -> Option<NewPooledTransactionHashes66> {
280 match self {
281 Self::Eth66(msg) => Some(mem::take(msg)),
282 Self::Eth68(_) => None,
283 }
284 }
285}
286
287impl<N: NetworkPrimitives> From<NewPooledTransactionHashes> for EthMessage<N> {
288 fn from(value: NewPooledTransactionHashes) -> Self {
289 match value {
290 NewPooledTransactionHashes::Eth66(msg) => Self::NewPooledTransactionHashes66(msg),
291 NewPooledTransactionHashes::Eth68(msg) => Self::NewPooledTransactionHashes68(msg),
292 }
293 }
294}
295
296impl From<NewPooledTransactionHashes66> for NewPooledTransactionHashes {
297 fn from(hashes: NewPooledTransactionHashes66) -> Self {
298 Self::Eth66(hashes)
299 }
300}
301
302impl From<NewPooledTransactionHashes68> for NewPooledTransactionHashes {
303 fn from(hashes: NewPooledTransactionHashes68) -> Self {
304 Self::Eth68(hashes)
305 }
306}
307
308#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper, Default)]
311#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
312#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
313#[add_arbitrary_tests(rlp)]
314pub struct NewPooledTransactionHashes66(
315 pub Vec<B256>,
319);
320
321impl From<Vec<B256>> for NewPooledTransactionHashes66 {
322 fn from(v: Vec<B256>) -> Self {
323 Self(v)
324 }
325}
326
327#[derive(Clone, Debug, PartialEq, Eq, Default)]
330#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
331pub struct NewPooledTransactionHashes68 {
332 pub types: Vec<u8>,
356 pub sizes: Vec<usize>,
358 pub hashes: Vec<B256>,
360}
361
362#[cfg(feature = "arbitrary")]
363impl proptest::prelude::Arbitrary for NewPooledTransactionHashes68 {
364 type Parameters = ();
365 fn arbitrary_with(_args: ()) -> Self::Strategy {
366 use proptest::{collection::vec, prelude::*};
367 let vec_length = any::<usize>().prop_map(|x| x % 100 + 1); vec_length
371 .prop_flat_map(|len| {
372 let types_vec = vec(
374 proptest_arbitrary_interop::arb::<reth_ethereum_primitives::TxType>()
375 .prop_map(|ty| ty as u8),
376 len..=len,
377 );
378
379 let sizes_vec = vec(proptest::num::usize::ANY.prop_map(|x| x % 131072), len..=len);
381 let hashes_vec = vec(any::<B256>(), len..=len);
382
383 (types_vec, sizes_vec, hashes_vec)
384 })
385 .prop_map(|(types, sizes, hashes)| Self { types, sizes, hashes })
386 .boxed()
387 }
388
389 type Strategy = proptest::prelude::BoxedStrategy<Self>;
390}
391
392impl NewPooledTransactionHashes68 {
393 pub fn metadata_iter(&self) -> impl Iterator<Item = (&B256, (u8, usize))> {
395 self.hashes.iter().zip(self.types.iter().copied().zip(self.sizes.iter().copied()))
396 }
397
398 pub fn push<T: SignedTransaction>(&mut self, tx: &T) {
400 self.hashes.push(*tx.tx_hash());
401 self.sizes.push(tx.encode_2718_len());
402 self.types.push(tx.ty());
403 }
404
405 pub fn extend<'a, T: SignedTransaction>(&mut self, txs: impl IntoIterator<Item = &'a T>) {
407 for tx in txs {
408 self.push(tx);
409 }
410 }
411
412 pub fn shrink_to_fit(&mut self) {
414 self.hashes.shrink_to_fit();
415 self.sizes.shrink_to_fit();
416 self.types.shrink_to_fit()
417 }
418
419 pub fn with_transaction<T: SignedTransaction>(mut self, tx: &T) -> Self {
421 self.push(tx);
422 self
423 }
424
425 pub fn with_transactions<'a, T: SignedTransaction>(
427 mut self,
428 txs: impl IntoIterator<Item = &'a T>,
429 ) -> Self {
430 self.extend(txs);
431 self
432 }
433}
434
435impl Encodable for NewPooledTransactionHashes68 {
436 fn encode(&self, out: &mut dyn bytes::BufMut) {
437 #[derive(RlpEncodable)]
438 struct EncodableNewPooledTransactionHashes68<'a> {
439 types: &'a [u8],
440 sizes: &'a Vec<usize>,
441 hashes: &'a Vec<B256>,
442 }
443
444 let encodable = EncodableNewPooledTransactionHashes68 {
445 types: &self.types[..],
446 sizes: &self.sizes,
447 hashes: &self.hashes,
448 };
449
450 encodable.encode(out);
451 }
452 fn length(&self) -> usize {
453 #[derive(RlpEncodable)]
454 struct EncodableNewPooledTransactionHashes68<'a> {
455 types: &'a [u8],
456 sizes: &'a Vec<usize>,
457 hashes: &'a Vec<B256>,
458 }
459
460 let encodable = EncodableNewPooledTransactionHashes68 {
461 types: &self.types[..],
462 sizes: &self.sizes,
463 hashes: &self.hashes,
464 };
465
466 encodable.length()
467 }
468}
469
470impl Decodable for NewPooledTransactionHashes68 {
471 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
472 #[derive(RlpDecodable)]
473 struct EncodableNewPooledTransactionHashes68 {
474 types: Bytes,
475 sizes: Vec<usize>,
476 hashes: Vec<B256>,
477 }
478
479 let encodable = EncodableNewPooledTransactionHashes68::decode(buf)?;
480 let msg = Self {
481 types: encodable.types.into(),
482 sizes: encodable.sizes,
483 hashes: encodable.hashes,
484 };
485
486 if msg.hashes.len() != msg.types.len() {
487 return Err(alloy_rlp::Error::ListLengthMismatch {
488 expected: msg.hashes.len(),
489 got: msg.types.len(),
490 })
491 }
492 if msg.hashes.len() != msg.sizes.len() {
493 return Err(alloy_rlp::Error::ListLengthMismatch {
494 expected: msg.hashes.len(),
495 got: msg.sizes.len(),
496 })
497 }
498
499 Ok(msg)
500 }
501}
502
503pub trait DedupPayload {
505 type Value;
507
508 fn is_empty(&self) -> bool;
510
511 fn len(&self) -> usize;
513
514 fn dedup(self) -> PartiallyValidData<Self::Value>;
516}
517
518pub type Eth68TxMetadata = Option<(u8, usize)>;
520
521impl DedupPayload for NewPooledTransactionHashes {
522 type Value = Eth68TxMetadata;
523
524 fn is_empty(&self) -> bool {
525 self.is_empty()
526 }
527
528 fn len(&self) -> usize {
529 self.len()
530 }
531
532 fn dedup(self) -> PartiallyValidData<Self::Value> {
533 match self {
534 Self::Eth66(msg) => msg.dedup(),
535 Self::Eth68(msg) => msg.dedup(),
536 }
537 }
538}
539
540impl DedupPayload for NewPooledTransactionHashes68 {
541 type Value = Eth68TxMetadata;
542
543 fn is_empty(&self) -> bool {
544 self.hashes.is_empty()
545 }
546
547 fn len(&self) -> usize {
548 self.hashes.len()
549 }
550
551 fn dedup(self) -> PartiallyValidData<Self::Value> {
552 let Self { hashes, mut sizes, mut types } = self;
553
554 let mut deduped_data = HashMap::with_capacity_and_hasher(hashes.len(), Default::default());
555
556 for hash in hashes.into_iter().rev() {
557 if let (Some(ty), Some(size)) = (types.pop(), sizes.pop()) {
558 deduped_data.insert(hash, Some((ty, size)));
559 }
560 }
561
562 PartiallyValidData::from_raw_data_eth68(deduped_data)
563 }
564}
565
566impl DedupPayload for NewPooledTransactionHashes66 {
567 type Value = Eth68TxMetadata;
568
569 fn is_empty(&self) -> bool {
570 self.0.is_empty()
571 }
572
573 fn len(&self) -> usize {
574 self.0.len()
575 }
576
577 fn dedup(self) -> PartiallyValidData<Self::Value> {
578 let Self(hashes) = self;
579
580 let mut deduped_data = HashMap::with_capacity_and_hasher(hashes.len(), Default::default());
581
582 let noop_value: Eth68TxMetadata = None;
583
584 for hash in hashes.into_iter().rev() {
585 deduped_data.insert(hash, noop_value);
586 }
587
588 PartiallyValidData::from_raw_data_eth66(deduped_data)
589 }
590}
591
592pub trait HandleMempoolData {
595 fn is_empty(&self) -> bool;
597
598 fn len(&self) -> usize;
600
601 fn retain_by_hash(&mut self, f: impl FnMut(&TxHash) -> bool);
603}
604
605pub trait HandleVersionedMempoolData {
607 fn msg_version(&self) -> EthVersion;
610}
611
612impl<T: SignedTransaction> HandleMempoolData for Vec<T> {
613 fn is_empty(&self) -> bool {
614 self.is_empty()
615 }
616
617 fn len(&self) -> usize {
618 self.len()
619 }
620
621 fn retain_by_hash(&mut self, mut f: impl FnMut(&TxHash) -> bool) {
622 self.retain(|tx| f(tx.tx_hash()))
623 }
624}
625
626macro_rules! handle_mempool_data_map_impl {
627 ($data_ty:ty, $(<$generic:ident>)?) => {
628 impl$(<$generic>)? HandleMempoolData for $data_ty {
629 fn is_empty(&self) -> bool {
630 self.data.is_empty()
631 }
632
633 fn len(&self) -> usize {
634 self.data.len()
635 }
636
637 fn retain_by_hash(&mut self, mut f: impl FnMut(&TxHash) -> bool) {
638 self.data.retain(|hash, _| f(hash));
639 }
640 }
641 };
642}
643
644#[derive(Debug, Deref, DerefMut, IntoIterator)]
647pub struct PartiallyValidData<V> {
648 #[deref]
649 #[deref_mut]
650 #[into_iterator]
651 data: HashMap<TxHash, V>,
652 version: Option<EthVersion>,
653}
654
655handle_mempool_data_map_impl!(PartiallyValidData<V>, <V>);
656
657impl<V> PartiallyValidData<V> {
658 pub const fn from_raw_data(data: HashMap<TxHash, V>, version: Option<EthVersion>) -> Self {
660 Self { data, version }
661 }
662
663 pub const fn from_raw_data_eth68(data: HashMap<TxHash, V>) -> Self {
665 Self::from_raw_data(data, Some(EthVersion::Eth68))
666 }
667
668 pub const fn from_raw_data_eth66(data: HashMap<TxHash, V>) -> Self {
670 Self::from_raw_data(data, Some(EthVersion::Eth66))
671 }
672
673 pub fn empty_eth68() -> Self {
676 Self::from_raw_data_eth68(HashMap::default())
677 }
678
679 pub fn empty_eth66() -> Self {
682 Self::from_raw_data_eth66(HashMap::default())
683 }
684
685 pub const fn msg_version(&self) -> Option<EthVersion> {
688 self.version
689 }
690
691 pub fn into_data(self) -> HashMap<TxHash, V> {
693 self.data
694 }
695}
696
697#[derive(Debug, Deref, DerefMut, IntoIterator, From)]
700pub struct ValidAnnouncementData {
701 #[deref]
702 #[deref_mut]
703 #[into_iterator]
704 data: HashMap<TxHash, Eth68TxMetadata>,
705 version: EthVersion,
706}
707
708handle_mempool_data_map_impl!(ValidAnnouncementData,);
709
710impl ValidAnnouncementData {
711 pub fn into_request_hashes(self) -> (RequestTxHashes, EthVersion) {
714 let hashes = self.data.into_keys().collect::<HashSet<_>>();
715
716 (RequestTxHashes::new(hashes), self.version)
717 }
718
719 pub fn from_partially_valid_data(data: PartiallyValidData<Eth68TxMetadata>) -> Self {
723 let PartiallyValidData { data, version } = data;
724
725 let version = version.expect("should have eth version for conversion");
726
727 Self { data, version }
728 }
729
730 pub fn into_data(self) -> HashMap<TxHash, Eth68TxMetadata> {
732 self.data
733 }
734}
735
736impl HandleVersionedMempoolData for ValidAnnouncementData {
737 fn msg_version(&self) -> EthVersion {
738 self.version
739 }
740}
741
742#[derive(Debug, Default, Deref, DerefMut, IntoIterator, Constructor)]
744pub struct RequestTxHashes {
745 #[deref]
746 #[deref_mut]
747 #[into_iterator(owned, ref)]
748 hashes: HashSet<TxHash>,
749}
750
751impl RequestTxHashes {
752 pub fn with_capacity(capacity: usize) -> Self {
757 Self::new(HashSet::with_capacity_and_hasher(capacity, Default::default()))
758 }
759
760 fn empty() -> Self {
762 Self::new(HashSet::default())
763 }
764
765 pub fn retain_count(&mut self, count: usize) -> Self {
767 let rest_capacity = self.hashes.len().saturating_sub(count);
768 if rest_capacity == 0 {
769 return Self::empty()
770 }
771 let mut rest = Self::with_capacity(rest_capacity);
772
773 let mut i = 0;
774 self.hashes.retain(|hash| {
775 if i >= count {
776 rest.insert(*hash);
777 return false
778 }
779 i += 1;
780
781 true
782 });
783
784 rest
785 }
786}
787
788impl FromIterator<(TxHash, Eth68TxMetadata)> for RequestTxHashes {
789 fn from_iter<I: IntoIterator<Item = (TxHash, Eth68TxMetadata)>>(iter: I) -> Self {
790 Self::new(iter.into_iter().map(|(hash, _)| hash).collect())
791 }
792}
793
794#[derive(Clone, Debug, PartialEq, Eq, Default, RlpEncodable, RlpDecodable)]
797#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
798#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
799pub struct BlockRangeUpdate {
800 pub earliest: u64,
802 pub latest: u64,
804 pub latest_hash: B256,
806}
807
808#[cfg(test)]
809mod tests {
810 use super::*;
811 use alloy_consensus::{transaction::TxHashRef, Typed2718};
812 use alloy_eips::eip2718::Encodable2718;
813 use alloy_primitives::{b256, hex, Signature, U256};
814 use reth_ethereum_primitives::{Transaction, TransactionSigned};
815 use std::str::FromStr;
816
817 fn test_encoding_vector<T: Encodable + Decodable + PartialEq + core::fmt::Debug>(
820 input: (T, &[u8]),
821 ) {
822 let (expected_decoded, expected_encoded) = input;
823 let mut encoded = Vec::new();
824 expected_decoded.encode(&mut encoded);
825
826 assert_eq!(hex::encode(&encoded), hex::encode(expected_encoded));
827
828 let decoded = T::decode(&mut encoded.as_ref()).unwrap();
829 assert_eq!(expected_decoded, decoded);
830 }
831
832 #[test]
833 fn can_return_latest_block() {
834 let mut blocks = NewBlockHashes(vec![BlockHashNumber { hash: B256::random(), number: 0 }]);
835 let latest = blocks.latest().unwrap();
836 assert_eq!(latest.number, 0);
837
838 blocks.0.push(BlockHashNumber { hash: B256::random(), number: 100 });
839 blocks.0.push(BlockHashNumber { hash: B256::random(), number: 2 });
840 let latest = blocks.latest().unwrap();
841 assert_eq!(latest.number, 100);
842 }
843
844 #[test]
845 fn eth_68_tx_hash_roundtrip() {
846 let vectors = vec![
847 (
848 NewPooledTransactionHashes68 { types: vec![], sizes: vec![], hashes: vec![] },
849 &hex!("c380c0c0")[..],
850 ),
851 (
852 NewPooledTransactionHashes68 {
853 types: vec![0x00],
854 sizes: vec![0x00],
855 hashes: vec![
856 B256::from_str(
857 "0x0000000000000000000000000000000000000000000000000000000000000000",
858 )
859 .unwrap(),
860 ],
861 },
862 &hex!(
863 "e500c180e1a00000000000000000000000000000000000000000000000000000000000000000"
864 )[..],
865 ),
866 (
867 NewPooledTransactionHashes68 {
868 types: vec![0x00, 0x00],
869 sizes: vec![0x00, 0x00],
870 hashes: vec![
871 B256::from_str(
872 "0x0000000000000000000000000000000000000000000000000000000000000000",
873 )
874 .unwrap(),
875 B256::from_str(
876 "0x0000000000000000000000000000000000000000000000000000000000000000",
877 )
878 .unwrap(),
879 ],
880 },
881 &hex!(
882 "f84a820000c28080f842a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000"
883 )[..],
884 ),
885 (
886 NewPooledTransactionHashes68 {
887 types: vec![0x02],
888 sizes: vec![0xb6],
889 hashes: vec![
890 B256::from_str(
891 "0xfecbed04c7b88d8e7221a0a3f5dc33f220212347fc167459ea5cc9c3eb4c1124",
892 )
893 .unwrap(),
894 ],
895 },
896 &hex!(
897 "e602c281b6e1a0fecbed04c7b88d8e7221a0a3f5dc33f220212347fc167459ea5cc9c3eb4c1124"
898 )[..],
899 ),
900 (
901 NewPooledTransactionHashes68 {
902 types: vec![0xff, 0xff],
903 sizes: vec![0xffffffff, 0xffffffff],
904 hashes: vec![
905 B256::from_str(
906 "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
907 )
908 .unwrap(),
909 B256::from_str(
910 "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
911 )
912 .unwrap(),
913 ],
914 },
915 &hex!(
916 "f85282ffffca84ffffffff84fffffffff842a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
917 )[..],
918 ),
919 (
920 NewPooledTransactionHashes68 {
921 types: vec![0xff, 0xff],
922 sizes: vec![0xffffffff, 0xffffffff],
923 hashes: vec![
924 B256::from_str(
925 "0xbeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafe",
926 )
927 .unwrap(),
928 B256::from_str(
929 "0xbeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafe",
930 )
931 .unwrap(),
932 ],
933 },
934 &hex!(
935 "f85282ffffca84ffffffff84fffffffff842a0beefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafea0beefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafebeefcafe"
936 )[..],
937 ),
938 (
939 NewPooledTransactionHashes68 {
940 types: vec![0x10, 0x10],
941 sizes: vec![0xdeadc0de, 0xdeadc0de],
942 hashes: vec![
943 B256::from_str(
944 "0x3b9aca00f0671c9a2a1b817a0a78d3fe0c0f776cccb2a8c3c1b412a4f4e4d4e2",
945 )
946 .unwrap(),
947 B256::from_str(
948 "0x3b9aca00f0671c9a2a1b817a0a78d3fe0c0f776cccb2a8c3c1b412a4f4e4d4e2",
949 )
950 .unwrap(),
951 ],
952 },
953 &hex!(
954 "f852821010ca84deadc0de84deadc0def842a03b9aca00f0671c9a2a1b817a0a78d3fe0c0f776cccb2a8c3c1b412a4f4e4d4e2a03b9aca00f0671c9a2a1b817a0a78d3fe0c0f776cccb2a8c3c1b412a4f4e4d4e2"
955 )[..],
956 ),
957 (
958 NewPooledTransactionHashes68 {
959 types: vec![0x6f, 0x6f],
960 sizes: vec![0x7fffffff, 0x7fffffff],
961 hashes: vec![
962 B256::from_str(
963 "0x0000000000000000000000000000000000000000000000000000000000000002",
964 )
965 .unwrap(),
966 B256::from_str(
967 "0x0000000000000000000000000000000000000000000000000000000000000002",
968 )
969 .unwrap(),
970 ],
971 },
972 &hex!(
973 "f852826f6fca847fffffff847ffffffff842a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000002"
974 )[..],
975 ),
976 ];
977
978 for vector in vectors {
979 test_encoding_vector(vector);
980 }
981 }
982
983 #[test]
984 fn request_hashes_retain_count_keep_subset() {
985 let mut hashes = RequestTxHashes::new(
986 [
987 b256!("0x0000000000000000000000000000000000000000000000000000000000000001"),
988 b256!("0x0000000000000000000000000000000000000000000000000000000000000002"),
989 b256!("0x0000000000000000000000000000000000000000000000000000000000000003"),
990 b256!("0x0000000000000000000000000000000000000000000000000000000000000004"),
991 b256!("0x0000000000000000000000000000000000000000000000000000000000000005"),
992 ]
993 .into_iter()
994 .collect::<HashSet<_>>(),
995 );
996
997 let rest = hashes.retain_count(3);
998
999 assert_eq!(3, hashes.len());
1000 assert_eq!(2, rest.len());
1001 }
1002
1003 #[test]
1004 fn request_hashes_retain_count_keep_all() {
1005 let mut hashes = RequestTxHashes::new(
1006 [
1007 b256!("0x0000000000000000000000000000000000000000000000000000000000000001"),
1008 b256!("0x0000000000000000000000000000000000000000000000000000000000000002"),
1009 b256!("0x0000000000000000000000000000000000000000000000000000000000000003"),
1010 b256!("0x0000000000000000000000000000000000000000000000000000000000000004"),
1011 b256!("0x0000000000000000000000000000000000000000000000000000000000000005"),
1012 ]
1013 .into_iter()
1014 .collect::<HashSet<_>>(),
1015 );
1016
1017 let _ = hashes.retain_count(6);
1018
1019 assert_eq!(5, hashes.len());
1020 }
1021
1022 #[test]
1023 fn split_request_hashes_keep_none() {
1024 let mut hashes = RequestTxHashes::new(
1025 [
1026 b256!("0x0000000000000000000000000000000000000000000000000000000000000001"),
1027 b256!("0x0000000000000000000000000000000000000000000000000000000000000002"),
1028 b256!("0x0000000000000000000000000000000000000000000000000000000000000003"),
1029 b256!("0x0000000000000000000000000000000000000000000000000000000000000004"),
1030 b256!("0x0000000000000000000000000000000000000000000000000000000000000005"),
1031 ]
1032 .into_iter()
1033 .collect::<HashSet<_>>(),
1034 );
1035
1036 let rest = hashes.retain_count(0);
1037
1038 assert_eq!(0, hashes.len());
1039 assert_eq!(5, rest.len());
1040 }
1041
1042 fn signed_transaction() -> impl SignedTransaction {
1043 TransactionSigned::new_unhashed(
1044 Transaction::Legacy(Default::default()),
1045 Signature::new(
1046 U256::from_str(
1047 "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12",
1048 )
1049 .unwrap(),
1050 U256::from_str(
1051 "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10",
1052 )
1053 .unwrap(),
1054 false,
1055 ),
1056 )
1057 }
1058
1059 #[test]
1060 fn test_pooled_tx_hashes_68_push() {
1061 let tx = signed_transaction();
1062 let mut tx_hashes =
1063 NewPooledTransactionHashes68 { types: vec![], sizes: vec![], hashes: vec![] };
1064 tx_hashes.push(&tx);
1065 assert_eq!(tx_hashes.types.len(), 1);
1066 assert_eq!(tx_hashes.sizes.len(), 1);
1067 assert_eq!(tx_hashes.hashes.len(), 1);
1068 assert_eq!(tx_hashes.types[0], tx.ty());
1069 assert_eq!(tx_hashes.sizes[0], tx.encode_2718_len());
1070 assert_eq!(tx_hashes.hashes[0], *tx.tx_hash());
1071 }
1072
1073 #[test]
1074 fn test_pooled_tx_hashes_68_extend() {
1075 let tx = signed_transaction();
1076 let txs = vec![tx.clone(), tx.clone()];
1077 let mut tx_hashes =
1078 NewPooledTransactionHashes68 { types: vec![], sizes: vec![], hashes: vec![] };
1079 tx_hashes.extend(&txs);
1080 assert_eq!(tx_hashes.types.len(), 2);
1081 assert_eq!(tx_hashes.sizes.len(), 2);
1082 assert_eq!(tx_hashes.hashes.len(), 2);
1083 assert_eq!(tx_hashes.types[0], tx.ty());
1084 assert_eq!(tx_hashes.sizes[0], tx.encode_2718_len());
1085 assert_eq!(tx_hashes.hashes[0], *tx.tx_hash());
1086 assert_eq!(tx_hashes.types[1], tx.ty());
1087 assert_eq!(tx_hashes.sizes[1], tx.encode_2718_len());
1088 assert_eq!(tx_hashes.hashes[1], *tx.tx_hash());
1089 }
1090
1091 #[test]
1092 fn test_pooled_tx_hashes_68_with_transaction() {
1093 let tx = signed_transaction();
1094 let tx_hashes =
1095 NewPooledTransactionHashes68 { types: vec![], sizes: vec![], hashes: vec![] }
1096 .with_transaction(&tx);
1097 assert_eq!(tx_hashes.types.len(), 1);
1098 assert_eq!(tx_hashes.sizes.len(), 1);
1099 assert_eq!(tx_hashes.hashes.len(), 1);
1100 assert_eq!(tx_hashes.types[0], tx.ty());
1101 assert_eq!(tx_hashes.sizes[0], tx.encode_2718_len());
1102 assert_eq!(tx_hashes.hashes[0], *tx.tx_hash());
1103 }
1104
1105 #[test]
1106 fn test_pooled_tx_hashes_68_with_transactions() {
1107 let tx = signed_transaction();
1108 let txs = vec![tx.clone(), tx.clone()];
1109 let tx_hashes =
1110 NewPooledTransactionHashes68 { types: vec![], sizes: vec![], hashes: vec![] }
1111 .with_transactions(&txs);
1112 assert_eq!(tx_hashes.types.len(), 2);
1113 assert_eq!(tx_hashes.sizes.len(), 2);
1114 assert_eq!(tx_hashes.hashes.len(), 2);
1115 assert_eq!(tx_hashes.types[0], tx.ty());
1116 assert_eq!(tx_hashes.sizes[0], tx.encode_2718_len());
1117 assert_eq!(tx_hashes.hashes[0], *tx.tx_hash());
1118 assert_eq!(tx_hashes.types[1], tx.ty());
1119 assert_eq!(tx_hashes.sizes[1], tx.encode_2718_len());
1120 assert_eq!(tx_hashes.hashes[1], *tx.tx_hash());
1121 }
1122}