1717//! Contains the state storage behind the peerset.
1818
1919use libp2p:: PeerId ;
20+ use log:: { error, warn} ;
2021use std:: { borrow:: Cow , collections:: { HashSet , HashMap } } ;
21- use log :: warn ;
22+ use wasm_timer :: Instant ;
2223
2324/// State storage behind the peerset.
2425///
@@ -69,7 +70,9 @@ struct Node {
6970impl Default for Node {
7071 fn default ( ) -> Node {
7172 Node {
72- connection_state : ConnectionState :: NotConnected ,
73+ connection_state : ConnectionState :: NotConnected {
74+ last_connected : Instant :: now ( ) ,
75+ } ,
7376 reputation : 0 ,
7477 }
7578 }
@@ -83,7 +86,11 @@ enum ConnectionState {
8386 /// We are connected through an outgoing connection.
8487 Out ,
8588 /// We are not connected to this node.
86- NotConnected ,
89+ NotConnected {
90+ /// When we were last connected to the node, or if we were never connected when we
91+ /// discovered it.
92+ last_connected : Instant ,
93+ } ,
8794}
8895
8996impl ConnectionState {
@@ -92,7 +99,7 @@ impl ConnectionState {
9299 match self {
93100 ConnectionState :: In => true ,
94101 ConnectionState :: Out => true ,
95- ConnectionState :: NotConnected => false ,
102+ ConnectionState :: NotConnected { .. } => false ,
96103 }
97104 }
98105}
@@ -212,11 +219,13 @@ impl PeersState {
212219 match node. connection_state {
213220 ConnectionState :: In => self . num_in -= 1 ,
214221 ConnectionState :: Out => self . num_out -= 1 ,
215- ConnectionState :: NotConnected =>
222+ ConnectionState :: NotConnected { .. } =>
216223 debug_assert ! ( false , "State inconsistency: disconnecting a disconnected node" )
217224 }
218225 }
219- node. connection_state = ConnectionState :: NotConnected ;
226+ node. connection_state = ConnectionState :: NotConnected {
227+ last_connected : Instant :: now ( ) ,
228+ } ;
220229 } else {
221230 warn ! ( target: "peerset" , "Attempting to disconnect unknown peer {}" , peer_id) ;
222231 }
@@ -292,7 +301,7 @@ impl PeersState {
292301 match peer. connection_state {
293302 ConnectionState :: In => self . num_in += 1 ,
294303 ConnectionState :: Out => self . num_out += 1 ,
295- ConnectionState :: NotConnected => { } ,
304+ ConnectionState :: NotConnected { .. } => { } ,
296305 }
297306 }
298307 }
@@ -305,7 +314,7 @@ impl PeersState {
305314 match peer. connection_state {
306315 ConnectionState :: In => self . num_in -= 1 ,
307316 ConnectionState :: Out => self . num_out -= 1 ,
308- ConnectionState :: NotConnected => { } ,
317+ ConnectionState :: NotConnected { .. } => { } ,
309318 }
310319 }
311320 }
@@ -467,6 +476,45 @@ impl<'a> NotConnectedPeer<'a> {
467476 self . peer_id . into_owned ( )
468477 }
469478
479+ /// Bumps the value that `last_connected_or_discovered` would return to now, even if we
480+ /// didn't connect or disconnect.
481+ pub fn bump_last_connected_or_discovered ( & mut self ) {
482+ let state = match self . state . nodes . get_mut ( & * self . peer_id ) {
483+ Some ( s) => s,
484+ None => return ,
485+ } ;
486+
487+ if let ConnectionState :: NotConnected { last_connected } = & mut state. connection_state {
488+ * last_connected = Instant :: now ( ) ;
489+ }
490+ }
491+
492+ /// Returns when we were last connected to this peer, or when we discovered it if we were
493+ /// never connected.
494+ ///
495+ /// Guaranteed to be earlier than calling `Instant::now()` after the function returns.
496+ pub fn last_connected_or_discovered ( & self ) -> Instant {
497+ let state = match self . state . nodes . get ( & * self . peer_id ) {
498+ Some ( s) => s,
499+ None => {
500+ error ! (
501+ target: "peerset" ,
502+ "State inconsistency with {}; not connected after borrow" ,
503+ self . peer_id
504+ ) ;
505+ return Instant :: now ( ) ;
506+ }
507+ } ;
508+
509+ match state. connection_state {
510+ ConnectionState :: NotConnected { last_connected } => last_connected,
511+ _ => {
512+ error ! ( target: "peerset" , "State inconsistency with {}" , self . peer_id) ;
513+ Instant :: now ( )
514+ }
515+ }
516+ }
517+
470518 /// Tries to set the peer as connected as an outgoing connection.
471519 ///
472520 /// If there are enough slots available, switches the node to "connected" and returns `Ok`. If
@@ -518,6 +566,22 @@ impl<'a> NotConnectedPeer<'a> {
518566 pub fn add_reputation ( & mut self , modifier : i32 ) {
519567 self . state . add_reputation ( & self . peer_id , modifier)
520568 }
569+
570+ /// Un-discovers the peer. Removes it from the list.
571+ pub fn forget_peer ( self ) -> UnknownPeer < ' a > {
572+ if self . state . nodes . remove ( & * self . peer_id ) . is_none ( ) {
573+ error ! (
574+ target: "peerset" ,
575+ "State inconsistency with {} when forgetting peer" ,
576+ self . peer_id
577+ ) ;
578+ }
579+
580+ UnknownPeer {
581+ parent : self . state ,
582+ peer_id : self . peer_id ,
583+ }
584+ }
521585}
522586
523587/// A peer that we have never heard of.
@@ -533,7 +597,9 @@ impl<'a> UnknownPeer<'a> {
533597 /// values using the `NotConnectedPeer` that this method returns.
534598 pub fn discover ( self ) -> NotConnectedPeer < ' a > {
535599 self . parent . nodes . insert ( self . peer_id . clone ( ) . into_owned ( ) , Node {
536- connection_state : ConnectionState :: NotConnected ,
600+ connection_state : ConnectionState :: NotConnected {
601+ last_connected : Instant :: now ( ) ,
602+ } ,
537603 reputation : 0 ,
538604 } ) ;
539605
0 commit comments