-
Notifications
You must be signed in to change notification settings - Fork 132
feat(l1): detect and update stale enr on ping pong #5507
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
20a9ad1
ee151a0
cd8296b
fabee25
d3cab37
3df7ae3
bed7abc
aa4130b
14a776c
756e6f2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -163,7 +163,7 @@ impl DiscoveryServer { | |||||||||||||||||||||||||||||||||||||||||||||||||
| sender_public_key, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| let _ = self.handle_ping(hash, node).await.inspect_err(|e| { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let _ = self.handle_ping(ping_message, hash, sender_public_key, node).await.inspect_err(|e| { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| error!(sent = "Ping", to = %format!("{sender_public_key:#x}"), err = ?e, "Error handling message"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -249,9 +249,12 @@ impl DiscoveryServer { | |||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| async fn lookup(&mut self) -> Result<(), DiscoveryServerError> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if let Some(contact) = self.peer_table.get_contact_for_lookup().await? { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if self.udp_socket.send_to(&self.find_node_message, &contact.node.udp_addr()).await.inspect_err( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| |e| error!(sending = "FindNode", addr = ?&contact.node.udp_addr(), err=?e, "Error sending message"), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ).is_err() { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if let Err(e) = self | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .udp_socket | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .send_to(&self.find_node_message, &contact.node.udp_addr()) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .await | ||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| error!(sending = "FindNode", addr = ?&contact.node.udp_addr(), err=?e, "Error sending message"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| self.peer_table | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .set_disposable(&contact.node.node_id()) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .await?; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -281,52 +284,12 @@ impl DiscoveryServer { | |||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| async fn enr_lookup(&mut self) -> Result<(), DiscoveryServerError> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if let Some(contact) = self.peer_table.get_contact_for_enr_lookup().await? { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let expiration: u64 = get_msg_expiration_from_seconds(EXPIRATION_SECONDS); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let enr_request = Message::ENRRequest(ENRRequestMessage { expiration }); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| let mut buf = Vec::new(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| enr_request.encode_with_header(&mut buf, &self.signer); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let enr_request_hash: [u8; 32] = buf[..32] | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .try_into() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .expect("first 32 bytes are the message hash"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if self.udp_socket.send_to(&buf, contact.node.udp_addr()) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .await | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .inspect_err( |e| error!(sending = "ENRRequest", addr = ?&contact.node.udp_addr(), to = %format!("{:#x}", contact.node.public_key), err=?e, "Error sending message"),) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .is_err() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| self.peer_table | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .set_disposable(&contact.node.node_id()) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .await?; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| METRICS.record_new_discarded_node().await; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| self.peer_table | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .record_enr_request_sent(&contact.node.node_id(), H256::from(enr_request_hash)) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .await?; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| self.send_enr_request(&contact.node).await?; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Ok(()) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| async fn send_ping(&mut self, node: &Node) -> Result<(), DiscoveryServerError> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| match self.send_ping_internal(node).await { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Ok(ping_hash) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| METRICS.record_ping_sent().await; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| self.peer_table | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .record_ping_sent(&node.node_id(), ping_hash) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .await?; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Err(err) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| error!(sent = "Ping", to = %format!("{:#x}", node.public_key), err = ?err, "Error sending message"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| self.peer_table.set_disposable(&node.node_id()).await?; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| METRICS.record_new_discarded_node().await; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Ok(()) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| async fn send_ping_internal(&self, node: &Node) -> Result<H256, DiscoveryServerError> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let mut buf = Vec::new(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // TODO: Parametrize this expiration. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let expiration: u64 = get_msg_expiration_from_seconds(EXPIRATION_SECONDS); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let from = Endpoint { | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -341,14 +304,13 @@ impl DiscoveryServer { | |||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let enr_seq = self.local_node_record.seq; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let ping = Message::Ping(PingMessage::new(from, to, expiration).with_enr_seq(enr_seq)); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ping.encode_with_header(&mut buf, &self.signer); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let ping_hash: [u8; 32] = buf[..32] | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .try_into() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .expect("first 32 bytes are the message hash"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // We do not use self.send() here, as we already encoded the message to calculate hash. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| self.udp_socket.send_to(&buf, node.udp_addr()).await?; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let ping_hash = self.send_else_dispose(ping, node).await?; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| trace!(sent = "Ping", to = %format!("{:#x}", node.public_key)); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Ok(H256::from(ping_hash)) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| METRICS.record_ping_sent().await; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| self.peer_table | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .record_ping_sent(&node.node_id(), ping_hash) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .await?; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Ok(()) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| async fn send_pong(&self, ping_hash: H256, node: &Node) -> Result<(), DiscoveryServerError> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -389,6 +351,18 @@ impl DiscoveryServer { | |||||||||||||||||||||||||||||||||||||||||||||||||
| Ok(()) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| async fn send_enr_request(&mut self, node: &Node) -> Result<(), DiscoveryServerError> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let expiration: u64 = get_msg_expiration_from_seconds(EXPIRATION_SECONDS); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let enr_request = Message::ENRRequest(ENRRequestMessage { expiration }); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| let enr_request_hash = self.send_else_dispose(enr_request, node).await?; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| self.peer_table | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .record_enr_request_sent(&node.node_id(), enr_request_hash) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .await?; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Ok(()) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| async fn send_enr_response( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| &self, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| request_hash: H256, | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -403,11 +377,34 @@ impl DiscoveryServer { | |||||||||||||||||||||||||||||||||||||||||||||||||
| Ok(()) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| async fn handle_ping(&mut self, hash: H256, node: Node) -> Result<(), DiscoveryServerError> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| async fn handle_ping( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| &mut self, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ping_message: PingMessage, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| hash: H256, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| sender_public_key: H512, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| node: Node, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) -> Result<(), DiscoveryServerError> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| self.send_pong(hash, &node).await?; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if self.peer_table.insert_if_new(&node).await.unwrap_or(false) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| self.send_ping(&node).await?; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // If the contact has stale ENR then request the updated one. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let node_id = node_id(&sender_public_key); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| let node_id = node_id(&sender_public_key); | |
| let node_id = node.node_id(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if let (Some(received), Some(stored)) = (received_enr_seq, stored_enr_seq) | |
| && received > stored | |
| { | |
| self.send_enr_request(&node).await?; | |
| } | |
| if received_enr_seq.is_some_and(|r| stored_enr_seq.is_some_and(|s| r > s)) { | |
| self.send_enr_request(&node).await?; | |
| } |
Not sure which one I prefer 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe transpose:
| if let (Some(received), Some(stored)) = (received_enr_seq, stored_enr_seq) | |
| && received > stored | |
| { | |
| self.send_enr_request(&node).await?; | |
| } | |
| if [received_enr_seq, stored_enr_seq].transpose().is_some_and(|[received, stored]| received > stored) { | |
| self.send_enr_request(&node).await?; | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or:
| if let (Some(received), Some(stored)) = (received_enr_seq, stored_enr_seq) | |
| && received > stored | |
| { | |
| self.send_enr_request(&node).await?; | |
| } | |
| if let Some([received, stored]) = [received_enr_seq, stored_enr_seq].transpose() && received > stored { | |
| self.send_enr_request(&node).await?; | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
transpose is an unstable feature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😭
Copilot
AI
Dec 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new ENR staleness detection logic in handle_ping lacks test coverage. Consider adding tests to verify that ENR requests are sent when a ping is received with a higher sequence number than the stored ENR.
Copilot
AI
Dec 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new ENR staleness detection logic in handle_pong lacks test coverage. Consider adding tests to verify that ENR requests are sent when a pong is received with a higher sequence number than the stored ENR.
Copilot
AI
Dec 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new send_else_dispose helper method lacks test coverage. Consider adding tests to verify its behavior when sending succeeds and when it fails, particularly ensuring that the node is marked as disposable and metrics are recorded on failure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's factorize common code (message encoding, hash extraction,
udp_socket.send, maybeset_disposable) withsend_ping/send_ping_internalto an utility function to minimize code repetiton.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added send_else_dispose to remove code duplication.