Skip to main content

reth_eth_wire_types/
blocks.rs

1//! Implements the `GetBlockHeaders`, `GetBlockBodies`, `BlockHeaders`, and `BlockBodies` message
2//! types.
3
4use crate::HeadersDirection;
5use alloc::vec::Vec;
6use alloy_eips::BlockHashOrNumber;
7use alloy_primitives::B256;
8use alloy_rlp::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper};
9use derive_more::{Deref, IntoIterator};
10use reth_codecs_derive::{add_arbitrary_tests, generate_tests};
11
12/// A request for a peer to return block headers starting at the requested block.
13/// The peer must return at most [`limit`](#structfield.limit) headers.
14/// If the [`reverse`](#structfield.reverse) field is `true`, the headers will be returned starting
15/// at [`start_block`](#structfield.start_block), traversing towards the genesis block.
16/// Otherwise, headers will be returned starting at [`start_block`](#structfield.start_block),
17/// traversing towards the latest block.
18///
19/// If the [`skip`](#structfield.skip) field is non-zero, the peer must skip that amount of headers
20/// in the direction specified by [`reverse`](#structfield.reverse).
21#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RlpEncodable, RlpDecodable)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
24#[add_arbitrary_tests(rlp)]
25pub struct GetBlockHeaders {
26    /// The block number or hash that the peer should start returning headers from.
27    pub start_block: BlockHashOrNumber,
28
29    /// The maximum number of headers to return.
30    pub limit: u64,
31
32    /// The number of blocks that the node should skip while traversing and returning headers.
33    /// A skip value of zero denotes that the peer should return contiguous headers, starting from
34    /// [`start_block`](#structfield.start_block) and returning at most
35    /// [`limit`](#structfield.limit) headers.
36    pub skip: u32,
37
38    /// The direction in which the headers should be returned in.
39    pub direction: HeadersDirection,
40}
41
42/// The response to [`GetBlockHeaders`], containing headers if any headers were found.
43#[derive(
44    Clone,
45    Debug,
46    PartialEq,
47    Eq,
48    RlpEncodableWrapper,
49    RlpDecodableWrapper,
50    Default,
51    Deref,
52    IntoIterator,
53)]
54#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
55#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
56pub struct BlockHeaders<H = alloy_consensus::Header>(
57    /// The requested headers.
58    pub Vec<H>,
59);
60
61generate_tests!(#[rlp, 10] BlockHeaders<alloy_consensus::Header>, EthBlockHeadersTests);
62
63impl<H> From<Vec<H>> for BlockHeaders<H> {
64    fn from(headers: Vec<H>) -> Self {
65        Self(headers)
66    }
67}
68
69/// A request for a peer to return block bodies for the given block hashes.
70#[derive(
71    Clone,
72    Debug,
73    PartialEq,
74    Eq,
75    RlpEncodableWrapper,
76    RlpDecodableWrapper,
77    Default,
78    Deref,
79    IntoIterator,
80)]
81#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
82#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
83#[add_arbitrary_tests(rlp)]
84pub struct GetBlockBodies(
85    /// The block hashes to request bodies for.
86    pub Vec<B256>,
87);
88
89impl From<Vec<B256>> for GetBlockBodies {
90    fn from(hashes: Vec<B256>) -> Self {
91        Self(hashes)
92    }
93}
94
95/// The response to [`GetBlockBodies`], containing the block bodies that the peer knows about if
96/// any were found.
97#[derive(
98    Clone,
99    Debug,
100    PartialEq,
101    Eq,
102    RlpEncodableWrapper,
103    RlpDecodableWrapper,
104    Default,
105    Deref,
106    IntoIterator,
107)]
108#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
109#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
110pub struct BlockBodies<B = reth_ethereum_primitives::BlockBody>(
111    /// The requested block bodies, each of which should correspond to a hash in the request.
112    pub Vec<B>,
113);
114
115generate_tests!(#[rlp, 16] BlockBodies<reth_ethereum_primitives::BlockBody>, EthBlockBodiesTests);
116
117impl<B> From<Vec<B>> for BlockBodies<B> {
118    fn from(bodies: Vec<B>) -> Self {
119        Self(bodies)
120    }
121}
122
123#[cfg(test)]
124mod tests {
125    use crate::{
126        message::RequestPair, BlockBodies, BlockHeaders, GetBlockBodies, GetBlockHeaders,
127        HeadersDirection,
128    };
129    use alloy_consensus::{Header, TxLegacy};
130    use alloy_eips::BlockHashOrNumber;
131    use alloy_primitives::{hex, Signature, TxKind, U256};
132    use alloy_rlp::{Decodable, Encodable};
133    use reth_ethereum_primitives::{BlockBody, Transaction, TransactionSigned};
134    use std::str::FromStr;
135
136    #[test]
137    fn decode_hash() {
138        // this is a valid 32 byte rlp string
139        let rlp = hex!("a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
140        let decoded_number = BlockHashOrNumber::decode(&mut &rlp[..]).unwrap();
141        let full_bytes = [0xff; 32].into();
142        let expected = BlockHashOrNumber::Hash(full_bytes);
143        assert_eq!(expected, decoded_number);
144    }
145
146    #[test]
147    fn decode_number() {
148        // this is a valid 64 bit number
149        let rlp = hex!("88ffffffffffffffff");
150        let decoded_number = BlockHashOrNumber::decode(&mut &rlp[..]).unwrap();
151        let expected = BlockHashOrNumber::Number(u64::MAX);
152        assert_eq!(expected, decoded_number);
153    }
154
155    #[test]
156    fn decode_largest_single_byte() {
157        // the largest single byte is 0x7f, so we should be able to decode this into a u64
158        let rlp = hex!("7f");
159        let decoded_number = BlockHashOrNumber::decode(&mut &rlp[..]).unwrap();
160        let expected = BlockHashOrNumber::Number(0x7fu64);
161        assert_eq!(expected, decoded_number);
162    }
163
164    #[test]
165    fn decode_long_hash() {
166        // let's try a 33 byte long string
167        // 0xa1 = 0x80 (start of string) + 0x21 (33, length of string)
168        let long_rlp = hex!("a1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
169        let decode_result = BlockHashOrNumber::decode(&mut &long_rlp[..]);
170        assert!(
171            decode_result.is_err(),
172            "Decoding a bytestring longer than 32 bytes should not decode successfully"
173        );
174    }
175
176    #[test]
177    fn decode_long_number() {
178        // let's try a 72 bit number
179        // 0x89 = 0x80 (start of string) + 0x09 (9, length of string)
180        let long_number = hex!("89ffffffffffffffffff");
181        let decode_result = BlockHashOrNumber::decode(&mut &long_number[..]);
182        assert!(
183            decode_result.is_err(),
184            "Decoding a number longer than 64 bits (but not exactly 32 bytes) should not decode successfully"
185        );
186    }
187
188    // Test vector from: https://eips.ethereum.org/EIPS/eip-2481
189    #[test]
190    fn encode_get_block_header() {
191        let expected = hex!(
192            "e8820457e4a000000000000000000000000000000000000000000000000000000000deadc0de050580"
193        );
194        let mut data = vec![];
195        RequestPair::<GetBlockHeaders> {
196            request_id: 1111,
197            message: GetBlockHeaders {
198                start_block: BlockHashOrNumber::Hash(
199                    hex!("00000000000000000000000000000000000000000000000000000000deadc0de").into(),
200                ),
201                limit: 5,
202                skip: 5,
203                direction: HeadersDirection::Rising,
204            },
205        }
206        .encode(&mut data);
207        assert_eq!(data, expected);
208    }
209
210    // Test vector from: https://eips.ethereum.org/EIPS/eip-2481
211    #[test]
212    fn decode_get_block_header() {
213        let data = hex!(
214            "e8820457e4a000000000000000000000000000000000000000000000000000000000deadc0de050580"
215        );
216        let expected = RequestPair::<GetBlockHeaders> {
217            request_id: 1111,
218            message: GetBlockHeaders {
219                start_block: BlockHashOrNumber::Hash(
220                    hex!("00000000000000000000000000000000000000000000000000000000deadc0de").into(),
221                ),
222                limit: 5,
223                skip: 5,
224                direction: HeadersDirection::Rising,
225            },
226        };
227        let result = RequestPair::decode(&mut &data[..]);
228        assert_eq!(result.unwrap(), expected);
229    }
230
231    // Test vector from: https://eips.ethereum.org/EIPS/eip-2481
232    #[test]
233    fn encode_get_block_header_number() {
234        let expected = hex!("ca820457c682270f050580");
235        let mut data = vec![];
236        RequestPair {
237            request_id: 1111,
238            message: GetBlockHeaders {
239                start_block: BlockHashOrNumber::Number(9999),
240                limit: 5,
241                skip: 5,
242                direction: HeadersDirection::Rising,
243            },
244        }
245        .encode(&mut data);
246        assert_eq!(data, expected);
247    }
248
249    // Test vector from: https://eips.ethereum.org/EIPS/eip-2481
250    #[test]
251    fn decode_get_block_header_number() {
252        let data = hex!("ca820457c682270f050580");
253        let expected = RequestPair {
254            request_id: 1111,
255            message: GetBlockHeaders {
256                start_block: BlockHashOrNumber::Number(9999),
257                limit: 5,
258                skip: 5,
259                direction: HeadersDirection::Rising,
260            },
261        };
262        let result = RequestPair::decode(&mut &data[..]);
263        assert_eq!(result.unwrap(), expected);
264    }
265
266    // Test vector from: https://eips.ethereum.org/EIPS/eip-2481
267    #[test]
268    fn encode_block_header() {
269        // [ (f90202) 0x0457 = 1111, [ (f901fc) [ (f901f9) header ] ] ]
270        let expected = hex!(
271            "f90202820457f901fcf901f9a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008208ae820d0582115c8215b3821a0a827788a00000000000000000000000000000000000000000000000000000000000000000880000000000000000"
272        );
273        let mut data = vec![];
274        RequestPair {
275            request_id: 1111,
276            message: BlockHeaders(vec![
277                Header {
278                    parent_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
279                    ommers_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
280                    beneficiary: hex!("0000000000000000000000000000000000000000").into(),
281                    state_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
282                    transactions_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
283                    receipts_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
284                    logs_bloom: hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into(),
285                    difficulty: U256::from(0x8aeu64),
286                    number: 0xd05u64,
287                    gas_limit: 0x115c,
288                    gas_used: 0x15b3,
289                    timestamp: 0x1a0au64,
290                    extra_data: hex!("7788")[..].into(),
291                    mix_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
292                    nonce: 0x0000000000000000u64.into(),
293                    base_fee_per_gas: None,
294                    withdrawals_root: None,
295                    blob_gas_used: None,
296                    excess_blob_gas: None,
297                    parent_beacon_block_root: None,
298                    requests_hash: None,
299                },
300            ]),
301        }.encode(&mut data);
302        assert_eq!(data, expected);
303    }
304
305    // Test vector from: https://eips.ethereum.org/EIPS/eip-2481
306    #[test]
307    fn decode_block_header() {
308        let data = hex!(
309            "f90202820457f901fcf901f9a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008208ae820d0582115c8215b3821a0a827788a00000000000000000000000000000000000000000000000000000000000000000880000000000000000"
310        );
311        let expected = RequestPair {
312            request_id: 1111,
313            message: BlockHeaders(vec![
314                Header {
315                    parent_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
316                    ommers_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
317                    beneficiary: hex!("0000000000000000000000000000000000000000").into(),
318                    state_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
319                    transactions_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
320                    receipts_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
321                    logs_bloom: hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into(),
322                    difficulty: U256::from(0x8aeu64),
323                    number: 0xd05u64,
324                    gas_limit: 0x115c,
325                    gas_used: 0x15b3,
326                    timestamp: 0x1a0au64,
327                    extra_data: hex!("7788")[..].into(),
328                    mix_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
329                    nonce: 0x0000000000000000u64.into(),
330                    base_fee_per_gas: None,
331                    withdrawals_root: None,
332                    blob_gas_used: None,
333                    excess_blob_gas: None,
334                    parent_beacon_block_root: None,
335                    requests_hash: None,
336                },
337            ]),
338        };
339        let result = RequestPair::decode(&mut &data[..]);
340        assert_eq!(result.unwrap(), expected);
341    }
342
343    // Test vector from: https://eips.ethereum.org/EIPS/eip-2481
344    #[test]
345    fn encode_get_block_bodies() {
346        let expected = hex!(
347            "f847820457f842a000000000000000000000000000000000000000000000000000000000deadc0dea000000000000000000000000000000000000000000000000000000000feedbeef"
348        );
349        let mut data = vec![];
350        RequestPair {
351            request_id: 1111,
352            message: GetBlockBodies(vec![
353                hex!("00000000000000000000000000000000000000000000000000000000deadc0de").into(),
354                hex!("00000000000000000000000000000000000000000000000000000000feedbeef").into(),
355            ]),
356        }
357        .encode(&mut data);
358        assert_eq!(data, expected);
359    }
360
361    // Test vector from: https://eips.ethereum.org/EIPS/eip-2481
362    #[test]
363    fn decode_get_block_bodies() {
364        let data = hex!(
365            "f847820457f842a000000000000000000000000000000000000000000000000000000000deadc0dea000000000000000000000000000000000000000000000000000000000feedbeef"
366        );
367        let expected = RequestPair {
368            request_id: 1111,
369            message: GetBlockBodies(vec![
370                hex!("00000000000000000000000000000000000000000000000000000000deadc0de").into(),
371                hex!("00000000000000000000000000000000000000000000000000000000feedbeef").into(),
372            ]),
373        };
374        let result = RequestPair::decode(&mut &data[..]);
375        assert_eq!(result.unwrap(), expected);
376    }
377
378    // Test vector from: https://eips.ethereum.org/EIPS/eip-2481
379    #[test]
380    fn encode_block_bodies() {
381        let expected = hex!(
382            "f902dc820457f902d6f902d3f8d2f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afbf901fcf901f9a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008208ae820d0582115c8215b3821a0a827788a00000000000000000000000000000000000000000000000000000000000000000880000000000000000"
383        );
384        let mut data = vec![];
385        let request = RequestPair {
386            request_id: 1111,
387            message: BlockBodies(vec![
388                BlockBody {
389                    transactions: vec![
390                        TransactionSigned::new_unhashed(Transaction::Legacy(TxLegacy {
391                            chain_id: Some(1),
392                            nonce: 0x8u64,
393                            gas_price: 0x4a817c808,
394                            gas_limit: 0x2e248,
395                            to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
396                            value: U256::from(0x200u64),
397                            input: Default::default(),
398                        }), Signature::new(
399                                U256::from_str("0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12").unwrap(),
400                                U256::from_str("0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10").unwrap(),
401                                false,
402                            ),
403                        ),
404                        TransactionSigned::new_unhashed(Transaction::Legacy(TxLegacy {
405                            chain_id: Some(1),
406                            nonce: 0x9u64,
407                            gas_price: 0x4a817c809,
408                            gas_limit: 0x33450,
409                            to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
410                            value: U256::from(0x2d9u64),
411                            input: Default::default(),
412                        }), Signature::new(
413                                U256::from_str("0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
414                                U256::from_str("0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
415                                false,
416                            ),
417                        ),
418                    ],
419                    ommers: vec![
420                        Header {
421                            parent_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
422                            ommers_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
423                            beneficiary: hex!("0000000000000000000000000000000000000000").into(),
424                            state_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
425                            transactions_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
426                            receipts_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
427                            logs_bloom: hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into(),
428                            difficulty: U256::from(0x8aeu64),
429                            number: 0xd05u64,
430                            gas_limit: 0x115c,
431                            gas_used: 0x15b3,
432                            timestamp: 0x1a0au64,
433                            extra_data: hex!("7788")[..].into(),
434                            mix_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
435                            nonce: 0x0000000000000000u64.into(),
436                            base_fee_per_gas: None,
437                            withdrawals_root: None,
438                            blob_gas_used: None,
439                            excess_blob_gas: None,
440                            parent_beacon_block_root: None,
441                            requests_hash: None,
442                        },
443                    ],
444                    withdrawals: None,
445                }
446            ]),
447        };
448        request.encode(&mut data);
449        assert_eq!(data, expected);
450    }
451
452    // Test vector from: https://eips.ethereum.org/EIPS/eip-2481
453    #[test]
454    fn decode_block_bodies() {
455        let data = hex!(
456            "f902dc820457f902d6f902d3f8d2f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afbf901fcf901f9a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008208ae820d0582115c8215b3821a0a827788a00000000000000000000000000000000000000000000000000000000000000000880000000000000000"
457        );
458        let expected = RequestPair {
459            request_id: 1111,
460            message: BlockBodies(vec![
461                BlockBody {
462                    transactions: vec![
463                        TransactionSigned::new_unhashed(Transaction::Legacy(
464                            TxLegacy {
465                                chain_id: Some(1),
466                                nonce: 0x8u64,
467                                gas_price: 0x4a817c808,
468                                gas_limit: 0x2e248,
469                                to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
470                                value: U256::from(0x200u64),
471                                input: Default::default(),
472                            }),
473                                                        Signature::new(
474                                U256::from_str("0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12").unwrap(),
475                                U256::from_str("0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10").unwrap(),
476                                false,
477                            ),
478                        ),
479                        TransactionSigned::new_unhashed(
480                            Transaction::Legacy(TxLegacy {
481                                chain_id: Some(1),
482                                nonce: 0x9u64,
483                                gas_price: 0x4a817c809,
484                                gas_limit: 0x33450,
485                                to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
486                                value: U256::from(0x2d9u64),
487                                input: Default::default(),
488                            }),
489                            Signature::new(
490                                U256::from_str("0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
491                                U256::from_str("0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
492                                false,
493                            ),
494                        ),
495                    ],
496                    ommers: vec![
497                        Header {
498                            parent_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
499                            ommers_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
500                            beneficiary: hex!("0000000000000000000000000000000000000000").into(),
501                            state_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
502                            transactions_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
503                            receipts_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
504                            logs_bloom: hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into(),
505                            difficulty: U256::from(0x8aeu64),
506                            number: 0xd05u64,
507                            gas_limit: 0x115c,
508                            gas_used: 0x15b3,
509                            timestamp: 0x1a0au64,
510                            extra_data: hex!("7788")[..].into(),
511                            mix_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
512                            nonce: 0x0000000000000000u64.into(),
513                            base_fee_per_gas: None,
514                            withdrawals_root: None,
515                            blob_gas_used: None,
516                            excess_blob_gas: None,
517                            parent_beacon_block_root: None,
518                            requests_hash: None,
519                        },
520                    ],
521                    withdrawals: None,
522                }
523            ]),
524        };
525        let result = RequestPair::decode(&mut &data[..]).unwrap();
526        assert_eq!(result, expected);
527    }
528
529    #[test]
530    fn empty_block_bodies_rlp() {
531        let body = BlockBodies::default();
532        let mut buf = Vec::new();
533        body.encode(&mut buf);
534        let decoded = BlockBodies::<BlockBody>::decode(&mut buf.as_slice()).unwrap();
535        assert_eq!(body, decoded);
536    }
537}