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                    block_access_list_hash: None,
300                    slot_number: None,
301                },
302            ]),
303        }.encode(&mut data);
304        assert_eq!(data, expected);
305    }
306
307    // Test vector from: https://eips.ethereum.org/EIPS/eip-2481
308    #[test]
309    fn decode_block_header() {
310        let data = hex!(
311            "f90202820457f901fcf901f9a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008208ae820d0582115c8215b3821a0a827788a00000000000000000000000000000000000000000000000000000000000000000880000000000000000"
312        );
313        let expected = RequestPair {
314            request_id: 1111,
315            message: BlockHeaders(vec![
316                Header {
317                    parent_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
318                    ommers_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
319                    beneficiary: hex!("0000000000000000000000000000000000000000").into(),
320                    state_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
321                    transactions_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
322                    receipts_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
323                    logs_bloom: hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into(),
324                    difficulty: U256::from(0x8aeu64),
325                    number: 0xd05u64,
326                    gas_limit: 0x115c,
327                    gas_used: 0x15b3,
328                    timestamp: 0x1a0au64,
329                    extra_data: hex!("7788")[..].into(),
330                    mix_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
331                    nonce: 0x0000000000000000u64.into(),
332                    base_fee_per_gas: None,
333                    withdrawals_root: None,
334                    blob_gas_used: None,
335                    excess_blob_gas: None,
336                    parent_beacon_block_root: None,
337                    requests_hash: None,
338                    block_access_list_hash: None,
339                    slot_number: None,
340                },
341            ]),
342        };
343        let result = RequestPair::decode(&mut &data[..]);
344        assert_eq!(result.unwrap(), expected);
345    }
346
347    // Test vector from: https://eips.ethereum.org/EIPS/eip-2481
348    #[test]
349    fn encode_get_block_bodies() {
350        let expected = hex!(
351            "f847820457f842a000000000000000000000000000000000000000000000000000000000deadc0dea000000000000000000000000000000000000000000000000000000000feedbeef"
352        );
353        let mut data = vec![];
354        RequestPair {
355            request_id: 1111,
356            message: GetBlockBodies(vec![
357                hex!("00000000000000000000000000000000000000000000000000000000deadc0de").into(),
358                hex!("00000000000000000000000000000000000000000000000000000000feedbeef").into(),
359            ]),
360        }
361        .encode(&mut data);
362        assert_eq!(data, expected);
363    }
364
365    // Test vector from: https://eips.ethereum.org/EIPS/eip-2481
366    #[test]
367    fn decode_get_block_bodies() {
368        let data = hex!(
369            "f847820457f842a000000000000000000000000000000000000000000000000000000000deadc0dea000000000000000000000000000000000000000000000000000000000feedbeef"
370        );
371        let expected = RequestPair {
372            request_id: 1111,
373            message: GetBlockBodies(vec![
374                hex!("00000000000000000000000000000000000000000000000000000000deadc0de").into(),
375                hex!("00000000000000000000000000000000000000000000000000000000feedbeef").into(),
376            ]),
377        };
378        let result = RequestPair::decode(&mut &data[..]);
379        assert_eq!(result.unwrap(), expected);
380    }
381
382    // Test vector from: https://eips.ethereum.org/EIPS/eip-2481
383    #[test]
384    fn encode_block_bodies() {
385        let expected = hex!(
386            "f902dc820457f902d6f902d3f8d2f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afbf901fcf901f9a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008208ae820d0582115c8215b3821a0a827788a00000000000000000000000000000000000000000000000000000000000000000880000000000000000"
387        );
388        let mut data = vec![];
389        let request = RequestPair {
390            request_id: 1111,
391            message: BlockBodies(vec![
392                BlockBody {
393                    transactions: vec![
394                        TransactionSigned::new_unhashed(Transaction::Legacy(TxLegacy {
395                            chain_id: Some(1),
396                            nonce: 0x8u64,
397                            gas_price: 0x4a817c808,
398                            gas_limit: 0x2e248,
399                            to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
400                            value: U256::from(0x200u64),
401                            input: Default::default(),
402                        }), Signature::new(
403                                U256::from_str("0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12").unwrap(),
404                                U256::from_str("0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10").unwrap(),
405                                false,
406                            ),
407                        ),
408                        TransactionSigned::new_unhashed(Transaction::Legacy(TxLegacy {
409                            chain_id: Some(1),
410                            nonce: 0x9u64,
411                            gas_price: 0x4a817c809,
412                            gas_limit: 0x33450,
413                            to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
414                            value: U256::from(0x2d9u64),
415                            input: Default::default(),
416                        }), Signature::new(
417                                U256::from_str("0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
418                                U256::from_str("0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
419                                false,
420                            ),
421                        ),
422                    ],
423                    ommers: vec![
424                        Header {
425                            parent_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
426                            ommers_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
427                            beneficiary: hex!("0000000000000000000000000000000000000000").into(),
428                            state_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
429                            transactions_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
430                            receipts_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
431                            logs_bloom: hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into(),
432                            difficulty: U256::from(0x8aeu64),
433                            number: 0xd05u64,
434                            gas_limit: 0x115c,
435                            gas_used: 0x15b3,
436                            timestamp: 0x1a0au64,
437                            extra_data: hex!("7788")[..].into(),
438                            mix_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
439                            nonce: 0x0000000000000000u64.into(),
440                            base_fee_per_gas: None,
441                            withdrawals_root: None,
442                            blob_gas_used: None,
443                            excess_blob_gas: None,
444                            parent_beacon_block_root: None,
445                            requests_hash: None,
446                            block_access_list_hash: None,
447                            slot_number: None,
448                        },
449                    ],
450                    withdrawals: None,
451                }
452            ]),
453        };
454        request.encode(&mut data);
455        assert_eq!(data, expected);
456    }
457
458    // Test vector from: https://eips.ethereum.org/EIPS/eip-2481
459    #[test]
460    fn decode_block_bodies() {
461        let data = hex!(
462            "f902dc820457f902d6f902d3f8d2f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afbf901fcf901f9a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008208ae820d0582115c8215b3821a0a827788a00000000000000000000000000000000000000000000000000000000000000000880000000000000000"
463        );
464        let expected = RequestPair {
465            request_id: 1111,
466            message: BlockBodies(vec![
467                BlockBody {
468                    transactions: vec![
469                        TransactionSigned::new_unhashed(Transaction::Legacy(
470                            TxLegacy {
471                                chain_id: Some(1),
472                                nonce: 0x8u64,
473                                gas_price: 0x4a817c808,
474                                gas_limit: 0x2e248,
475                                to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
476                                value: U256::from(0x200u64),
477                                input: Default::default(),
478                            }),
479                                                        Signature::new(
480                                U256::from_str("0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12").unwrap(),
481                                U256::from_str("0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10").unwrap(),
482                                false,
483                            ),
484                        ),
485                        TransactionSigned::new_unhashed(
486                            Transaction::Legacy(TxLegacy {
487                                chain_id: Some(1),
488                                nonce: 0x9u64,
489                                gas_price: 0x4a817c809,
490                                gas_limit: 0x33450,
491                                to: TxKind::Call(hex!("3535353535353535353535353535353535353535").into()),
492                                value: U256::from(0x2d9u64),
493                                input: Default::default(),
494                            }),
495                            Signature::new(
496                                U256::from_str("0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
497                                U256::from_str("0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
498                                false,
499                            ),
500                        ),
501                    ],
502                    ommers: vec![
503                        Header {
504                            parent_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
505                            ommers_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
506                            beneficiary: hex!("0000000000000000000000000000000000000000").into(),
507                            state_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
508                            transactions_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
509                            receipts_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
510                            logs_bloom: hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into(),
511                            difficulty: U256::from(0x8aeu64),
512                            number: 0xd05u64,
513                            gas_limit: 0x115c,
514                            gas_used: 0x15b3,
515                            timestamp: 0x1a0au64,
516                            extra_data: hex!("7788")[..].into(),
517                            mix_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
518                            nonce: 0x0000000000000000u64.into(),
519                            base_fee_per_gas: None,
520                            withdrawals_root: None,
521                            blob_gas_used: None,
522                            excess_blob_gas: None,
523                            parent_beacon_block_root: None,
524                            requests_hash: None,
525                            block_access_list_hash: None,
526                            slot_number: None,
527                        },
528                    ],
529                    withdrawals: None,
530                }
531            ]),
532        };
533        let result = RequestPair::decode(&mut &data[..]).unwrap();
534        assert_eq!(result, expected);
535    }
536
537    #[test]
538    fn empty_block_bodies_rlp() {
539        let body = BlockBodies::default();
540        let mut buf = Vec::new();
541        body.encode(&mut buf);
542        let decoded = BlockBodies::<BlockBody>::decode(&mut buf.as_slice()).unwrap();
543        assert_eq!(body, decoded);
544    }
545}