diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Network/DHT/Routing.hs | 150 |
1 files changed, 88 insertions, 62 deletions
diff --git a/src/Network/DHT/Routing.hs b/src/Network/DHT/Routing.hs index 1821ca1c..58e0cbd3 100644 --- a/src/Network/DHT/Routing.hs +++ b/src/Network/DHT/Routing.hs | |||
@@ -16,10 +16,12 @@ | |||
16 | {-# LANGUAGE CPP #-} | 16 | {-# LANGUAGE CPP #-} |
17 | {-# LANGUAGE RecordWildCards #-} | 17 | {-# LANGUAGE RecordWildCards #-} |
18 | {-# LANGUAGE BangPatterns #-} | 18 | {-# LANGUAGE BangPatterns #-} |
19 | {-# LANGUAGE RankNTypes #-} | ||
19 | {-# LANGUAGE ViewPatterns #-} | 20 | {-# LANGUAGE ViewPatterns #-} |
20 | {-# LANGUAGE TypeOperators #-} | 21 | {-# LANGUAGE TypeOperators #-} |
21 | {-# LANGUAGE DeriveGeneric #-} | 22 | {-# LANGUAGE DeriveGeneric #-} |
22 | {-# LANGUAGE DeriveFunctor #-} | 23 | {-# LANGUAGE DeriveFunctor #-} |
24 | {-# LANGUAGE GADTs #-} | ||
23 | {-# LANGUAGE ScopedTypeVariables #-} | 25 | {-# LANGUAGE ScopedTypeVariables #-} |
24 | {-# LANGUAGE StandaloneDeriving, FlexibleContexts, MultiParamTypeClasses, FlexibleInstances #-} | 26 | {-# LANGUAGE StandaloneDeriving, FlexibleContexts, MultiParamTypeClasses, FlexibleInstances #-} |
25 | {-# OPTIONS_GHC -fno-warn-orphans #-} | 27 | {-# OPTIONS_GHC -fno-warn-orphans #-} |
@@ -171,15 +173,22 @@ bucketQ = seqQ | |||
171 | 173 | ||
172 | newtype Compare a = Compare (a -> a -> Ordering) | 174 | newtype Compare a = Compare (a -> a -> Ordering) |
173 | 175 | ||
174 | newtype Ordered s a = Ordered a | 176 | contramapC :: (b -> a) -> Compare a -> Compare b |
177 | contramapC f (Compare cmp) = Compare $ \a b -> cmp (f a) (f b) | ||
178 | |||
179 | newtype Ordered' s a = Ordered a | ||
180 | deriving (Show) | ||
175 | 181 | ||
176 | -- | Hack to avoid UndecidableInstances | 182 | -- | Hack to avoid UndecidableInstances |
177 | newtype Shrink a = Shrink a | 183 | newtype Shrink a = Shrink a |
184 | deriving (Show) | ||
185 | |||
186 | type Ordered s a = Ordered' s (Shrink a) | ||
178 | 187 | ||
179 | instance Reifies s (Compare a) => Eq (Ordered s (Shrink a)) where | 188 | instance Reifies s (Compare a) => Eq (Ordered' s (Shrink a)) where |
180 | a == b = (compare a b == EQ) | 189 | a == b = (compare a b == EQ) |
181 | 190 | ||
182 | instance Reifies s (Compare a) => Ord (Ordered s (Shrink a)) where | 191 | instance Reifies s (Compare a) => Ord (Ordered' s (Shrink a)) where |
183 | compare a b = cmp (coerce a) (coerce b) | 192 | compare a b = cmp (coerce a) (coerce b) |
184 | where Compare cmp = reflect (Proxy :: Proxy s) | 193 | where Compare cmp = reflect (Proxy :: Proxy s) |
185 | 194 | ||
@@ -189,16 +198,20 @@ instance Reifies s (Compare a) => Ord (Ordered s (Shrink a)) where | |||
189 | -- table tree. Size of the bucket should be choosen such that it's | 198 | -- table tree. Size of the bucket should be choosen such that it's |
190 | -- very unlikely that all nodes in bucket fail within an hour of | 199 | -- very unlikely that all nodes in bucket fail within an hour of |
191 | -- each other. | 200 | -- each other. |
192 | data Bucket ni = Bucket | 201 | data Bucket s ni = Bucket |
193 | { bktNodes :: !(PSQ ni Timestamp) -- current routing nodes | 202 | { bktNodes :: !(PSQ (Ordered s ni) Timestamp) -- current routing nodes |
194 | , bktQ :: !(BucketQueue (Timestamp,ni)) -- replacements pending time-outs | 203 | , bktQ :: !(BucketQueue (Timestamp,ni)) -- replacements pending time-outs |
195 | } deriving (Generic) | 204 | } deriving (Generic) |
196 | 205 | ||
197 | deriving instance Show ni => Show (Bucket ni) | 206 | deriving instance Show ni => Show (Bucket s ni) |
207 | |||
208 | bucketCompare :: forall p ni s. Reifies s (Compare ni) => p (Bucket s ni) -> Compare ni | ||
209 | bucketCompare _ = reflect (Proxy :: Proxy s) | ||
198 | 210 | ||
199 | mapBucket :: Ord ni => (a -> ni) -> Bucket a -> Bucket ni | 211 | mapBucket :: Reifies t (Compare ni) => (a -> ni) -> Bucket s a -> Bucket t ni |
200 | mapBucket f (Bucket ns q) = Bucket (PSQ.fromList $ map (\(ni :-> tm) -> (f ni :-> tm)) $ PSQ.toList ns) | 212 | mapBucket f (Bucket ns q) = Bucket (PSQ.fromList $ map (\(ni :-> tm) -> (f' ni :-> tm)) $ PSQ.toList ns) |
201 | (fmap (second f) q) | 213 | (fmap (second f) q) |
214 | where f' = coerce . f . coerce | ||
202 | 215 | ||
203 | 216 | ||
204 | #if 0 | 217 | #if 0 |
@@ -255,10 +268,10 @@ updateBucketForInbound curTime info bucket | |||
255 | -- timestamp updated here, since 'TryInsert' is called on every inbound packet, | 268 | -- timestamp updated here, since 'TryInsert' is called on every inbound packet, |
256 | -- including ping results. | 269 | -- including ping results. |
257 | | already_have | 270 | | already_have |
258 | = pure ( [], map_ns $ PSQ.insertWith max info curTime ) | 271 | = pure ( [], map_ns $ PSQ.insertWith max (coerce info) curTime ) |
259 | -- bucket is good, but not full => we can insert a new node | 272 | -- bucket is good, but not full => we can insert a new node |
260 | | PSQ.size (bktNodes bucket) < defaultBucketSize | 273 | | PSQ.size (bktNodes bucket) < defaultBucketSize |
261 | = pure ( [], map_ns $ PSQ.insert info curTime ) | 274 | = pure ( [], map_ns $ PSQ.insert (coerce info) curTime ) |
262 | -- If there are any questionable nodes in the bucket have not been | 275 | -- If there are any questionable nodes in the bucket have not been |
263 | -- seen in the last 15 minutes, the least recently seen node is | 276 | -- seen in the last 15 minutes, the least recently seen node is |
264 | -- pinged. If any nodes in the bucket are known to have become bad, | 277 | -- pinged. If any nodes in the bucket are known to have become bad, |
@@ -267,7 +280,7 @@ updateBucketForInbound curTime info bucket | |||
267 | | not (L.null stales) | 280 | | not (L.null stales) |
268 | = pure ( stales | 281 | = pure ( stales |
269 | , bucket { -- Update timestamps so that we don't redundantly ping. | 282 | , bucket { -- Update timestamps so that we don't redundantly ping. |
270 | bktNodes = updateStamps curTime stales $ bktNodes bucket | 283 | bktNodes = updateStamps curTime (coerce stales) $ bktNodes bucket |
271 | -- Update queue with the pending NodeInfo in case of ping fail. | 284 | -- Update queue with the pending NodeInfo in case of ping fail. |
272 | , bktQ = runIdentity $ pushBack bucketQ (curTime,info) $ bktQ bucket } ) | 285 | , bktQ = runIdentity $ pushBack bucketQ (curTime,info) $ bktQ bucket } ) |
273 | -- When the bucket is full of good nodes, the new node is simply discarded. | 286 | -- When the bucket is full of good nodes, the new node is simply discarded. |
@@ -281,11 +294,11 @@ updateBucketForInbound curTime info bucket | |||
281 | stales = -- One stale: | 294 | stales = -- One stale: |
282 | do (n :-> t) <- maybeToList $ PSQ.findMin (bktNodes bucket) | 295 | do (n :-> t) <- maybeToList $ PSQ.findMin (bktNodes bucket) |
283 | guard (t < curTime - delta) | 296 | guard (t < curTime - delta) |
284 | return n | 297 | return $ coerce n |
285 | -- All stale: | 298 | -- All stale: |
286 | -- map key \$ PSQ.atMost (curTime - delta) $ bktNodes bucket | 299 | -- map key \$ PSQ.atMost (curTime - delta) $ bktNodes bucket |
287 | 300 | ||
288 | already_have = maybe False (const True) $ PSQ.lookup info (bktNodes bucket) | 301 | already_have = maybe False (const True) $ PSQ.lookup (coerce info) (bktNodes bucket) |
289 | 302 | ||
290 | map_ns f = bucket { bktNodes = f (bktNodes bucket) } | 303 | map_ns f = bucket { bktNodes = f (bktNodes bucket) } |
291 | -- map_q f = bucket { bktQ = runIdentity \$ f (bktQ bucket) } | 304 | -- map_q f = bucket { bktQ = runIdentity \$ f (bktQ bucket) } |
@@ -302,13 +315,13 @@ updateBucketForPingResult bad_node got_response bucket | |||
302 | replacements | got_response = [] -- Timestamp was already updated by TryInsert. | 315 | replacements | got_response = [] -- Timestamp was already updated by TryInsert. |
303 | | Just info <- top = do | 316 | | Just info <- top = do |
304 | -- Insert only if there's a removal. | 317 | -- Insert only if there's a removal. |
305 | _ <- maybeToList $ PSQ.lookup bad_node (bktNodes bucket) | 318 | _ <- maybeToList $ PSQ.lookup (coerce bad_node) (bktNodes bucket) |
306 | return (bad_node, info) | 319 | return (bad_node, info) |
307 | | otherwise = [] | 320 | | otherwise = [] |
308 | 321 | ||
309 | replace (bad_node, (tm, info)) = | 322 | replace (bad_node, (tm, info)) = |
310 | PSQ.insert info tm | 323 | PSQ.insert (coerce info) tm |
311 | . PSQ.delete bad_node | 324 | . PSQ.delete (coerce bad_node) |
312 | 325 | ||
313 | 326 | ||
314 | updateStamps :: Ord ni => Timestamp -> [ni] -> PSQ ni Timestamp -> PSQ ni Timestamp | 327 | updateStamps :: Ord ni => Timestamp -> [ni] -> PSQ ni Timestamp -> PSQ ni Timestamp |
@@ -335,12 +348,12 @@ partitionQ imp test q0 = do | |||
335 | 348 | ||
336 | 349 | ||
337 | split :: -- ( Eq ip , Ord (NodeId) , FiniteBits (NodeId)) => | 350 | split :: -- ( Eq ip , Ord (NodeId) , FiniteBits (NodeId)) => |
338 | forall ni. Ord ni => | 351 | forall ni s. ( Reifies s (Compare ni) ) => |
339 | (ni -> Word -> Bool) | 352 | (ni -> Word -> Bool) |
340 | -> BitIx -> Bucket ni -> (Bucket ni, Bucket ni) | 353 | -> BitIx -> Bucket s ni -> (Bucket s ni, Bucket s ni) |
341 | split testNodeIdBit i b = (Bucket ns qs, Bucket ms rs) | 354 | split testNodeIdBit i b = (Bucket ns qs, Bucket ms rs) |
342 | where | 355 | where |
343 | (ns,ms) = (PSQ.fromList *** PSQ.fromList) . partition (spanBit . key) . PSQ.toList $ bktNodes b | 356 | (ns,ms) = (PSQ.fromList *** PSQ.fromList) . partition (spanBit . coerce . key) . PSQ.toList $ bktNodes b |
344 | (qs,rs) = runIdentity $ partitionQ bucketQ (spanBit . snd) $ bktQ b | 357 | (qs,rs) = runIdentity $ partitionQ bucketQ (spanBit . snd) $ bktQ b |
345 | 358 | ||
346 | spanBit :: ni -> Bool | 359 | spanBit :: ni -> Bool |
@@ -382,11 +395,23 @@ deriving instance (Show ni, Show nid) => Show (Info ni nid) | |||
382 | -- is always split into two new buckets covering the ranges @0..2 ^ | 395 | -- is always split into two new buckets covering the ranges @0..2 ^ |
383 | -- 159@ and @2 ^ 159..2 ^ 160@. | 396 | -- 159@ and @2 ^ 159..2 ^ 160@. |
384 | -- | 397 | -- |
385 | data BucketList ni = BucketList !ni !Int ![Bucket ni] | 398 | data BucketList ni = forall s. Reifies s (Compare ni) => |
386 | deriving Generic | 399 | BucketList { thisNode :: !ni |
387 | 400 | , bktCount :: !Int | |
388 | mapTable :: Ord ni => (a -> ni) -> BucketList a -> BucketList ni | 401 | -- | Non-empty list of buckets. |
389 | mapTable f (BucketList self n bs) = BucketList (f self) n (map (mapBucket f) bs) | 402 | , buckets :: [Bucket s ni] |
403 | } | ||
404 | |||
405 | mapTable :: (b -> t) -> (t -> b) -> BucketList t -> BucketList b | ||
406 | mapTable g f tbl@(BucketList self n bkts) = reify (contramapC g $ bucketCompare bkts) | ||
407 | $ \p -> BucketList | ||
408 | { thisNode = f self | ||
409 | , bktCount = n | ||
410 | , buckets = map (resolve p . mapBucket f) bkts | ||
411 | } | ||
412 | where | ||
413 | resolve :: Proxy s -> Bucket s ni -> Bucket s ni | ||
414 | resolve = const id | ||
390 | 415 | ||
391 | instance (Eq ni) => Eq (BucketList ni) where | 416 | instance (Eq ni) => Eq (BucketList ni) where |
392 | (==) = (==) `on` Network.DHT.Routing.toList | 417 | (==) = (==) `on` Network.DHT.Routing.toList |
@@ -422,14 +447,19 @@ instance Pretty (BucketList ni) where | |||
422 | ss = shape t | 447 | ss = shape t |
423 | 448 | ||
424 | -- | Empty table with specified /spine/ node id. | 449 | -- | Empty table with specified /spine/ node id. |
425 | nullTable :: ni -> Int -> BucketList ni | 450 | nullTable :: (ni -> ni -> Ordering) -> ni -> Int -> BucketList ni |
426 | nullTable ni n = BucketList | 451 | nullTable cmp ni n = |
452 | reify (Compare cmp) | ||
453 | $ \p -> BucketList | ||
427 | ni | 454 | ni |
428 | (bucketCount (pred n)) | 455 | (bucketCount (pred n)) |
429 | [Bucket PSQ.empty (runIdentity $ emptyQueue bucketQ)] | 456 | [Bucket (empty p) (runIdentity $ emptyQueue bucketQ)] |
430 | where | 457 | where |
431 | bucketCount x = max 0 (min 159 x) | 458 | bucketCount x = max 0 (min 159 x) |
432 | 459 | ||
460 | empty :: Proxy s -> PSQ (p s ni) t | ||
461 | empty = const $ PSQ.empty | ||
462 | |||
433 | #if 0 | 463 | #if 0 |
434 | 464 | ||
435 | -- | Test if table is empty. In this case DHT should start | 465 | -- | Test if table is empty. In this case DHT should start |
@@ -459,7 +489,7 @@ type NodeCount = Int | |||
459 | -- | Internally, routing table is similar to list of buckets or a | 489 | -- | Internally, routing table is similar to list of buckets or a |
460 | -- /matrix/ of nodes. This function returns the shape of the matrix. | 490 | -- /matrix/ of nodes. This function returns the shape of the matrix. |
461 | shape :: BucketList ni -> [Int] | 491 | shape :: BucketList ni -> [Int] |
462 | shape = map (PSQ.size . bktNodes) . buckets | 492 | shape (BucketList _ _ tbl) = map (PSQ.size . bktNodes) tbl |
463 | 493 | ||
464 | #if 0 | 494 | #if 0 |
465 | 495 | ||
@@ -473,16 +503,18 @@ depth = L.length . shape | |||
473 | 503 | ||
474 | #endif | 504 | #endif |
475 | 505 | ||
476 | lookupBucket :: ( FiniteBits nid | 506 | lookupBucket :: forall ni nid x. |
507 | ( FiniteBits nid | ||
477 | , Ord nid | 508 | , Ord nid |
478 | ) => (ni -> nid) -> nid -> BucketList ni -> [Bucket ni] | 509 | ) => (ni -> nid) -> nid -> (forall s. [Bucket s ni] -> x) -> BucketList ni -> x |
479 | lookupBucket nodeId nid (BucketList self _ bkts) = go 0 [] bkts | 510 | lookupBucket nodeId nid kont (BucketList self _ bkts) = kont $ go 0 [] bkts |
480 | where | 511 | where |
481 | d = complement (nid `xor` nodeId self) | 512 | d = nid `xor` nodeId self |
482 | 513 | ||
514 | go :: Word -> [Bucket s ni] -> [Bucket s ni] -> [Bucket s ni] | ||
483 | go i bs (bucket : buckets) | 515 | go i bs (bucket : buckets) |
484 | | testIdBit d i = bucket : buckets ++ bs | 516 | | testIdBit d i = go (succ i) (bucket:bs) buckets |
485 | | otherwise = go (succ i) (bucket:bs) buckets | 517 | | otherwise = bucket : buckets ++ bs |
486 | go _ bs [] = bs | 518 | go _ bs [] = bs |
487 | 519 | ||
488 | 520 | ||
@@ -563,8 +595,7 @@ kclosest nodeId k nid tbl = take k $ rank nodeId nid (L.concat bucket) | |||
563 | where | 595 | where |
564 | (bucket,everyone) = | 596 | (bucket,everyone) = |
565 | L.splitAt 1 | 597 | L.splitAt 1 |
566 | . L.map (L.map PSQ.key . PSQ.toList . bktNodes) | 598 | . lookupBucket nodeId nid (L.map (coerce . L.map PSQ.key . PSQ.toList . bktNodes)) |
567 | . lookupBucket nodeId nid | ||
568 | $ tbl | 599 | $ tbl |
569 | 600 | ||
570 | 601 | ||
@@ -574,9 +605,9 @@ kclosest nodeId k nid tbl = take k $ rank nodeId nid (L.concat bucket) | |||
574 | -----------------------------------------------------------------------} | 605 | -----------------------------------------------------------------------} |
575 | 606 | ||
576 | splitTip :: -- ( Eq ip , Ord (NodeId) , FiniteBits (NodeId)) => | 607 | splitTip :: -- ( Eq ip , Ord (NodeId) , FiniteBits (NodeId)) => |
577 | Ord ni => | 608 | ( Reifies s (Compare ni) ) => |
578 | (ni -> Word -> Bool) | 609 | (ni -> Word -> Bool) |
579 | -> ni -> Int -> BitIx -> Bucket ni -> [ Bucket ni ] | 610 | -> ni -> Int -> BitIx -> Bucket s ni -> [ Bucket s ni ] |
580 | splitTip testNodeBit ni n i bucket | 611 | splitTip testNodeBit ni n i bucket |
581 | | testNodeBit ni i = [zeros , ones ] | 612 | | testNodeBit ni i = [zeros , ones ] |
582 | | otherwise = [ones , zeros ] | 613 | | otherwise = [ones , zeros ] |
@@ -590,25 +621,24 @@ splitTip testNodeBit ni n i bucket | |||
590 | -- paper. The rule requiring additional splits is in section 2.4. | 621 | -- paper. The rule requiring additional splits is in section 2.4. |
591 | modifyBucket | 622 | modifyBucket |
592 | :: -- ( Eq ip , Ord (NodeId) , FiniteBits (NodeId)) => | 623 | :: -- ( Eq ip , Ord (NodeId) , FiniteBits (NodeId)) => |
593 | forall ni nid xs. (Ord ni, Bits nid) => | 624 | forall ni nid xs. |
594 | (nid -> Word -> Bool) | 625 | KademliaSpace nid ni |
595 | -> (ni -> nid) | 626 | -> nid -> (forall s. Reifies s (Compare ni) => Bucket s ni -> Maybe (xs, Bucket s ni)) -> BucketList ni -> Maybe (xs,BucketList ni) |
596 | -> nid -> (Bucket ni -> Maybe (xs, Bucket ni)) -> BucketList ni -> Maybe (xs,BucketList ni) | 627 | modifyBucket space nid f (BucketList self n bkts) |
597 | modifyBucket testIdBit nodeId nid f (BucketList self n bkts) | ||
598 | = second (BucketList self n) <$> go (0 :: BitIx) bkts | 628 | = second (BucketList self n) <$> go (0 :: BitIx) bkts |
599 | where | 629 | where |
600 | d = nid `xor` nodeId self | 630 | d = kademliaXor space nid (kademliaLocation space self) |
601 | 631 | ||
602 | go :: BitIx -> [Bucket ni] -> Maybe (xs, [Bucket ni]) | 632 | -- go :: BitIx -> [Bucket s ni] -> Maybe (xs, [Bucket s ni]) |
603 | 633 | ||
604 | go !i (bucket : buckets@(_:_)) | 634 | go !i (bucket : buckets@(_:_)) |
605 | | testIdBit d i = second (bucket :) <$> go (succ i) buckets | 635 | | kademliaTestBit space d i = second (bucket :) <$> go (succ i) buckets |
606 | | otherwise = second (: buckets) <$> f bucket | 636 | | otherwise = second (: buckets) <$> f bucket |
607 | 637 | ||
608 | go !i [bucket] | 638 | go !i [bucket] |
609 | | (n == 0) = second (: []) <$> f bucket | 639 | | (n == 0) = second (: []) <$> f bucket |
610 | | otherwise = second (: []) <$> f bucket | 640 | | otherwise = second (: []) <$> f bucket |
611 | <|> go i (splitTip (testIdBit . nodeId) self n i bucket) | 641 | <|> go i (splitTip (kademliaTestBit space . kademliaLocation space) self n i bucket) |
612 | 642 | ||
613 | 643 | ||
614 | -- | Triggering event for atomic table update | 644 | -- | Triggering event for atomic table update |
@@ -655,13 +685,12 @@ deriving instance ( Show ip | |||
655 | -- | 685 | -- |
656 | -- [ /tbl'/ ] The updated routing 'BucketList'. | 686 | -- [ /tbl'/ ] The updated routing 'BucketList'. |
657 | -- | 687 | -- |
658 | updateForInbound :: (Ord ni, Bits nid) => | 688 | updateForInbound :: |
659 | KademliaSpace nid ni | 689 | KademliaSpace nid ni |
660 | -> Timestamp -> ni -> BucketList ni -> (Bool, [ni], BucketList ni) | 690 | -> Timestamp -> ni -> BucketList ni -> (Bool, [ni], BucketList ni) |
661 | updateForInbound space tm ni tbl = | 691 | updateForInbound space tm ni tbl@(BucketList _ _ bkts) = |
662 | maybe (False, [],tbl) (\(ps,tbl') -> (True, ps, tbl')) | 692 | maybe (False, [],tbl) (\(ps,tbl') -> (True, ps, tbl')) |
663 | $ modifyBucket (kademliaTestBit space) | 693 | $ modifyBucket space |
664 | (kademliaLocation space) | ||
665 | (kademliaLocation space ni) | 694 | (kademliaLocation space ni) |
666 | (updateBucketForInbound tm ni) | 695 | (updateBucketForInbound tm ni) |
667 | tbl | 696 | tbl |
@@ -670,16 +699,15 @@ updateForInbound space tm ni tbl = | |||
670 | -- | 699 | -- |
671 | -- Each (a,(tm,b)) in the returned list indicates that the node /a/ was deleted from the | 700 | -- Each (a,(tm,b)) in the returned list indicates that the node /a/ was deleted from the |
672 | -- routing table and the node /b/, with timestamp /tm/, has taken its place. | 701 | -- routing table and the node /b/, with timestamp /tm/, has taken its place. |
673 | updateForPingResult :: (Ord ni, Bits nid) => | 702 | updateForPingResult :: |
674 | KademliaSpace nid ni | 703 | KademliaSpace nid ni |
675 | -> ni -- ^ The pinged node. | 704 | -> ni -- ^ The pinged node. |
676 | -> Bool -- ^ True if we got a reply, False if it timed out. | 705 | -> Bool -- ^ True if we got a reply, False if it timed out. |
677 | -> BucketList ni -- ^ The routing table. | 706 | -> BucketList ni -- ^ The routing table. |
678 | -> ( [(ni,(Timestamp, ni))], BucketList ni ) | 707 | -> ( [(ni,(Timestamp, ni))], BucketList ni ) |
679 | updateForPingResult space ni got_reply tbl = | 708 | updateForPingResult space ni got_reply tbl = |
680 | fromMaybe ([],tbl) | 709 | fromMaybe ([],tbl) |
681 | $ modifyBucket (kademliaTestBit space) | 710 | $ modifyBucket space |
682 | (kademliaLocation space) | ||
683 | (kademliaLocation space ni) | 711 | (kademliaLocation space ni) |
684 | (updateBucketForPingResult ni got_reply) | 712 | (updateBucketForPingResult ni got_reply) |
685 | tbl | 713 | tbl |
@@ -694,12 +722,8 @@ type TableEntry ni = (ni, Timestamp) | |||
694 | tableEntry :: NodeEntry ni -> TableEntry ni | 722 | tableEntry :: NodeEntry ni -> TableEntry ni |
695 | tableEntry (a :-> b) = (a, b) | 723 | tableEntry (a :-> b) = (a, b) |
696 | 724 | ||
697 | -- | Non-empty list of buckets. | ||
698 | buckets :: BucketList ni -> [Bucket ni] | ||
699 | buckets (BucketList _ _ bs) = bs | ||
700 | |||
701 | toList :: BucketList ni -> [[TableEntry ni]] | 725 | toList :: BucketList ni -> [[TableEntry ni]] |
702 | toList = L.map (L.map tableEntry . PSQ.toList . bktNodes) . buckets | 726 | toList (BucketList _ _ bkts) = coerce $ L.map (L.map tableEntry . PSQ.toList . bktNodes) bkts |
703 | 727 | ||
704 | data KademliaSpace nid ni = KademliaSpace | 728 | data KademliaSpace nid ni = KademliaSpace |
705 | { -- | Given a node record (probably including IP address), yields a | 729 | { -- | Given a node record (probably including IP address), yields a |
@@ -709,6 +733,8 @@ data KademliaSpace nid ni = KademliaSpace | |||
709 | -- 'Data.Bits.testBit' except that the ordering of bits is reversed, so | 733 | -- 'Data.Bits.testBit' except that the ordering of bits is reversed, so |
710 | -- that 0 is the most significant bit. | 734 | -- that 0 is the most significant bit. |
711 | , kademliaTestBit :: nid -> Word -> Bool | 735 | , kademliaTestBit :: nid -> Word -> Bool |
736 | -- | The Kademlia xor-metric. | ||
737 | , kademliaXor :: nid -> nid -> nid | ||
712 | } | 738 | } |
713 | 739 | ||
714 | contramapKS f ks = ks | 740 | contramapKS f ks = ks |