1use 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#[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 pub start_block: BlockHashOrNumber,
28
29 pub limit: u64,
31
32 pub skip: u32,
37
38 pub direction: HeadersDirection,
40}
41
42#[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 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#[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 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#[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 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::{b256, hex, Address, Bloom, Signature, TxKind, B256, 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 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 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 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 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 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]
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(b256!(
199 "00000000000000000000000000000000000000000000000000000000deadc0de"
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]
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(b256!(
220 "00000000000000000000000000000000000000000000000000000000deadc0de"
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]
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]
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]
268 fn encode_block_header() {
269 let expected = hex!(
271 "f90202820457f901fcf901f9a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008208ae820d0582115c8215b3821a0a827788a00000000000000000000000000000000000000000000000000000000000000000880000000000000000"
272 );
273 let mut data = vec![];
274 RequestPair {
275 request_id: 1111,
276 message: BlockHeaders(vec![Header {
277 parent_hash: B256::ZERO,
278 ommers_hash: B256::ZERO,
279 beneficiary: Address::ZERO,
280 state_root: B256::ZERO,
281 transactions_root: B256::ZERO,
282 receipts_root: B256::ZERO,
283 logs_bloom: Bloom::ZERO,
284 difficulty: U256::from(0x8aeu64),
285 number: 0xd05u64,
286 gas_limit: 0x115c,
287 gas_used: 0x15b3,
288 timestamp: 0x1a0au64,
289 extra_data: hex!("7788")[..].into(),
290 mix_hash: B256::ZERO,
291 nonce: 0x0000000000000000u64.into(),
292 base_fee_per_gas: None,
293 withdrawals_root: None,
294 blob_gas_used: None,
295 excess_blob_gas: None,
296 parent_beacon_block_root: None,
297 requests_hash: None,
298 block_access_list_hash: None,
299 slot_number: None,
300 }]),
301 }
302 .encode(&mut data);
303 assert_eq!(data, expected);
304 }
305
306 #[test]
308 fn decode_block_header() {
309 let data = hex!(
310 "f90202820457f901fcf901f9a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008208ae820d0582115c8215b3821a0a827788a00000000000000000000000000000000000000000000000000000000000000000880000000000000000"
311 );
312 let expected = RequestPair {
313 request_id: 1111,
314 message: BlockHeaders(vec![Header {
315 parent_hash: B256::ZERO,
316 ommers_hash: B256::ZERO,
317 beneficiary: Address::ZERO,
318 state_root: B256::ZERO,
319 transactions_root: B256::ZERO,
320 receipts_root: B256::ZERO,
321 logs_bloom: Bloom::ZERO,
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: B256::ZERO,
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 block_access_list_hash: None,
337 slot_number: None,
338 }]),
339 };
340 let result = RequestPair::decode(&mut &data[..]);
341 assert_eq!(result.unwrap(), expected);
342 }
343
344 #[test]
346 fn encode_get_block_bodies() {
347 let expected = hex!(
348 "f847820457f842a000000000000000000000000000000000000000000000000000000000deadc0dea000000000000000000000000000000000000000000000000000000000feedbeef"
349 );
350 let mut data = vec![];
351 RequestPair {
352 request_id: 1111,
353 message: GetBlockBodies(vec![
354 b256!("00000000000000000000000000000000000000000000000000000000deadc0de"),
355 b256!("00000000000000000000000000000000000000000000000000000000feedbeef"),
356 ]),
357 }
358 .encode(&mut data);
359 assert_eq!(data, expected);
360 }
361
362 #[test]
364 fn decode_get_block_bodies() {
365 let data = hex!(
366 "f847820457f842a000000000000000000000000000000000000000000000000000000000deadc0dea000000000000000000000000000000000000000000000000000000000feedbeef"
367 );
368 let expected = RequestPair {
369 request_id: 1111,
370 message: GetBlockBodies(vec![
371 b256!("00000000000000000000000000000000000000000000000000000000deadc0de"),
372 b256!("00000000000000000000000000000000000000000000000000000000feedbeef"),
373 ]),
374 };
375 let result = RequestPair::decode(&mut &data[..]);
376 assert_eq!(result.unwrap(), expected);
377 }
378
379 #[test]
381 fn encode_block_bodies() {
382 let expected = hex!(
383 "f902dc820457f902d6f902d3f8d2f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afbf901fcf901f9a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008208ae820d0582115c8215b3821a0a827788a00000000000000000000000000000000000000000000000000000000000000000880000000000000000"
384 );
385 let mut data = vec![];
386 let request = RequestPair {
387 request_id: 1111,
388 message: BlockBodies(vec![
389 BlockBody {
390 transactions: vec![
391 TransactionSigned::new_unhashed(Transaction::Legacy(TxLegacy {
392 chain_id: Some(1),
393 nonce: 0x8u64,
394 gas_price: 0x4a817c808,
395 gas_limit: 0x2e248,
396 to: TxKind::Call(Address::repeat_byte(0x35)),
397 value: U256::from(0x200u64),
398 input: Default::default(),
399 }), Signature::new(
400 U256::from_str("0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12").unwrap(),
401 U256::from_str("0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10").unwrap(),
402 false,
403 ),
404 ),
405 TransactionSigned::new_unhashed(Transaction::Legacy(TxLegacy {
406 chain_id: Some(1),
407 nonce: 0x9u64,
408 gas_price: 0x4a817c809,
409 gas_limit: 0x33450,
410 to: TxKind::Call(Address::repeat_byte(0x35)),
411 value: U256::from(0x2d9u64),
412 input: Default::default(),
413 }), Signature::new(
414 U256::from_str("0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
415 U256::from_str("0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
416 false,
417 ),
418 ),
419 ],
420 ommers: vec![
421 Header {
422 parent_hash: B256::ZERO,
423 ommers_hash: B256::ZERO,
424 beneficiary: Address::ZERO,
425 state_root: B256::ZERO,
426 transactions_root: B256::ZERO,
427 receipts_root: B256::ZERO,
428 logs_bloom: Bloom::ZERO,
429 difficulty: U256::from(0x8aeu64),
430 number: 0xd05u64,
431 gas_limit: 0x115c,
432 gas_used: 0x15b3,
433 timestamp: 0x1a0au64,
434 extra_data: hex!("7788")[..].into(),
435 mix_hash: B256::ZERO,
436 nonce: 0x0000000000000000u64.into(),
437 base_fee_per_gas: None,
438 withdrawals_root: None,
439 blob_gas_used: None,
440 excess_blob_gas: None,
441 parent_beacon_block_root: None,
442 requests_hash: None,
443 block_access_list_hash: None,
444 slot_number: None,
445 },
446 ],
447 withdrawals: None,
448 }
449 ]),
450 };
451 request.encode(&mut data);
452 assert_eq!(data, expected);
453 }
454
455 #[test]
457 fn decode_block_bodies() {
458 let data = hex!(
459 "f902dc820457f902d6f902d3f8d2f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afbf901fcf901f9a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008208ae820d0582115c8215b3821a0a827788a00000000000000000000000000000000000000000000000000000000000000000880000000000000000"
460 );
461 let expected = RequestPair {
462 request_id: 1111,
463 message: BlockBodies(vec![
464 BlockBody {
465 transactions: vec![
466 TransactionSigned::new_unhashed(Transaction::Legacy(
467 TxLegacy {
468 chain_id: Some(1),
469 nonce: 0x8u64,
470 gas_price: 0x4a817c808,
471 gas_limit: 0x2e248,
472 to: TxKind::Call(Address::repeat_byte(0x35)),
473 value: U256::from(0x200u64),
474 input: Default::default(),
475 }),
476 Signature::new(
477 U256::from_str("0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12").unwrap(),
478 U256::from_str("0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10").unwrap(),
479 false,
480 ),
481 ),
482 TransactionSigned::new_unhashed(
483 Transaction::Legacy(TxLegacy {
484 chain_id: Some(1),
485 nonce: 0x9u64,
486 gas_price: 0x4a817c809,
487 gas_limit: 0x33450,
488 to: TxKind::Call(Address::repeat_byte(0x35)),
489 value: U256::from(0x2d9u64),
490 input: Default::default(),
491 }),
492 Signature::new(
493 U256::from_str("0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
494 U256::from_str("0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
495 false,
496 ),
497 ),
498 ],
499 ommers: vec![
500 Header {
501 parent_hash: B256::ZERO,
502 ommers_hash: B256::ZERO,
503 beneficiary: Address::ZERO,
504 state_root: B256::ZERO,
505 transactions_root: B256::ZERO,
506 receipts_root: B256::ZERO,
507 logs_bloom: Bloom::ZERO,
508 difficulty: U256::from(0x8aeu64),
509 number: 0xd05u64,
510 gas_limit: 0x115c,
511 gas_used: 0x15b3,
512 timestamp: 0x1a0au64,
513 extra_data: hex!("7788")[..].into(),
514 mix_hash: B256::ZERO,
515 nonce: 0x0000000000000000u64.into(),
516 base_fee_per_gas: None,
517 withdrawals_root: None,
518 blob_gas_used: None,
519 excess_blob_gas: None,
520 parent_beacon_block_root: None,
521 requests_hash: None,
522 block_access_list_hash: None,
523 slot_number: None,
524 },
525 ],
526 withdrawals: None,
527 }
528 ]),
529 };
530 let result = RequestPair::decode(&mut &data[..]).unwrap();
531 assert_eq!(result, expected);
532 }
533
534 #[test]
535 fn empty_block_bodies_rlp() {
536 let body = BlockBodies::default();
537 let mut buf = Vec::new();
538 body.encode(&mut buf);
539 let decoded = BlockBodies::<BlockBody>::decode(&mut buf.as_slice()).unwrap();
540 assert_eq!(body, decoded);
541 }
542}