@@ -4,22 +4,20 @@ use chrono::Utc;
44use  dapi_grpc:: tonic:: codegen:: http; 
55use  dapi_grpc:: tonic:: transport:: Uri ; 
66use  rand:: { rngs:: SmallRng ,  seq:: IteratorRandom ,  SeedableRng } ; 
7- use  std:: collections:: HashSet ; 
7+ use  std:: collections:: hash_map:: Entry ; 
8+ use  std:: collections:: HashMap ; 
89use  std:: hash:: { Hash ,  Hasher } ; 
10+ use  std:: mem; 
911use  std:: str:: FromStr ; 
12+ use  std:: sync:: { Arc ,  RwLock } ; 
1013use  std:: time:: Duration ; 
1114
1215const  DEFAULT_BASE_BAN_PERIOD :  Duration  = Duration :: from_secs ( 60 ) ; 
1316
1417/// DAPI address. 
1518#[ derive( Debug ,  Clone ,  Eq ) ]  
1619#[ cfg_attr( feature = "mocks" ,  derive( serde:: Serialize ,  serde:: Deserialize ) ) ]  
17- pub  struct  Address  { 
18-     ban_count :  usize , 
19-     banned_until :  Option < chrono:: DateTime < Utc > > , 
20-     #[ cfg_attr( feature = "mocks" ,  serde( with = "http_serde::uri" ) ) ]  
21-     uri :  Uri , 
22- } 
20+ pub  struct  Address ( #[ cfg_attr( feature = "mocks" ,  serde( with = "http_serde::uri" ) ) ]   Uri ) ; 
2321
2422impl  FromStr  for  Address  { 
2523    type  Err  = AddressListError ; 
@@ -33,35 +31,46 @@ impl FromStr for Address {
3331
3432impl  PartialEq < Self >  for  Address  { 
3533    fn  eq ( & self ,  other :  & Self )  -> bool  { 
36-         self . uri  == other. uri 
34+         self . 0  == other. 0 
3735    } 
3836} 
3937
4038impl  PartialEq < Uri >  for  Address  { 
4139    fn  eq ( & self ,  other :  & Uri )  -> bool  { 
42-         self . uri  == * other
40+         self . 0  == * other
4341    } 
4442} 
4543
4644impl  Hash  for  Address  { 
4745    fn  hash < H :  Hasher > ( & self ,  state :  & mut  H )  { 
48-         self . uri . hash ( state) ; 
46+         self . 0 . hash ( state) ; 
4947    } 
5048} 
5149
5250impl  From < Uri >  for  Address  { 
5351    fn  from ( uri :  Uri )  -> Self  { 
54-         Address  { 
55-             ban_count :  0 , 
56-             banned_until :  None , 
57-             uri, 
58-         } 
52+         Address ( uri) 
5953    } 
6054} 
6155
6256impl  Address  { 
57+     /// Get [Uri] of a node. 
58+      pub  fn  uri ( & self )  -> & Uri  { 
59+         & self . 0 
60+     } 
61+ } 
62+ 
63+ /// Address status 
64+ /// Contains information about the number of bans and the time until the next ban is lifted. 
65+ #[ derive( Debug ,  Default ,  Clone ) ]  
66+ pub  struct  AddressStatus  { 
67+     ban_count :  usize , 
68+     banned_until :  Option < chrono:: DateTime < Utc > > , 
69+ } 
70+ 
71+ impl  AddressStatus  { 
6372    /// Ban the [Address] so it won't be available through [AddressList::get_live_address] for some time. 
64-      fn  ban ( & mut  self ,  base_ban_period :  & Duration )  { 
73+      pub   fn  ban ( & mut  self ,  base_ban_period :  & Duration )  { 
6574        let  coefficient = ( self . ban_count  as  f64 ) . exp ( ) ; 
6675        let  ban_period = Duration :: from_secs_f64 ( base_ban_period. as_secs_f64 ( )  *  coefficient) ; 
6776
@@ -75,24 +84,16 @@ impl Address {
7584    } 
7685
7786    /// Clears ban record. 
78-      fn  unban ( & mut  self )  { 
87+      pub   fn  unban ( & mut  self )  { 
7988        self . ban_count  = 0 ; 
8089        self . banned_until  = None ; 
8190    } 
82- 
83-     /// Get [Uri] of a node. 
84-      pub  fn  uri ( & self )  -> & Uri  { 
85-         & self . uri 
86-     } 
8791} 
8892
8993/// [AddressList] errors 
9094#[ derive( Debug ,  thiserror:: Error ) ]  
9195#[ cfg_attr( feature = "mocks" ,  derive( serde:: Serialize ,  serde:: Deserialize ) ) ]  
9296pub  enum  AddressListError  { 
93-     /// Specified address is not present in the list 
94-      #[ error( "address {0} not found in the list" ) ]  
95-     AddressNotFound ( #[ cfg_attr( feature = "mocks" ,  serde( with = "http_serde::uri" ) ) ]   Uri ) , 
9697    /// A valid uri is required to create an Address 
9798     #[ error( "unable parse address: {0}" ) ]  
9899    #[ cfg_attr( feature = "mocks" ,  serde( skip) ) ]  
@@ -103,7 +104,7 @@ pub enum AddressListError {
103104/// for [DapiRequest](crate::DapiRequest) execution. 
104105#[ derive( Debug ,  Clone ) ]  
105106pub  struct  AddressList  { 
106-     addresses :  HashSet < Address > , 
107+     addresses :  Arc < RwLock < HashMap < Address ,   AddressStatus > > > , 
107108    base_ban_period :  Duration , 
108109} 
109110
@@ -115,7 +116,7 @@ impl Default for AddressList {
115116
116117impl  std:: fmt:: Display  for  Address  { 
117118    fn  fmt ( & self ,  f :  & mut  std:: fmt:: Formatter < ' _ > )  -> std:: fmt:: Result  { 
118-         self . uri . fmt ( f) 
119+         self . 0 . fmt ( f) 
119120    } 
120121} 
121122
@@ -128,43 +129,70 @@ impl AddressList {
128129    /// Creates an empty [AddressList] with adjustable base ban time. 
129130     pub  fn  with_settings ( base_ban_period :  Duration )  -> Self  { 
130131        AddressList  { 
131-             addresses :  HashSet :: new ( ) , 
132+             addresses :  Arc :: new ( RwLock :: new ( HashMap :: new ( ) ) ) , 
132133            base_ban_period, 
133134        } 
134135    } 
135136
136137    /// Bans address 
137-      pub ( crate )  fn  ban_address ( & mut  self ,  address :  & Address )  -> Result < ( ) ,  AddressListError >  { 
138-         if  !self . addresses . remove ( address)  { 
139-             return  Err ( AddressListError :: AddressNotFound ( address. uri . clone ( ) ) ) ; 
140-         } ; 
138+      /// Returns false if the address is not in the list. 
139+      pub  fn  ban ( & self ,  address :  & Address )  -> bool  { 
140+         let  mut  guard = self . addresses . write ( ) . unwrap ( ) ; 
141141
142-         let  mut  banned_address = address. clone ( ) ; 
143-         banned_address. ban ( & self . base_ban_period ) ; 
142+         let  Some ( status)  = guard. get_mut ( address)  else  { 
143+             return  false ; 
144+         } ; 
144145
145-         self . addresses . insert ( banned_address ) ; 
146+         status . ban ( & self . base_ban_period ) ; 
146147
147-         Ok ( ( ) ) 
148+         true 
148149    } 
149150
150151    /// Clears address' ban record 
151-      pub ( crate )  fn  unban_address ( & mut  self ,  address :  & Address )  -> Result < ( ) ,  AddressListError >  { 
152-         if  !self . addresses . remove ( address)  { 
153-             return  Err ( AddressListError :: AddressNotFound ( address. uri . clone ( ) ) ) ; 
152+      /// Returns false if the address is not in the list. 
153+      pub  fn  unban ( & self ,  address :  & Address )  -> bool  { 
154+         let  mut  guard = self . addresses . write ( ) . unwrap ( ) ; 
155+ 
156+         let  Some ( status)  = guard. get_mut ( address)  else  { 
157+             return  false ; 
154158        } ; 
155159
156-         let  mut  unbanned_address = address. clone ( ) ; 
157-         unbanned_address. unban ( ) ; 
160+         status. unban ( ) ; 
161+ 
162+         true 
163+     } 
158164
159-         self . addresses . insert ( unbanned_address) ; 
165+     /// Check if the address is banned. 
166+      pub  fn  is_banned ( & self ,  address :  & Address )  -> bool  { 
167+         let  guard = self . addresses . read ( ) . unwrap ( ) ; 
160168
161-         Ok ( ( ) ) 
169+         guard
170+             . get ( address) 
171+             . map ( |status| status. is_banned ( ) ) 
172+             . unwrap_or ( false ) 
162173    } 
163174
164175    /// Adds a node [Address] to [AddressList] 
165176     /// Returns false if the address is already in the list. 
166177     pub  fn  add ( & mut  self ,  address :  Address )  -> bool  { 
167-         self . addresses . insert ( address) 
178+         let  mut  guard = self . addresses . write ( ) . unwrap ( ) ; 
179+ 
180+         match  guard. entry ( address)  { 
181+             Entry :: Occupied ( _)  => false , 
182+             Entry :: Vacant ( e)  => { 
183+                 e. insert ( AddressStatus :: default ( ) ) ; 
184+ 
185+                 true 
186+             } 
187+         } 
188+     } 
189+ 
190+     /// Remove address from the list 
191+      /// Returns [AddressStatus] if the address was in the list. 
192+      pub  fn  remove ( & mut  self ,  address :  & Address )  -> Option < AddressStatus >  { 
193+         let  mut  guard = self . addresses . write ( ) . unwrap ( ) ; 
194+ 
195+         guard. remove ( address) 
168196    } 
169197
170198    // TODO: this is the most simple way to add an address 
@@ -173,46 +201,53 @@ impl AddressList {
173201    /// Add a node [Address] to [AddressList] by [Uri]. 
174202     /// Returns false if the address is already in the list. 
175203     pub  fn  add_uri ( & mut  self ,  uri :  Uri )  -> bool  { 
176-         self . addresses . insert ( uri . into ( ) ) 
204+         self . add ( Address :: from ( uri ) ) 
177205    } 
178206
179207    /// Randomly select a not banned address. 
180-      pub  fn  get_live_address ( & self )  -> Option < & Address >  { 
181-         let  mut  rng =  SmallRng :: from_entropy ( ) ; 
208+      pub  fn  get_live_address ( & self )  -> Option < Address >  { 
209+         let  guard =  self . addresses . read ( ) . unwrap ( ) ; 
182210
183-         self . unbanned ( ) . into_iter ( ) . choose ( & mut  rng) 
184-     } 
211+         let  mut  rng = SmallRng :: from_entropy ( ) ; 
185212
186-     /// Get all addresses that are not banned. 
187-      fn  unbanned ( & self )  -> Vec < & Address >  { 
188213        let  now = chrono:: Utc :: now ( ) ; 
189214
190-         self . addresses 
215+         guard 
191216            . iter ( ) 
192-             . filter ( |addr| { 
193-                 addr. banned_until 
217+             . filter ( |( _,  status) | { 
218+                 status
219+                     . banned_until 
194220                    . map ( |banned_until| banned_until < now) 
195221                    . unwrap_or ( true ) 
196222            } ) 
197-             . collect ( ) 
198-     } 
199- 
200-     /// Get number of available, not banned addresses. 
201-      pub  fn  available ( & self )  -> usize  { 
202-         self . unbanned ( ) . len ( ) 
223+             . choose ( & mut  rng) 
224+             . map ( |( addr,  _) | addr. clone ( ) ) 
203225    } 
204226
205227    /// Get number of all addresses, both banned and not banned. 
206228     pub  fn  len ( & self )  -> usize  { 
207-         self . addresses . len ( ) 
229+         self . addresses . read ( ) . unwrap ( ) . len ( ) 
208230    } 
209231
210232    /// Check if the list is empty. 
211233     /// Returns true if there are no addresses in the list. 
212234     /// Returns false if there is at least one address in the list. 
213235     /// Banned addresses are also counted. 
214236     pub  fn  is_empty ( & self )  -> bool  { 
215-         self . addresses . is_empty ( ) 
237+         self . addresses . read ( ) . unwrap ( ) . is_empty ( ) 
238+     } 
239+ } 
240+ 
241+ impl  IntoIterator  for  AddressList  { 
242+     type  Item  = ( Address ,  AddressStatus ) ; 
243+     type  IntoIter  = std:: collections:: hash_map:: IntoIter < Address ,  AddressStatus > ; 
244+ 
245+     fn  into_iter ( self )  -> Self :: IntoIter  { 
246+         let  mut  guard = self . addresses . write ( ) . unwrap ( ) ; 
247+ 
248+         let  addresses_map = mem:: take ( & mut  * guard) ; 
249+ 
250+         addresses_map. into_iter ( ) 
216251    } 
217252} 
218253
@@ -238,12 +273,3 @@ impl FromIterator<Uri> for AddressList {
238273        address_list
239274    } 
240275} 
241- 
242- impl  IntoIterator  for  AddressList  { 
243-     type  Item  = Address ; 
244-     type  IntoIter  = std:: collections:: hash_set:: IntoIter < Address > ; 
245- 
246-     fn  into_iter ( self )  -> Self :: IntoIter  { 
247-         self . addresses . into_iter ( ) 
248-     } 
249- } 
0 commit comments