-
Notifications
You must be signed in to change notification settings - Fork 445
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: track closest peers separately from main routing table (#2748)
The routing table is a balance trie where the path to the leaf node storing the contact is derived from the prefix of the kad id of the contact. This makes it great for starting a query because we can quickly find contacts in the kad-vicinity of the target, but it's less good for knowing peers that are in our kad-vicinity, since the bits that make us kad-close to another peer might not be in the prefix. Instead, use a peer distance list that we update whenever a peer successfully completes a `PING` operation. Periodically check this list and tag the closes peers with `KEEP_ALIVE` so we maintain connections to them, which will ensure we propagate changes in our PeerInfo to those peers most likely to answer `FIND_PEER` queries for our data.
- Loading branch information
1 parent
661d658
commit 27b2fa6
Showing
10 changed files
with
308 additions
and
213 deletions.
There are no files selected for viewing
2 changes: 1 addition & 1 deletion
2
...d-dht/src/peer-list/peer-distance-list.ts → packages/kad-dht/src/peer-distance-list.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import { KEEP_ALIVE } from '@libp2p/interface' | ||
import { PeerSet } from '@libp2p/peer-collections' | ||
import { PeerDistanceList } from '../peer-distance-list.js' | ||
import { convertPeerId } from '../utils.js' | ||
import type { RoutingTable } from './index.js' | ||
import type { ComponentLogger, Logger, Metrics, PeerId, PeerStore, Startable } from '@libp2p/interface' | ||
|
||
export const PEER_SET_SIZE = 20 | ||
export const REFRESH_INTERVAL = 5000 | ||
export const KAD_CLOSE_TAG_NAME = 'kad-close' | ||
export const KAD_CLOSE_TAG_VALUE = 50 | ||
|
||
export interface ClosestPeersInit { | ||
logPrefix: string | ||
routingTable: RoutingTable | ||
peerSetSize?: number | ||
refreshInterval?: number | ||
closeTagName?: string | ||
closeTagValue?: number | ||
} | ||
|
||
export interface ClosestPeersComponents { | ||
peerId: PeerId | ||
peerStore: PeerStore | ||
metrics?: Metrics | ||
logger: ComponentLogger | ||
} | ||
|
||
/** | ||
* Contains a list of the kad-closest peers encountered on the network. | ||
* | ||
* Once every few seconds, if the list has changed, it tags the closest peers. | ||
*/ | ||
export class ClosestPeers implements Startable { | ||
private readonly routingTable: RoutingTable | ||
private readonly components: ClosestPeersComponents | ||
private closestPeers: PeerSet | ||
private newPeers?: PeerDistanceList | ||
private readonly refreshInterval: number | ||
private readonly peerSetSize: number | ||
private timeout?: ReturnType<typeof setTimeout> | ||
private readonly closeTagName: string | ||
private readonly closeTagValue: number | ||
private readonly log: Logger | ||
|
||
constructor (components: ClosestPeersComponents, init: ClosestPeersInit) { | ||
this.components = components | ||
this.log = components.logger.forComponent(`${init.logPrefix}:routing-table`) | ||
this.routingTable = init.routingTable | ||
this.refreshInterval = init.refreshInterval ?? REFRESH_INTERVAL | ||
this.peerSetSize = init.peerSetSize ?? PEER_SET_SIZE | ||
this.closeTagName = init.closeTagName ?? KAD_CLOSE_TAG_NAME | ||
this.closeTagValue = init.closeTagValue ?? KAD_CLOSE_TAG_VALUE | ||
|
||
this.closestPeers = new PeerSet() | ||
this.onPeerPing = this.onPeerPing.bind(this) | ||
} | ||
|
||
async start (): Promise<void> { | ||
const targetKadId = await convertPeerId(this.components.peerId) | ||
this.newPeers = new PeerDistanceList(targetKadId, this.peerSetSize) | ||
this.routingTable.addEventListener('peer:ping', this.onPeerPing) | ||
|
||
this.timeout = setInterval(() => { | ||
this.updatePeerTags() | ||
.catch(err => { | ||
this.log.error('error updating peer tags - %e', err) | ||
}) | ||
}, this.refreshInterval) | ||
} | ||
|
||
stop (): void { | ||
this.routingTable.removeEventListener('peer:ping', this.onPeerPing) | ||
clearTimeout(this.timeout) | ||
} | ||
|
||
onPeerPing (event: CustomEvent<PeerId>): void { | ||
this.newPeers?.add({ id: event.detail, multiaddrs: [] }) | ||
.catch(err => { | ||
this.log.error('error adding peer to distance list - %e', err) | ||
}) | ||
} | ||
|
||
async updatePeerTags (): Promise<void> { | ||
const newClosest = new PeerSet(this.newPeers?.peers.map(peer => peer.id)) | ||
const added = newClosest.difference(this.closestPeers) | ||
const removed = this.closestPeers.difference(newClosest) | ||
this.closestPeers = newClosest | ||
|
||
await Promise.all([ | ||
...[...added].map(async peerId => { | ||
await this.components.peerStore.merge(peerId, { | ||
tags: { | ||
[this.closeTagName]: { | ||
value: this.closeTagValue | ||
}, | ||
[KEEP_ALIVE]: { | ||
value: 1 | ||
} | ||
} | ||
}) | ||
}), | ||
...[...removed].map(async peerId => { | ||
await this.components.peerStore.merge(peerId, { | ||
tags: { | ||
[this.closeTagName]: undefined, | ||
[KEEP_ALIVE]: undefined | ||
} | ||
}) | ||
}) | ||
]) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.