@@ -16,6 +16,7 @@ use crate::socket;
1616use ethportal_api:: types:: enr:: Enr ;
1717use ethportal_api:: utils:: bytes:: hex_encode;
1818use ethportal_api:: NodeInfo ;
19+ use std:: hash:: { Hash , Hasher } ;
1920use std:: net:: Ipv4Addr ;
2021use std:: str:: FromStr ;
2122use std:: { convert:: TryFrom , fmt, io, net:: SocketAddr , sync:: Arc } ;
@@ -290,7 +291,7 @@ impl Discv5UdpSocket {
290291}
291292
292293/// A wrapper around `Enr` that implements `ConnectionPeer`.
293- #[ derive( Clone , Debug , Eq , PartialEq , Hash ) ]
294+ #[ derive( Clone , Debug ) ]
294295pub struct UtpEnr ( pub Enr ) ;
295296
296297impl UtpEnr {
@@ -305,6 +306,28 @@ impl UtpEnr {
305306 }
306307}
307308
309+ // Why are we implementing Hash, PartialEq, Eq for UtpEnr?
310+ // UtpEnr is used as an element of the key for a Connections HashTable in our uTP library.
311+ // Enr's can change and are not stable, so if we initiate a ``connect_with_cid`` we are inserting
312+ // our known Enr for the peer, but if the peer has a more upto date Enr, values will be different
313+ // and the Hash for the old Enr and New Enr will be different, along with equating the two structs will return false.
314+ // This leads us to a situation where our peer sends us a uTP messages back and our code thinks the same peer
315+ // is instead 2 different peers causing uTP to ignore the messages. We fixed this by implementing Eq and
316+ // Hash only using the NodeId of the Enr as it is the only stable non-updatable field in the Enr.
317+ impl Hash for UtpEnr {
318+ fn hash < H : Hasher > ( & self , state : & mut H ) {
319+ self . 0 . node_id ( ) . hash ( state) ;
320+ }
321+ }
322+
323+ impl PartialEq for UtpEnr {
324+ fn eq ( & self , other : & Self ) -> bool {
325+ self . 0 . node_id ( ) == other. 0 . node_id ( )
326+ }
327+ }
328+
329+ impl Eq for UtpEnr { }
330+
308331impl ConnectionPeer for UtpEnr { }
309332
310333#[ async_trait]
0 commit comments