@@ -152,38 +152,31 @@ impl RecordStore for MemoryStore {
152152 }
153153 . or_insert_with ( Default :: default) ;
154154
155- if let Some ( i) = providers. iter ( ) . position ( |p| p. provider == record. provider ) {
156- // In-place update of an existing provider record.
157- providers. as_mut ( ) [ i] = record;
158- } else {
159- // It is a new provider record for that key.
160- let local_key = self . local_key ;
161- let key = kbucket:: Key :: new ( record. key . clone ( ) ) ;
162- let provider = kbucket:: Key :: from ( record. provider ) ;
163- if let Some ( i) = providers. iter ( ) . position ( |p| {
164- let pk = kbucket:: Key :: from ( p. provider ) ;
165- provider. distance ( & key) < pk. distance ( & key)
166- } ) {
167- // Insert the new provider.
168- if local_key. preimage ( ) == & record. provider {
155+ for p in providers. iter_mut ( ) {
156+ if p. provider == record. provider {
157+ // In-place update of an existing provider record.
158+ if self . local_key . preimage ( ) == & record. provider {
159+ self . provided . remove ( p) ;
169160 self . provided . insert ( record. clone ( ) ) ;
170161 }
171- providers. insert ( i, record) ;
172- // Remove the excess provider, if any.
173- if providers. len ( ) > self . config . max_providers_per_key {
174- if let Some ( p) = providers. pop ( ) {
175- self . provided . remove ( & p) ;
176- }
177- }
178- } else if providers. len ( ) < self . config . max_providers_per_key {
179- // The distance of the new provider to the key is larger than
180- // the distance of any existing provider, but there is still room.
181- if local_key. preimage ( ) == & record. provider {
182- self . provided . insert ( record. clone ( ) ) ;
183- }
184- providers. push ( record) ;
162+ * p = record;
163+ return Ok ( ( ) ) ;
185164 }
186165 }
166+
167+ // If the providers list is full, we ignore the new provider.
168+ // This strategy can mitigate Sybil attacks, in which an attacker
169+ // floods the network with fake provider records.
170+ if providers. len ( ) == self . config . max_providers_per_key {
171+ return Ok ( ( ) ) ;
172+ }
173+
174+ // Otherwise, insert the new provider record.
175+ if self . local_key . preimage ( ) == & record. provider {
176+ self . provided . insert ( record. clone ( ) ) ;
177+ }
178+ providers. push ( record) ;
179+
187180 Ok ( ( ) )
188181 }
189182
@@ -202,7 +195,9 @@ impl RecordStore for MemoryStore {
202195 let providers = e. get_mut ( ) ;
203196 if let Some ( i) = providers. iter ( ) . position ( |p| & p. provider == provider) {
204197 let p = providers. remove ( i) ;
205- self . provided . remove ( & p) ;
198+ if & p. provider == self . local_key . preimage ( ) {
199+ self . provided . remove ( & p) ;
200+ }
206201 }
207202 if providers. is_empty ( ) {
208203 e. remove ( ) ;
@@ -221,11 +216,6 @@ mod tests {
221216 fn random_multihash ( ) -> Multihash < 64 > {
222217 Multihash :: wrap ( SHA_256_MH , & rand:: thread_rng ( ) . gen :: < [ u8 ; 32 ] > ( ) ) . unwrap ( )
223218 }
224-
225- fn distance ( r : & ProviderRecord ) -> kbucket:: Distance {
226- kbucket:: Key :: new ( r. key . clone ( ) ) . distance ( & kbucket:: Key :: from ( r. provider ) )
227- }
228-
229219 #[ test]
230220 fn put_get_remove_record ( ) {
231221 fn prop ( r : Record ) {
@@ -250,30 +240,6 @@ mod tests {
250240 quickcheck ( prop as fn ( _) )
251241 }
252242
253- #[ test]
254- fn providers_ordered_by_distance_to_key ( ) {
255- fn prop ( providers : Vec < kbucket:: Key < PeerId > > ) -> bool {
256- let mut store = MemoryStore :: new ( PeerId :: random ( ) ) ;
257- let key = Key :: from ( random_multihash ( ) ) ;
258-
259- let mut records = providers
260- . into_iter ( )
261- . map ( |p| ProviderRecord :: new ( key. clone ( ) , p. into_preimage ( ) , Vec :: new ( ) ) )
262- . collect :: < Vec < _ > > ( ) ;
263-
264- for r in & records {
265- assert ! ( store. add_provider( r. clone( ) ) . is_ok( ) ) ;
266- }
267-
268- records. sort_by_key ( distance) ;
269- records. truncate ( store. config . max_providers_per_key ) ;
270-
271- records == store. providers ( & key) . to_vec ( )
272- }
273-
274- quickcheck ( prop as fn ( _) -> _ )
275- }
276-
277243 #[ test]
278244 fn provided ( ) {
279245 let id = PeerId :: random ( ) ;
@@ -302,6 +268,46 @@ mod tests {
302268 assert_eq ! ( vec![ rec. clone( ) ] , store. providers( & rec. key) . to_vec( ) ) ;
303269 }
304270
271+ #[ test]
272+ fn update_provided ( ) {
273+ let prv = PeerId :: random ( ) ;
274+ let mut store = MemoryStore :: new ( prv) ;
275+ let key = random_multihash ( ) ;
276+ let mut rec = ProviderRecord :: new ( key, prv, Vec :: new ( ) ) ;
277+ assert ! ( store. add_provider( rec. clone( ) ) . is_ok( ) ) ;
278+ assert_eq ! (
279+ vec![ Cow :: Borrowed ( & rec) ] ,
280+ store. provided( ) . collect:: <Vec <_>>( )
281+ ) ;
282+ rec. expires = Some ( Instant :: now ( ) ) ;
283+ assert ! ( store. add_provider( rec. clone( ) ) . is_ok( ) ) ;
284+ assert_eq ! (
285+ vec![ Cow :: Borrowed ( & rec) ] ,
286+ store. provided( ) . collect:: <Vec <_>>( )
287+ ) ;
288+ }
289+
290+ #[ test]
291+ fn max_providers_per_key ( ) {
292+ let config = MemoryStoreConfig :: default ( ) ;
293+ let key = kbucket:: Key :: new ( Key :: from ( random_multihash ( ) ) ) ;
294+
295+ let mut store = MemoryStore :: with_config ( PeerId :: random ( ) , config. clone ( ) ) ;
296+ let peers = ( 0 ..config. max_providers_per_key )
297+ . map ( |_| PeerId :: random ( ) )
298+ . collect :: < Vec < _ > > ( ) ;
299+ for peer in peers {
300+ let rec = ProviderRecord :: new ( key. preimage ( ) . clone ( ) , peer, Vec :: new ( ) ) ;
301+ assert ! ( store. add_provider( rec) . is_ok( ) ) ;
302+ }
303+
304+ // The new provider cannot be added because the key is already saturated.
305+ let peer = PeerId :: random ( ) ;
306+ let rec = ProviderRecord :: new ( key. preimage ( ) . clone ( ) , peer, Vec :: new ( ) ) ;
307+ assert ! ( store. add_provider( rec. clone( ) ) . is_ok( ) ) ;
308+ assert ! ( !store. providers( & rec. key) . contains( & rec) ) ;
309+ }
310+
305311 #[ test]
306312 fn max_provided_keys ( ) {
307313 let mut store = MemoryStore :: new ( PeerId :: random ( ) ) ;
0 commit comments