1use crate::{error::DecodePacketError, MAX_PACKET_SIZE, MIN_PACKET_SIZE};
4use alloy_primitives::{
5 bytes::{Buf, BufMut, Bytes, BytesMut},
6 keccak256, B256,
7};
8use alloy_rlp::{
9 Decodable, Encodable, Error as RlpError, Header, RlpDecodable, RlpEncodable,
10 RlpEncodableWrapper,
11};
12use enr::Enr;
13use reth_ethereum_forks::{EnrForkIdEntry, ForkId};
14use reth_network_peers::{pk2id, NodeRecord, PeerId};
15use secp256k1::{
16 ecdsa::{RecoverableSignature, RecoveryId},
17 SecretKey, SECP256K1,
18};
19use std::net::{IpAddr, Ipv4Addr};
20
21#[derive(Debug)]
27#[repr(u8)]
28pub enum MessageId {
29 Ping = 1,
31 Pong = 2,
33 FindNode = 3,
35 Neighbours = 4,
37 EnrRequest = 5,
39 EnrResponse = 6,
41}
42
43impl MessageId {
44 const fn from_u8(msg: u8) -> Result<Self, u8> {
46 Ok(match msg {
47 1 => Self::Ping,
48 2 => Self::Pong,
49 3 => Self::FindNode,
50 4 => Self::Neighbours,
51 5 => Self::EnrRequest,
52 6 => Self::EnrResponse,
53 _ => return Err(msg),
54 })
55 }
56}
57
58#[derive(Debug, Eq, PartialEq)]
60pub enum Message {
61 Ping(Ping),
63 Pong(Pong),
65 FindNode(FindNode),
67 Neighbours(Neighbours),
69 EnrRequest(EnrRequest),
71 EnrResponse(EnrResponse),
73}
74
75impl Message {
78 pub const fn msg_type(&self) -> MessageId {
80 match self {
81 Self::Ping(_) => MessageId::Ping,
82 Self::Pong(_) => MessageId::Pong,
83 Self::FindNode(_) => MessageId::FindNode,
84 Self::Neighbours(_) => MessageId::Neighbours,
85 Self::EnrRequest(_) => MessageId::EnrRequest,
86 Self::EnrResponse(_) => MessageId::EnrResponse,
87 }
88 }
89
90 pub fn encode(&self, secret_key: &SecretKey) -> (Bytes, B256) {
95 let mut datagram = BytesMut::with_capacity(MAX_PACKET_SIZE);
97
98 let mut sig_bytes = datagram.split_off(B256::len_bytes());
101 let mut payload = sig_bytes.split_off(secp256k1::constants::COMPACT_SIGNATURE_SIZE + 1);
102
103 payload.put_u8(self.msg_type() as u8);
105
106 match self {
108 Self::Ping(message) => message.encode(&mut payload),
109 Self::Pong(message) => message.encode(&mut payload),
110 Self::FindNode(message) => message.encode(&mut payload),
111 Self::Neighbours(message) => message.encode(&mut payload),
112 Self::EnrRequest(message) => message.encode(&mut payload),
113 Self::EnrResponse(message) => message.encode(&mut payload),
114 }
115
116 let signature: RecoverableSignature = SECP256K1.sign_ecdsa_recoverable(
118 &secp256k1::Message::from_digest(keccak256(&payload).0),
119 secret_key,
120 );
121
122 let (rec, sig) = signature.serialize_compact();
124 sig_bytes.extend_from_slice(&sig);
125 sig_bytes.put_u8(i32::from(rec) as u8);
126 sig_bytes.unsplit(payload);
127
128 let hash = keccak256(&sig_bytes);
130 datagram.extend_from_slice(hash.as_slice());
131
132 datagram.unsplit(sig_bytes);
134
135 (datagram.freeze(), hash)
137 }
138
139 pub fn decode(packet: &[u8]) -> Result<Packet, DecodePacketError> {
143 if packet.len() < MIN_PACKET_SIZE {
144 return Err(DecodePacketError::PacketTooShort)
145 }
146
147 let header_hash = keccak256(&packet[32..]);
153 let data_hash = B256::from_slice(&packet[..32]);
154 if data_hash != header_hash {
155 return Err(DecodePacketError::HashMismatch)
156 }
157
158 let signature = &packet[32..96];
159 let recovery_id = RecoveryId::try_from(packet[96] as i32)?;
160 let recoverable_sig = RecoverableSignature::from_compact(signature, recovery_id)?;
161
162 let msg = secp256k1::Message::from_digest(keccak256(&packet[97..]).0);
164
165 let pk = SECP256K1.recover_ecdsa(&msg, &recoverable_sig)?;
166 let node_id = pk2id(&pk);
167
168 let msg_type = packet[97];
169 let payload = &mut &packet[98..];
170
171 let msg = match MessageId::from_u8(msg_type).map_err(DecodePacketError::UnknownMessage)? {
172 MessageId::Ping => Self::Ping(Ping::decode(payload)?),
173 MessageId::Pong => Self::Pong(Pong::decode(payload)?),
174 MessageId::FindNode => Self::FindNode(FindNode::decode(payload)?),
175 MessageId::Neighbours => Self::Neighbours(Neighbours::decode(payload)?),
176 MessageId::EnrRequest => Self::EnrRequest(EnrRequest::decode(payload)?),
177 MessageId::EnrResponse => Self::EnrResponse(EnrResponse::decode(payload)?),
178 };
179
180 Ok(Packet { msg, node_id, hash: header_hash })
181 }
182}
183
184#[derive(Debug)]
188pub struct Packet {
189 pub msg: Message,
191 pub node_id: PeerId,
193 pub hash: B256,
195}
196
197#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, RlpEncodableWrapper)]
199struct PingNodeEndpoint(NodeEndpoint);
200
201impl alloy_rlp::Decodable for PingNodeEndpoint {
202 #[inline]
203 fn decode(b: &mut &[u8]) -> alloy_rlp::Result<Self> {
204 let alloy_rlp::Header { list, payload_length } = alloy_rlp::Header::decode(b)?;
205 if !list {
206 return Err(alloy_rlp::Error::UnexpectedString);
207 }
208 let started_len = b.len();
209 if started_len < payload_length {
210 return Err(alloy_rlp::Error::InputTooShort);
211 }
212
213 let address =
220 if *b.first().ok_or(alloy_rlp::Error::InputTooShort)? == alloy_rlp::EMPTY_STRING_CODE {
221 let addr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
222 b.advance(1);
223 addr
224 } else {
225 alloy_rlp::Decodable::decode(b)?
226 };
227
228 let this = NodeEndpoint {
229 address,
230 udp_port: alloy_rlp::Decodable::decode(b)?,
231 tcp_port: alloy_rlp::Decodable::decode(b)?,
232 };
233 let consumed = started_len - b.len();
234 if consumed != payload_length {
235 return Err(alloy_rlp::Error::ListLengthMismatch {
236 expected: payload_length,
237 got: consumed,
238 });
239 }
240 Ok(Self(this))
241 }
242}
243
244#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, RlpEncodable, RlpDecodable)]
246pub struct NodeEndpoint {
247 pub address: IpAddr,
249 pub udp_port: u16,
251 pub tcp_port: u16,
253}
254
255impl From<NodeRecord> for NodeEndpoint {
256 fn from(NodeRecord { address, tcp_port, udp_port, .. }: NodeRecord) -> Self {
257 Self { address, tcp_port, udp_port }
258 }
259}
260
261impl NodeEndpoint {
262 pub const fn from_udp_address(udp_address: &std::net::SocketAddr, tcp_port: u16) -> Self {
264 Self { address: udp_address.ip(), udp_port: udp_address.port(), tcp_port }
265 }
266}
267
268#[derive(Clone, Copy, Debug, Eq, PartialEq, RlpEncodable)]
270pub struct FindNode {
271 pub id: PeerId,
273 pub expire: u64,
275}
276
277impl Decodable for FindNode {
278 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
282 let b = &mut &**buf;
283 let rlp_head = Header::decode(b)?;
284 if !rlp_head.list {
285 return Err(RlpError::UnexpectedString)
286 }
287 let started_len = b.len();
288
289 let this = Self { id: Decodable::decode(b)?, expire: Decodable::decode(b)? };
290
291 let consumed = started_len - b.len();
295 if consumed > rlp_head.payload_length {
296 return Err(RlpError::ListLengthMismatch {
297 expected: rlp_head.payload_length,
298 got: consumed,
299 })
300 }
301
302 let rem = rlp_head.payload_length - consumed;
303 b.advance(rem);
304 *buf = *b;
305
306 Ok(this)
307 }
308}
309
310#[derive(Clone, Debug, Eq, PartialEq, RlpEncodable)]
312pub struct Neighbours {
313 pub nodes: Vec<NodeRecord>,
315 pub expire: u64,
317}
318
319impl Decodable for Neighbours {
320 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
324 let b = &mut &**buf;
325 let rlp_head = Header::decode(b)?;
326 if !rlp_head.list {
327 return Err(RlpError::UnexpectedString)
328 }
329 let started_len = b.len();
330
331 let this = Self { nodes: Decodable::decode(b)?, expire: Decodable::decode(b)? };
332
333 let consumed = started_len - b.len();
337 if consumed > rlp_head.payload_length {
338 return Err(RlpError::ListLengthMismatch {
339 expected: rlp_head.payload_length,
340 got: consumed,
341 })
342 }
343
344 let rem = rlp_head.payload_length - consumed;
345 b.advance(rem);
346 *buf = *b;
347
348 Ok(this)
349 }
350}
351
352#[derive(Clone, Copy, Debug, Eq, PartialEq, RlpEncodable)]
356pub struct EnrRequest {
357 pub expire: u64,
360}
361
362impl Decodable for EnrRequest {
363 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
367 let b = &mut &**buf;
368 let rlp_head = Header::decode(b)?;
369 if !rlp_head.list {
370 return Err(RlpError::UnexpectedString)
371 }
372 let started_len = b.len();
373
374 let this = Self { expire: Decodable::decode(b)? };
375
376 let consumed = started_len - b.len();
380 if consumed > rlp_head.payload_length {
381 return Err(RlpError::ListLengthMismatch {
382 expected: rlp_head.payload_length,
383 got: consumed,
384 })
385 }
386
387 let rem = rlp_head.payload_length - consumed;
388 b.advance(rem);
389 *buf = *b;
390
391 Ok(this)
392 }
393}
394
395#[derive(Clone, Debug, Eq, PartialEq, RlpEncodable, RlpDecodable)]
400pub struct EnrResponse {
401 pub request_hash: B256,
403 pub enr: Enr<SecretKey>,
405}
406
407impl EnrResponse {
410 pub fn eth_fork_id(&self) -> Option<ForkId> {
414 let mut maybe_fork_id = self.enr.get_raw_rlp(b"eth")?;
415 EnrForkIdEntry::decode(&mut maybe_fork_id).ok().map(Into::into)
416 }
417}
418
419#[derive(Debug, Clone, Eq, PartialEq)]
423pub struct Ping {
424 pub from: NodeEndpoint,
426 pub to: NodeEndpoint,
428 pub expire: u64,
430 pub enr_sq: Option<u64>,
432}
433
434impl Encodable for Ping {
435 fn encode(&self, out: &mut dyn BufMut) {
436 #[derive(RlpEncodable)]
437 struct V4PingMessage<'a> {
438 version: u32,
439 from: &'a NodeEndpoint,
440 to: &'a NodeEndpoint,
441 expire: u64,
442 }
443
444 #[derive(RlpEncodable)]
445 struct V4PingMessageEIP868<'a> {
446 version: u32,
447 from: &'a NodeEndpoint,
448 to: &'a NodeEndpoint,
449 expire: u64,
450 enr_seq: u64,
451 }
452 if let Some(enr_seq) = self.enr_sq {
453 V4PingMessageEIP868 {
454 version: 4, from: &self.from,
456 to: &self.to,
457 expire: self.expire,
458 enr_seq,
459 }
460 .encode(out);
461 } else {
462 V4PingMessage {
463 version: 4, from: &self.from,
465 to: &self.to,
466 expire: self.expire,
467 }
468 .encode(out);
469 }
470 }
471}
472
473impl Decodable for Ping {
474 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
475 let b = &mut &**buf;
476 let rlp_head = Header::decode(b)?;
477 if !rlp_head.list {
478 return Err(RlpError::UnexpectedString)
479 }
480 let started_len = b.len();
481
482 let _version = u32::decode(b)?;
485
486 let from = PingNodeEndpoint::decode(b)?.0;
488
489 let mut this =
490 Self { from, to: Decodable::decode(b)?, expire: Decodable::decode(b)?, enr_sq: None };
491
492 if b.has_remaining() {
494 this.enr_sq = Some(Decodable::decode(b)?);
495 }
496
497 let consumed = started_len - b.len();
498 if consumed > rlp_head.payload_length {
499 return Err(RlpError::ListLengthMismatch {
500 expected: rlp_head.payload_length,
501 got: consumed,
502 })
503 }
504 let rem = rlp_head.payload_length - consumed;
505 b.advance(rem);
506 *buf = *b;
507 Ok(this)
508 }
509}
510
511#[derive(Clone, Debug, Eq, PartialEq)]
515pub struct Pong {
516 pub to: NodeEndpoint,
518 pub echo: B256,
520 pub expire: u64,
522 pub enr_sq: Option<u64>,
524}
525
526impl Encodable for Pong {
527 fn encode(&self, out: &mut dyn BufMut) {
528 #[derive(RlpEncodable)]
529 struct PongMessageEIP868<'a> {
530 to: &'a NodeEndpoint,
531 echo: &'a B256,
532 expire: u64,
533 enr_seq: u64,
534 }
535
536 #[derive(RlpEncodable)]
537 struct PongMessage<'a> {
538 to: &'a NodeEndpoint,
539 echo: &'a B256,
540 expire: u64,
541 }
542
543 if let Some(enr_seq) = self.enr_sq {
544 PongMessageEIP868 { to: &self.to, echo: &self.echo, expire: self.expire, enr_seq }
545 .encode(out);
546 } else {
547 PongMessage { to: &self.to, echo: &self.echo, expire: self.expire }.encode(out);
548 }
549 }
550}
551
552impl Decodable for Pong {
553 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
554 let b = &mut &**buf;
555 let rlp_head = Header::decode(b)?;
556 if !rlp_head.list {
557 return Err(RlpError::UnexpectedString)
558 }
559 let started_len = b.len();
560 let mut this = Self {
561 to: Decodable::decode(b)?,
562 echo: Decodable::decode(b)?,
563 expire: Decodable::decode(b)?,
564 enr_sq: None,
565 };
566
567 if b.has_remaining() {
569 this.enr_sq = Some(Decodable::decode(b)?);
570 }
571
572 let consumed = started_len - b.len();
573 if consumed > rlp_head.payload_length {
574 return Err(RlpError::ListLengthMismatch {
575 expected: rlp_head.payload_length,
576 got: consumed,
577 })
578 }
579 let rem = rlp_head.payload_length - consumed;
580 b.advance(rem);
581 *buf = *b;
582
583 Ok(this)
584 }
585}
586
587#[cfg(test)]
588mod tests {
589 use super::*;
590 use crate::{
591 test_utils::{rng_endpoint, rng_ipv4_record, rng_ipv6_record, rng_message},
592 DEFAULT_DISCOVERY_PORT, SAFE_MAX_DATAGRAM_NEIGHBOUR_RECORDS,
593 };
594 use alloy_primitives::hex;
595 use assert_matches::assert_matches;
596 use enr::EnrPublicKey;
597 use rand::{thread_rng, Rng, RngCore};
598 use reth_ethereum_forks::ForkHash;
599
600 #[test]
601 fn test_endpoint_ipv_v4() {
602 let mut rng = thread_rng();
603 for _ in 0..100 {
604 let mut ip = [0u8; 4];
605 rng.fill_bytes(&mut ip);
606 let msg = NodeEndpoint {
607 address: IpAddr::V4(ip.into()),
608 tcp_port: rng.gen(),
609 udp_port: rng.gen(),
610 };
611
612 let decoded = NodeEndpoint::decode(&mut alloy_rlp::encode(msg).as_slice()).unwrap();
613 assert_eq!(msg, decoded);
614 }
615 }
616
617 #[test]
618 fn test_endpoint_ipv_64() {
619 let mut rng = thread_rng();
620 for _ in 0..100 {
621 let mut ip = [0u8; 16];
622 rng.fill_bytes(&mut ip);
623 let msg = NodeEndpoint {
624 address: IpAddr::V6(ip.into()),
625 tcp_port: rng.gen(),
626 udp_port: rng.gen(),
627 };
628
629 let decoded = NodeEndpoint::decode(&mut alloy_rlp::encode(msg).as_slice()).unwrap();
630 assert_eq!(msg, decoded);
631 }
632 }
633
634 #[test]
635 fn test_ping_message() {
636 let mut rng = thread_rng();
637 for _ in 0..100 {
638 let mut ip = [0u8; 16];
639 rng.fill_bytes(&mut ip);
640 let msg = Ping {
641 from: rng_endpoint(&mut rng),
642 to: rng_endpoint(&mut rng),
643 expire: 0,
644 enr_sq: None,
645 };
646
647 let decoded = Ping::decode(&mut alloy_rlp::encode(&msg).as_slice()).unwrap();
648 assert_eq!(msg, decoded);
649 }
650 }
651
652 #[test]
653 fn test_ping_message_with_enr() {
654 let mut rng = thread_rng();
655 for _ in 0..100 {
656 let mut ip = [0u8; 16];
657 rng.fill_bytes(&mut ip);
658 let msg = Ping {
659 from: rng_endpoint(&mut rng),
660 to: rng_endpoint(&mut rng),
661 expire: 0,
662 enr_sq: Some(rng.gen()),
663 };
664
665 let decoded = Ping::decode(&mut alloy_rlp::encode(&msg).as_slice()).unwrap();
666 assert_eq!(msg, decoded);
667 }
668 }
669
670 #[test]
671 fn test_pong_message() {
672 let mut rng = thread_rng();
673 for _ in 0..100 {
674 let mut ip = [0u8; 16];
675 rng.fill_bytes(&mut ip);
676 let msg = Pong {
677 to: rng_endpoint(&mut rng),
678 echo: rng.gen(),
679 expire: rng.gen(),
680 enr_sq: None,
681 };
682
683 let decoded = Pong::decode(&mut alloy_rlp::encode(&msg).as_slice()).unwrap();
684 assert_eq!(msg, decoded);
685 }
686 }
687
688 #[test]
689 fn test_pong_message_with_enr() {
690 let mut rng = thread_rng();
691 for _ in 0..100 {
692 let mut ip = [0u8; 16];
693 rng.fill_bytes(&mut ip);
694 let msg = Pong {
695 to: rng_endpoint(&mut rng),
696 echo: rng.gen(),
697 expire: rng.gen(),
698 enr_sq: Some(rng.gen()),
699 };
700
701 let decoded = Pong::decode(&mut alloy_rlp::encode(&msg).as_slice()).unwrap();
702 assert_eq!(msg, decoded);
703 }
704 }
705
706 #[test]
707 fn test_hash_mismatch() {
708 let mut rng = thread_rng();
709 let msg = rng_message(&mut rng);
710 let (secret_key, _) = SECP256K1.generate_keypair(&mut rng);
711 let (buf, _) = msg.encode(&secret_key);
712
713 let mut buf_vec = buf.to_vec();
714 buf_vec.push(0);
715 match Message::decode(buf_vec.as_slice()).unwrap_err() {
716 DecodePacketError::HashMismatch => {}
717 err => {
718 unreachable!("unexpected err {}", err)
719 }
720 }
721 }
722
723 #[test]
724 fn neighbours_max_ipv4() {
725 let mut rng = thread_rng();
726 let msg = Message::Neighbours(Neighbours {
727 nodes: std::iter::repeat_with(|| rng_ipv4_record(&mut rng)).take(16).collect(),
728 expire: rng.gen(),
729 });
730 let (secret_key, _) = SECP256K1.generate_keypair(&mut rng);
731
732 let (encoded, _) = msg.encode(&secret_key);
733 assert!(encoded.len() > MAX_PACKET_SIZE, "{} {msg:?}", encoded.len());
735 }
736
737 #[test]
738 fn neighbours_max_nodes() {
739 let mut rng = thread_rng();
740 for _ in 0..1000 {
741 let msg = Message::Neighbours(Neighbours {
742 nodes: std::iter::repeat_with(|| rng_ipv6_record(&mut rng))
743 .take(SAFE_MAX_DATAGRAM_NEIGHBOUR_RECORDS)
744 .collect(),
745 expire: rng.gen(),
746 });
747 let (secret_key, _) = SECP256K1.generate_keypair(&mut rng);
748
749 let (encoded, _) = msg.encode(&secret_key);
750 assert!(encoded.len() <= MAX_PACKET_SIZE, "{} {msg:?}", encoded.len());
751
752 let mut neighbours = Neighbours {
753 nodes: std::iter::repeat_with(|| rng_ipv6_record(&mut rng))
754 .take(SAFE_MAX_DATAGRAM_NEIGHBOUR_RECORDS - 1)
755 .collect(),
756 expire: rng.gen(),
757 };
758 neighbours.nodes.push(rng_ipv4_record(&mut rng));
759 let msg = Message::Neighbours(neighbours);
760 let (encoded, _) = msg.encode(&secret_key);
761 assert!(encoded.len() <= MAX_PACKET_SIZE, "{} {msg:?}", encoded.len());
762 }
763 }
764
765 #[test]
766 fn test_encode_decode_message() {
767 let mut rng = thread_rng();
768 for _ in 0..100 {
769 let msg = rng_message(&mut rng);
770 let (secret_key, pk) = SECP256K1.generate_keypair(&mut rng);
771 let sender_id = pk2id(&pk);
772
773 let (buf, _) = msg.encode(&secret_key);
774
775 let packet = Message::decode(buf.as_ref()).unwrap();
776
777 assert_eq!(msg, packet.msg);
778 assert_eq!(sender_id, packet.node_id);
779 }
780 }
781
782 #[test]
783 fn decode_pong_packet() {
784 let packet = "2ad84c37327a06c2522cf7bc039621da89f68907441b755935bb308dc4cd17d6fe550e90329ad6a516ca7db18e08900067928a0dfa3b5c75d55a42c984497373698d98616662c048983ea85895ea2da765eabeb15525478384e106337bfd8ed50002f3c9843ed8cae682fd1c80a008ad4dead0922211df47593e7d837b2b23d13954285871ca23250ea594993ded84635690e5829670";
785 let data = hex::decode(packet).unwrap();
786 Message::decode(&data).unwrap();
787 }
788 #[test]
789 fn decode_ping_packet() {
790 let packet = "05ae5bf922cf2a93f97632a4ab0943dc252a0dab0c42d86dd62e5d91e1a0966e9b628fbf4763fdfbb928540460b797e6be2e7058a82f6083f6d2e7391bb021741459976d4152aa16bbee0c3609dcfac6668db1ef78b7ee9f8b4ced10dd5ae2900101df04cb8403d12d4f82765f82765fc9843ed8cae6828aa6808463569916829670";
791 let data = hex::decode(packet).unwrap();
792 Message::decode(&data).unwrap();
793 }
794
795 #[test]
796 fn encode_decode_enr_msg() {
797 use alloy_rlp::Decodable;
798 use enr::secp256k1::SecretKey;
799 use std::net::Ipv4Addr;
800
801 let mut rng = rand::rngs::OsRng;
802 let key = SecretKey::new(&mut rng);
803 let ip = Ipv4Addr::new(127, 0, 0, 1);
804 let tcp = 3000;
805
806 let fork_id: ForkId = ForkId { hash: ForkHash([220, 233, 108, 45]), next: 0u64 };
807
808 let enr = {
809 let mut builder = Enr::builder();
810 builder.ip(ip.into());
811 builder.tcp4(tcp);
812 let mut buf = Vec::new();
813 let forkentry = EnrForkIdEntry { fork_id };
814 forkentry.encode(&mut buf);
815 builder.add_value_rlp("eth", buf.into());
816 builder.build(&key).unwrap()
817 };
818
819 let enr_response = EnrResponse { request_hash: rng.gen(), enr };
820
821 let mut buf = Vec::new();
822 enr_response.encode(&mut buf);
823
824 let decoded = EnrResponse::decode(&mut &buf[..]).unwrap();
825
826 let fork_id_decoded = decoded.eth_fork_id().unwrap();
827 assert_eq!(fork_id, fork_id_decoded);
828 }
829
830 #[test]
834 fn encode_known_rlp_enr() {
835 use alloy_rlp::Decodable;
836 use enr::{secp256k1::SecretKey, EnrPublicKey};
837 use std::net::Ipv4Addr;
838
839 let valid_record = hex!("f884b8407098ad865b00a582051940cb9cf36836572411a47278783077011599ed5cd16b76f2635f4e234738f30813a89eb9137e3e3df5266e3a1f11df72ecf1145ccb9c01826964827634826970847f00000189736563703235366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd31388375647082765f");
840 let signature = hex!("7098ad865b00a582051940cb9cf36836572411a47278783077011599ed5cd16b76f2635f4e234738f30813a89eb9137e3e3df5266e3a1f11df72ecf1145ccb9c");
841 let expected_pubkey =
842 hex!("03ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd3138");
843
844 let enr = Enr::<SecretKey>::decode(&mut &valid_record[..]).unwrap();
845 let pubkey = enr.public_key().encode();
846
847 assert_eq!(enr.ip4(), Some(Ipv4Addr::new(127, 0, 0, 1)));
848 assert_eq!(enr.id(), Some(String::from("v4")));
849 assert_eq!(enr.udp4(), Some(DEFAULT_DISCOVERY_PORT));
850 assert_eq!(enr.tcp4(), None);
851 assert_eq!(enr.signature(), &signature[..]);
852 assert_eq!(pubkey.to_vec(), expected_pubkey);
853 assert!(enr.verify());
854
855 assert_eq!(&alloy_rlp::encode(&enr)[..], &valid_record[..]);
856
857 assert_eq!(enr.length(), valid_record.len());
859 }
860
861 #[test]
864 fn decode_enr_rlp() {
865 use enr::secp256k1::SecretKey;
866 use std::net::Ipv4Addr;
867
868 let valid_record = hex!("f884b8407098ad865b00a582051940cb9cf36836572411a47278783077011599ed5cd16b76f2635f4e234738f30813a89eb9137e3e3df5266e3a1f11df72ecf1145ccb9c01826964827634826970847f00000189736563703235366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd31388375647082765f");
869 let signature = hex!("7098ad865b00a582051940cb9cf36836572411a47278783077011599ed5cd16b76f2635f4e234738f30813a89eb9137e3e3df5266e3a1f11df72ecf1145ccb9c");
870 let expected_pubkey =
871 hex!("03ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd3138");
872
873 let mut valid_record_buf = valid_record.as_slice();
874 let enr = Enr::<SecretKey>::decode(&mut valid_record_buf).unwrap();
875 let pubkey = enr.public_key().encode();
876
877 assert!(valid_record_buf.is_empty());
879
880 assert_eq!(enr.ip4(), Some(Ipv4Addr::new(127, 0, 0, 1)));
881 assert_eq!(enr.id(), Some(String::from("v4")));
882 assert_eq!(enr.udp4(), Some(DEFAULT_DISCOVERY_PORT));
883 assert_eq!(enr.tcp4(), None);
884 assert_eq!(enr.signature(), &signature[..]);
885 assert_eq!(pubkey.to_vec(), expected_pubkey);
886 assert!(enr.verify());
887 }
888
889 #[test]
891 fn decode_failing_packet() {
892 let packet = hex!("2467ab56952aedf4cfb8bb7830ddc8922d0f992185229919dad9de3841fe95d9b3a7b52459398235f6d3805644666d908b45edb3670414ed97f357afba51f71f7d35c1f45878ba732c3868b04ca42ff0ed347c99efcf3a5768afed68eb21ef960001db04c3808080c9840a480e8f82765f808466a9a06386019106833efe");
893
894 let _message = Message::decode(&packet[..]).unwrap();
895 }
896
897 #[test]
899 fn decode_node() {
900 let packet = hex!("cb840000000082115c82115d");
901 let _message = NodeEndpoint::decode(&mut &packet[..]).unwrap();
902 }
903
904 #[test]
907 fn encode_decode_enr_rlp() {
908 use enr::{secp256k1::SecretKey, EnrPublicKey};
909 use std::net::Ipv4Addr;
910
911 let key = SecretKey::new(&mut rand::rngs::OsRng);
912 let ip = Ipv4Addr::new(127, 0, 0, 1);
913 let tcp = 3000;
914
915 let enr = {
916 let mut builder = Enr::builder();
917 builder.ip(ip.into());
918 builder.tcp4(tcp);
919 builder.build(&key).unwrap()
920 };
921
922 let mut encoded_bytes = &alloy_rlp::encode(&enr)[..];
923 let decoded_enr = Enr::<SecretKey>::decode(&mut encoded_bytes).unwrap();
924
925 assert!(encoded_bytes.is_empty());
927
928 assert_eq!(decoded_enr, enr);
929 assert_eq!(decoded_enr.id(), Some("v4".into()));
930 assert_eq!(decoded_enr.ip4(), Some(ip));
931 assert_eq!(decoded_enr.tcp4(), Some(tcp));
932 assert_eq!(
933 decoded_enr.public_key().encode(),
934 key.public_key(secp256k1::SECP256K1).encode()
935 );
936 assert!(decoded_enr.verify());
937 }
938
939 mod eip8 {
940 use super::*;
941
942 fn junk_enr_request() -> Vec<u8> {
943 let mut buf = Vec::new();
944 let expire: u64 = 123456;
946
947 let junk: u64 = 112233;
949
950 let payload_length = expire.length() + junk.length();
952 alloy_rlp::Header { list: true, payload_length }.encode(&mut buf);
953
954 expire.encode(&mut buf);
956 junk.encode(&mut buf);
957
958 buf
959 }
960
961 #[test]
963 fn eip8_decode_enr_request() {
964 let enr_request_with_junk = junk_enr_request();
965
966 let mut buf = enr_request_with_junk.as_slice();
967 let decoded = EnrRequest::decode(&mut buf).unwrap();
968 assert_eq!(decoded.expire, 123456);
969 }
970
971 #[test]
975 fn eip8_decode_findnode() {
976 let findnode_with_junk = hex!("c7c44041b9f7c7e41934417ebac9a8e1a4c6298f74553f2fcfdcae6ed6fe53163eb3d2b52e39fe91831b8a927bf4fc222c3902202027e5e9eb812195f95d20061ef5cd31d502e47ecb61183f74a504fe04c51e73df81f25c4d506b26db4517490103f84eb840ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd31387574077f301b421bc84df7266c44e9e6d569fc56be00812904767bf5ccd1fc7f8443b9a35582999983999999280dc62cc8255c73471e0a61da0c89acdc0e035e260add7fc0c04ad9ebf3919644c91cb247affc82b69bd2ca235c71eab8e49737c937a2c396");
977
978 let buf = findnode_with_junk.as_slice();
979 let decoded = Message::decode(buf).unwrap();
980
981 let expected_id = hex!("ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd31387574077f301b421bc84df7266c44e9e6d569fc56be00812904767bf5ccd1fc7f");
982 assert_matches!(decoded.msg, Message::FindNode(FindNode { id, expire: 1136239445 }) if id == expected_id);
983 }
984
985 #[test]
989 fn eip8_decode_neighbours() {
990 let neighbours_with_junk = hex!("c679fc8fe0b8b12f06577f2e802d34f6fa257e6137a995f6f4cbfc9ee50ed3710faf6e66f932c4c8d81d64343f429651328758b47d3dbc02c4042f0fff6946a50f4a49037a72bb550f3a7872363a83e1b9ee6469856c24eb4ef80b7535bcf99c0004f9015bf90150f84d846321163782115c82115db8403155e1427f85f10a5c9a7755877748041af1bcd8d474ec065eb33df57a97babf54bfd2103575fa829115d224c523596b401065a97f74010610fce76382c0bf32f84984010203040101b840312c55512422cf9b8a4097e9a6ad79402e87a15ae909a4bfefa22398f03d20951933beea1e4dfa6f968212385e829f04c2d314fc2d4e255e0d3bc08792b069dbf8599020010db83c4d001500000000abcdef12820d05820d05b84038643200b172dcfef857492156971f0e6aa2c538d8b74010f8e140811d53b98c765dd2d96126051913f44582e8c199ad7c6d6819e9a56483f637feaac9448aacf8599020010db885a308d313198a2e037073488203e78203e8b8408dcab8618c3253b558d459da53bd8fa68935a719aff8b811197101a4b2b47dd2d47295286fc00cc081bb542d760717d1bdd6bec2c37cd72eca367d6dd3b9df738443b9a355010203b525a138aa34383fec3d2719a0");
991
992 let buf = neighbours_with_junk.as_slice();
993 let decoded = Message::decode(buf).unwrap();
994
995 let _ = NodeRecord {
996 address: "99.33.22.55".parse().unwrap(),
997 tcp_port: 4444,
998 udp_port: 4445,
999 id: hex!("3155e1427f85f10a5c9a7755877748041af1bcd8d474ec065eb33df57a97babf54bfd2103575fa829115d224c523596b401065a97f74010610fce76382c0bf32").into(),
1000 }.length();
1001
1002 let expected_nodes: Vec<NodeRecord> = vec![
1003 NodeRecord {
1004 address: "99.33.22.55".parse().unwrap(),
1005 udp_port: 4444,
1006 tcp_port: 4445,
1007 id: hex!("3155e1427f85f10a5c9a7755877748041af1bcd8d474ec065eb33df57a97babf54bfd2103575fa829115d224c523596b401065a97f74010610fce76382c0bf32").into(),
1008 },
1009 NodeRecord {
1010 address: "1.2.3.4".parse().unwrap(),
1011 udp_port: 1,
1012 tcp_port: 1,
1013 id: hex!("312c55512422cf9b8a4097e9a6ad79402e87a15ae909a4bfefa22398f03d20951933beea1e4dfa6f968212385e829f04c2d314fc2d4e255e0d3bc08792b069db").into(),
1014 },
1015 NodeRecord {
1016 address: "2001:db8:3c4d:15::abcd:ef12".parse().unwrap(),
1017 udp_port: 3333,
1018 tcp_port: 3333,
1019 id: hex!("38643200b172dcfef857492156971f0e6aa2c538d8b74010f8e140811d53b98c765dd2d96126051913f44582e8c199ad7c6d6819e9a56483f637feaac9448aac").into(),
1020 },
1021 NodeRecord {
1022 address: "2001:db8:85a3:8d3:1319:8a2e:370:7348".parse().unwrap(),
1023 udp_port: 999,
1024 tcp_port: 1000,
1025 id: hex!("8dcab8618c3253b558d459da53bd8fa68935a719aff8b811197101a4b2b47dd2d47295286fc00cc081bb542d760717d1bdd6bec2c37cd72eca367d6dd3b9df73").into(),
1026 },
1027 ];
1028 assert_matches!(decoded.msg, Message::Neighbours(Neighbours { nodes, expire: 1136239445 }) if nodes == expected_nodes);
1029 }
1030 }
1031}