reth_eth_wire_types/
transactions.rs

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