Skip to main content

reth_eth_wire_types/
transactions.rs

1//! Implements the `GetPooledTransactions` and `PooledTransactions` message types.
2
3use alloc::vec::Vec;
4use alloy_consensus::transaction::PooledTransaction;
5use alloy_eips::eip2718::Encodable2718;
6use alloy_primitives::B256;
7use alloy_rlp::{RlpDecodableWrapper, RlpEncodableWrapper};
8use derive_more::{Constructor, Deref, IntoIterator};
9use reth_codecs_derive::add_arbitrary_tests;
10
11/// A list of transaction hashes that the peer would like transaction bodies for.
12#[derive(
13    Clone,
14    Debug,
15    PartialEq,
16    Eq,
17    RlpEncodableWrapper,
18    RlpDecodableWrapper,
19    Default,
20    Deref,
21    IntoIterator,
22)]
23#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
25#[add_arbitrary_tests(rlp)]
26pub struct GetPooledTransactions(
27    /// The transaction hashes to request transaction bodies for.
28    pub Vec<B256>,
29);
30
31impl<T> From<Vec<T>> for GetPooledTransactions
32where
33    T: Into<B256>,
34{
35    fn from(hashes: Vec<T>) -> Self {
36        Self(hashes.into_iter().map(|h| h.into()).collect())
37    }
38}
39
40/// The response to [`GetPooledTransactions`], containing the transaction bodies associated with
41/// the requested hashes.
42///
43/// This response may not contain all bodies requested, but the bodies should be in the same order
44/// as the request's hashes. Hashes may be skipped, and the client should ensure that each body
45/// corresponds to a requested hash. Hashes may need to be re-requested if the bodies are not
46/// included in the response.
47// #[derive_arbitrary(rlp, 10)]
48#[derive(
49    Clone,
50    Debug,
51    PartialEq,
52    Eq,
53    RlpEncodableWrapper,
54    RlpDecodableWrapper,
55    IntoIterator,
56    Deref,
57    Constructor,
58)]
59#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
60pub struct PooledTransactions<T = PooledTransaction>(
61    /// The transaction bodies, each of which should correspond to a requested hash.
62    pub Vec<T>,
63);
64
65impl<T: Encodable2718> PooledTransactions<T> {
66    /// Returns an iterator over the transaction hashes in this response.
67    pub fn hashes(&self) -> impl Iterator<Item = B256> + '_ {
68        self.iter().map(|tx| tx.trie_hash())
69    }
70}
71
72impl<T, U> TryFrom<Vec<U>> for PooledTransactions<T>
73where
74    T: TryFrom<U>,
75{
76    type Error = T::Error;
77
78    fn try_from(txs: Vec<U>) -> Result<Self, Self::Error> {
79        txs.into_iter().map(T::try_from).collect()
80    }
81}
82
83impl<T> FromIterator<T> for PooledTransactions<T> {
84    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
85        Self(iter.into_iter().collect())
86    }
87}
88
89impl<T> Default for PooledTransactions<T> {
90    fn default() -> Self {
91        Self(Default::default())
92    }
93}
94
95#[cfg(test)]
96mod tests {
97    use crate::{message::RequestPair, GetPooledTransactions, PooledTransactions};
98    use alloy_consensus::{transaction::PooledTransaction, TxEip1559, TxLegacy};
99    use alloy_primitives::{hex, Signature, TxKind, U256};
100    use alloy_rlp::{Decodable, Encodable};
101    use reth_chainspec::MIN_TRANSACTION_GAS;
102    use reth_ethereum_primitives::{Transaction, TransactionSigned};
103    use std::str::FromStr;
104
105    #[test]
106    // Test vector from: https://eips.ethereum.org/EIPS/eip-2481
107    fn encode_get_pooled_transactions() {
108        let expected = hex!(
109            "f847820457f842a000000000000000000000000000000000000000000000000000000000deadc0dea000000000000000000000000000000000000000000000000000000000feedbeef"
110        );
111        let mut data = vec![];
112        let request = RequestPair {
113            request_id: 1111,
114            message: GetPooledTransactions(vec![
115                hex!("00000000000000000000000000000000000000000000000000000000deadc0de").into(),
116                hex!("00000000000000000000000000000000000000000000000000000000feedbeef").into(),
117            ]),
118        };
119        request.encode(&mut data);
120        assert_eq!(data, expected);
121    }
122
123    #[test]
124    // Test vector from: https://eips.ethereum.org/EIPS/eip-2481
125    fn decode_get_pooled_transactions() {
126        let data = hex!(
127            "f847820457f842a000000000000000000000000000000000000000000000000000000000deadc0dea000000000000000000000000000000000000000000000000000000000feedbeef"
128        );
129        let request = RequestPair::<GetPooledTransactions>::decode(&mut &data[..]).unwrap();
130        assert_eq!(
131            request,
132            RequestPair {
133                request_id: 1111,
134                message: GetPooledTransactions(vec![
135                    hex!("00000000000000000000000000000000000000000000000000000000deadc0de").into(),
136                    hex!("00000000000000000000000000000000000000000000000000000000feedbeef").into(),
137                ])
138            }
139        );
140    }
141
142    #[test]
143    // Test vector from: https://eips.ethereum.org/EIPS/eip-2481
144    fn encode_pooled_transactions() {
145        let expected = hex!(
146            "f8d7820457f8d2f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb"
147        );
148        let mut data = vec![];
149        let txs = vec![
150            TransactionSigned::new_unhashed(
151                Transaction::Legacy(TxLegacy {
152                    chain_id: Some(1),
153                    nonce: 0x8u64,
154                    gas_price: 0x4a817c808,
155                    gas_limit: 0x2e248,
156                    to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
157                    value: U256::from(0x200u64),
158                    input: Default::default(),
159                }),
160                Signature::new(
161                    U256::from_str(
162                        "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12",
163                    )
164                    .unwrap(),
165                    U256::from_str(
166                        "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10",
167                    )
168                    .unwrap(),
169                    false,
170                ),
171            ),
172            TransactionSigned::new_unhashed(
173                Transaction::Legacy(TxLegacy {
174                    chain_id: Some(1),
175                    nonce: 0x09u64,
176                    gas_price: 0x4a817c809,
177                    gas_limit: 0x33450,
178                    to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
179                    value: U256::from(0x2d9u64),
180                    input: Default::default(),
181                }),
182                Signature::new(
183                    U256::from_str(
184                        "0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb",
185                    )
186                    .unwrap(),
187                    U256::from_str(
188                        "0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb",
189                    )
190                    .unwrap(),
191                    false,
192                ),
193            ),
194        ];
195        let message: Vec<PooledTransaction> = txs
196            .into_iter()
197            .map(|tx| {
198                PooledTransaction::try_from(tx)
199                    .expect("Failed to convert TransactionSigned to PooledTransaction")
200            })
201            .collect();
202        let request = RequestPair {
203            request_id: 1111,
204            message: PooledTransactions(message), /* Assuming PooledTransactions wraps a
205                                                   * Vec<PooledTransaction> */
206        };
207        request.encode(&mut data);
208        assert_eq!(data, expected);
209    }
210
211    #[test]
212    // Test vector from: https://eips.ethereum.org/EIPS/eip-2481
213    fn decode_pooled_transactions() {
214        let data = hex!(
215            "f8d7820457f8d2f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb"
216        );
217        let txs = vec![
218            TransactionSigned::new_unhashed(
219                Transaction::Legacy(TxLegacy {
220                    chain_id: Some(1),
221                    nonce: 0x8u64,
222                    gas_price: 0x4a817c808,
223                    gas_limit: 0x2e248,
224                    to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
225                    value: U256::from(0x200u64),
226                    input: Default::default(),
227                }),
228                Signature::new(
229                    U256::from_str(
230                        "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12",
231                    )
232                    .unwrap(),
233                    U256::from_str(
234                        "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10",
235                    )
236                    .unwrap(),
237                    false,
238                ),
239            ),
240            TransactionSigned::new_unhashed(
241                Transaction::Legacy(TxLegacy {
242                    chain_id: Some(1),
243                    nonce: 0x09u64,
244                    gas_price: 0x4a817c809,
245                    gas_limit: 0x33450,
246                    to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
247                    value: U256::from(0x2d9u64),
248                    input: Default::default(),
249                }),
250                Signature::new(
251                    U256::from_str(
252                        "0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb",
253                    )
254                    .unwrap(),
255                    U256::from_str(
256                        "0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb",
257                    )
258                    .unwrap(),
259                    false,
260                ),
261            ),
262        ];
263        let message: Vec<PooledTransaction> = txs
264            .into_iter()
265            .map(|tx| {
266                PooledTransaction::try_from(tx)
267                    .expect("Failed to convert TransactionSigned to PooledTransaction")
268            })
269            .collect();
270        let expected = RequestPair { request_id: 1111, message: PooledTransactions(message) };
271
272        let request = RequestPair::<PooledTransactions>::decode(&mut &data[..]).unwrap();
273        assert_eq!(request, expected);
274    }
275
276    #[test]
277    fn decode_pooled_transactions_network() {
278        let data = hex!(
279            "f9022980f90225f8650f84832156008287fb94cf7f9e66af820a19257a2108375b180b0ec491678204d2802ca035b7bfeb9ad9ece2cbafaaf8e202e706b4cfaeb233f46198f00b44d4a566a981a0612638fb29427ca33b9a3be2a0a561beecfe0269655be160d35e72d366a6a860b87502f872041a8459682f008459682f0d8252089461815774383099e24810ab832a5b2a5425c154d58829a2241af62c000080c001a059e6b67f48fb32e7e570dfb11e042b5ad2e55e3ce3ce9cd989c7e06e07feeafda0016b83f4f980694ed2eee4d10667242b1f40dc406901b34125b008d334d47469f86b0384773594008398968094d3e8763675e4c425df46cc3b5c0f6cbdac39604687038d7ea4c68000802ba0ce6834447c0a4193c40382e6c57ae33b241379c5418caac9cdc18d786fd12071a03ca3ae86580e94550d7c071e3a02eadb5a77830947c9225165cf9100901bee88f86b01843b9aca00830186a094d3e8763675e4c425df46cc3b5c0f6cbdac3960468702769bb01b2a00802ba0e24d8bd32ad906d6f8b8d7741e08d1959df021698b19ee232feba15361587d0aa05406ad177223213df262cb66ccbb2f46bfdccfdfbbb5ffdda9e2c02d977631daf86b02843b9aca00830186a094d3e8763675e4c425df46cc3b5c0f6cbdac39604687038d7ea4c68000802ba00eb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5aea03a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18"
280        );
281        let decoded_transactions =
282            RequestPair::<PooledTransactions>::decode(&mut &data[..]).unwrap();
283        let txs = vec![
284            TransactionSigned::new_unhashed(
285                Transaction::Legacy(TxLegacy {
286                    chain_id: Some(4),
287                    nonce: 15u64,
288                    gas_price: 2200000000,
289                    gas_limit: 34811,
290                    to: TxKind::Call(hex!("cf7f9e66af820a19257a2108375b180b0ec49167").into()),
291                    value: U256::from(1234u64),
292                    input: Default::default(),
293                }),
294                Signature::new(
295                    U256::from_str(
296                        "0x35b7bfeb9ad9ece2cbafaaf8e202e706b4cfaeb233f46198f00b44d4a566a981",
297                    )
298                    .unwrap(),
299                    U256::from_str(
300                        "0x612638fb29427ca33b9a3be2a0a561beecfe0269655be160d35e72d366a6a860",
301                    )
302                    .unwrap(),
303                    true,
304                ),
305            ),
306            TransactionSigned::new_unhashed(
307                Transaction::Eip1559(TxEip1559 {
308                    chain_id: 4,
309                    nonce: 26u64,
310                    max_priority_fee_per_gas: 1500000000,
311                    max_fee_per_gas: 1500000013,
312                    gas_limit: MIN_TRANSACTION_GAS,
313                    to: TxKind::Call(hex!("61815774383099e24810ab832a5b2a5425c154d5").into()),
314                    value: U256::from(3000000000000000000u64),
315                    input: Default::default(),
316                    access_list: Default::default(),
317                }),
318                Signature::new(
319                    U256::from_str(
320                        "0x59e6b67f48fb32e7e570dfb11e042b5ad2e55e3ce3ce9cd989c7e06e07feeafd",
321                    )
322                    .unwrap(),
323                    U256::from_str(
324                        "0x016b83f4f980694ed2eee4d10667242b1f40dc406901b34125b008d334d47469",
325                    )
326                    .unwrap(),
327                    true,
328                ),
329            ),
330            TransactionSigned::new_unhashed(
331                Transaction::Legacy(TxLegacy {
332                    chain_id: Some(4),
333                    nonce: 3u64,
334                    gas_price: 2000000000,
335                    gas_limit: 10000000,
336                    to: TxKind::Call(hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into()),
337                    value: U256::from(1000000000000000u64),
338                    input: Default::default(),
339                }),
340                Signature::new(
341                    U256::from_str(
342                        "0xce6834447c0a4193c40382e6c57ae33b241379c5418caac9cdc18d786fd12071",
343                    )
344                    .unwrap(),
345                    U256::from_str(
346                        "0x3ca3ae86580e94550d7c071e3a02eadb5a77830947c9225165cf9100901bee88",
347                    )
348                    .unwrap(),
349                    false,
350                ),
351            ),
352            TransactionSigned::new_unhashed(
353                Transaction::Legacy(TxLegacy {
354                    chain_id: Some(4),
355                    nonce: 1u64,
356                    gas_price: 1000000000,
357                    gas_limit: 100000,
358                    to: TxKind::Call(hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into()),
359                    value: U256::from(693361000000000u64),
360                    input: Default::default(),
361                }),
362                Signature::new(
363                    U256::from_str(
364                        "0xe24d8bd32ad906d6f8b8d7741e08d1959df021698b19ee232feba15361587d0a",
365                    )
366                    .unwrap(),
367                    U256::from_str(
368                        "0x5406ad177223213df262cb66ccbb2f46bfdccfdfbbb5ffdda9e2c02d977631da",
369                    )
370                    .unwrap(),
371                    false,
372                ),
373            ),
374            TransactionSigned::new_unhashed(
375                Transaction::Legacy(TxLegacy {
376                    chain_id: Some(4),
377                    nonce: 2u64,
378                    gas_price: 1000000000,
379                    gas_limit: 100000,
380                    to: TxKind::Call(hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into()),
381                    value: U256::from(1000000000000000u64),
382                    input: Default::default(),
383                }),
384                Signature::new(
385                    U256::from_str(
386                        "0xeb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5ae",
387                    )
388                    .unwrap(),
389                    U256::from_str(
390                        "0x3a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18",
391                    )
392                    .unwrap(),
393                    false,
394                ),
395            ),
396        ];
397        let message: Vec<PooledTransaction> = txs
398            .into_iter()
399            .map(|tx| {
400                PooledTransaction::try_from(tx)
401                    .expect("Failed to convert TransactionSigned to PooledTransaction")
402            })
403            .collect();
404        let expected_transactions =
405            RequestPair { request_id: 0, message: PooledTransactions(message) };
406
407        // checking tx by tx for easier debugging if there are any regressions
408        for (decoded, expected) in
409            decoded_transactions.message.0.iter().zip(expected_transactions.message.0.iter())
410        {
411            assert_eq!(decoded, expected);
412        }
413
414        assert_eq!(decoded_transactions, expected_transactions);
415    }
416
417    #[test]
418    fn encode_pooled_transactions_network() {
419        let expected = hex!(
420            "f9022980f90225f8650f84832156008287fb94cf7f9e66af820a19257a2108375b180b0ec491678204d2802ca035b7bfeb9ad9ece2cbafaaf8e202e706b4cfaeb233f46198f00b44d4a566a981a0612638fb29427ca33b9a3be2a0a561beecfe0269655be160d35e72d366a6a860b87502f872041a8459682f008459682f0d8252089461815774383099e24810ab832a5b2a5425c154d58829a2241af62c000080c001a059e6b67f48fb32e7e570dfb11e042b5ad2e55e3ce3ce9cd989c7e06e07feeafda0016b83f4f980694ed2eee4d10667242b1f40dc406901b34125b008d334d47469f86b0384773594008398968094d3e8763675e4c425df46cc3b5c0f6cbdac39604687038d7ea4c68000802ba0ce6834447c0a4193c40382e6c57ae33b241379c5418caac9cdc18d786fd12071a03ca3ae86580e94550d7c071e3a02eadb5a77830947c9225165cf9100901bee88f86b01843b9aca00830186a094d3e8763675e4c425df46cc3b5c0f6cbdac3960468702769bb01b2a00802ba0e24d8bd32ad906d6f8b8d7741e08d1959df021698b19ee232feba15361587d0aa05406ad177223213df262cb66ccbb2f46bfdccfdfbbb5ffdda9e2c02d977631daf86b02843b9aca00830186a094d3e8763675e4c425df46cc3b5c0f6cbdac39604687038d7ea4c68000802ba00eb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5aea03a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18"
421        );
422        let txs = vec![
423            TransactionSigned::new_unhashed(
424                Transaction::Legacy(TxLegacy {
425                    chain_id: Some(4),
426                    nonce: 15u64,
427                    gas_price: 2200000000,
428                    gas_limit: 34811,
429                    to: TxKind::Call(hex!("cf7f9e66af820a19257a2108375b180b0ec49167").into()),
430                    value: U256::from(1234u64),
431                    input: Default::default(),
432                }),
433                Signature::new(
434                    U256::from_str(
435                        "0x35b7bfeb9ad9ece2cbafaaf8e202e706b4cfaeb233f46198f00b44d4a566a981",
436                    )
437                    .unwrap(),
438                    U256::from_str(
439                        "0x612638fb29427ca33b9a3be2a0a561beecfe0269655be160d35e72d366a6a860",
440                    )
441                    .unwrap(),
442                    true,
443                ),
444            ),
445            TransactionSigned::new_unhashed(
446                Transaction::Eip1559(TxEip1559 {
447                    chain_id: 4,
448                    nonce: 26u64,
449                    max_priority_fee_per_gas: 1500000000,
450                    max_fee_per_gas: 1500000013,
451                    gas_limit: MIN_TRANSACTION_GAS,
452                    to: TxKind::Call(hex!("61815774383099e24810ab832a5b2a5425c154d5").into()),
453                    value: U256::from(3000000000000000000u64),
454                    input: Default::default(),
455                    access_list: Default::default(),
456                }),
457                Signature::new(
458                    U256::from_str(
459                        "0x59e6b67f48fb32e7e570dfb11e042b5ad2e55e3ce3ce9cd989c7e06e07feeafd",
460                    )
461                    .unwrap(),
462                    U256::from_str(
463                        "0x016b83f4f980694ed2eee4d10667242b1f40dc406901b34125b008d334d47469",
464                    )
465                    .unwrap(),
466                    true,
467                ),
468            ),
469            TransactionSigned::new_unhashed(
470                Transaction::Legacy(TxLegacy {
471                    chain_id: Some(4),
472                    nonce: 3u64,
473                    gas_price: 2000000000,
474                    gas_limit: 10000000,
475                    to: TxKind::Call(hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into()),
476                    value: U256::from(1000000000000000u64),
477                    input: Default::default(),
478                }),
479                Signature::new(
480                    U256::from_str(
481                        "0xce6834447c0a4193c40382e6c57ae33b241379c5418caac9cdc18d786fd12071",
482                    )
483                    .unwrap(),
484                    U256::from_str(
485                        "0x3ca3ae86580e94550d7c071e3a02eadb5a77830947c9225165cf9100901bee88",
486                    )
487                    .unwrap(),
488                    false,
489                ),
490            ),
491            TransactionSigned::new_unhashed(
492                Transaction::Legacy(TxLegacy {
493                    chain_id: Some(4),
494                    nonce: 1u64,
495                    gas_price: 1000000000,
496                    gas_limit: 100000,
497                    to: TxKind::Call(hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into()),
498                    value: U256::from(693361000000000u64),
499                    input: Default::default(),
500                }),
501                Signature::new(
502                    U256::from_str(
503                        "0xe24d8bd32ad906d6f8b8d7741e08d1959df021698b19ee232feba15361587d0a",
504                    )
505                    .unwrap(),
506                    U256::from_str(
507                        "0x5406ad177223213df262cb66ccbb2f46bfdccfdfbbb5ffdda9e2c02d977631da",
508                    )
509                    .unwrap(),
510                    false,
511                ),
512            ),
513            TransactionSigned::new_unhashed(
514                Transaction::Legacy(TxLegacy {
515                    chain_id: Some(4),
516                    nonce: 2u64,
517                    gas_price: 1000000000,
518                    gas_limit: 100000,
519                    to: TxKind::Call(hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into()),
520                    value: U256::from(1000000000000000u64),
521                    input: Default::default(),
522                }),
523                Signature::new(
524                    U256::from_str(
525                        "0xeb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5ae",
526                    )
527                    .unwrap(),
528                    U256::from_str(
529                        "0x3a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18",
530                    )
531                    .unwrap(),
532                    false,
533                ),
534            ),
535        ];
536        let message: Vec<PooledTransaction> = txs
537            .into_iter()
538            .map(|tx| {
539                PooledTransaction::try_from(tx)
540                    .expect("Failed to convert TransactionSigned to PooledTransaction")
541            })
542            .collect();
543        let transactions = RequestPair { request_id: 0, message: PooledTransactions(message) };
544
545        let mut encoded = vec![];
546        transactions.encode(&mut encoded);
547        assert_eq!(encoded.len(), transactions.length());
548        let encoded_str = hex::encode(encoded);
549        let expected_str = hex::encode(expected);
550        assert_eq!(encoded_str.len(), expected_str.len());
551        assert_eq!(encoded_str, expected_str);
552    }
553}