Skip to content

Commit d1ff510

Browse files
committed
feat: add routing field to providers (#3340)
To better debug which routing system supplied a given provider, add a string field to the return type of `findProviders` which allows this information to be reported.
1 parent 7394509 commit d1ff510

File tree

10 files changed

+134
-56
lines changed

10 files changed

+134
-56
lines changed

packages/integration-tests/test/fixtures/utils.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Circuit } from '@multiformats/multiaddr-matcher'
55
import { detect } from 'detect-browser'
66
import pWaitFor from 'p-wait-for'
77
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
8-
import type { Libp2p, AbortOptions, ContentRouting, PeerId, PeerInfo } from '@libp2p/interface'
8+
import type { Libp2p, AbortOptions, ContentRouting, PeerId, Provider } from '@libp2p/interface'
99
import type { AddressManager } from '@libp2p/interface-internal'
1010
import type { Multiaddr } from '@multiformats/multiaddr'
1111
import type { CID, Version } from 'multiformats'
@@ -153,7 +153,7 @@ export interface MockContentRoutingComponents {
153153
}
154154

155155
export class MockContentRouting implements ContentRouting {
156-
static providers = new Map<string, PeerInfo[]>()
156+
static providers = new Map<string, Provider[]>()
157157
static data = new Map<string, Uint8Array>()
158158

159159
static reset (): void {
@@ -175,7 +175,8 @@ export class MockContentRouting implements ContentRouting {
175175

176176
providers.push({
177177
id: this.peerId,
178-
multiaddrs: this.addressManager.getAddresses()
178+
multiaddrs: this.addressManager.getAddresses(),
179+
routing: 'mock-content-routing'
179180
})
180181

181182
MockContentRouting.providers.set(cid.toString(), providers)
@@ -185,7 +186,7 @@ export class MockContentRouting implements ContentRouting {
185186

186187
}
187188

188-
async * findProviders (cid: CID<unknown, number, number, Version>, options?: AbortOptions | undefined): AsyncGenerator<PeerInfo, void, undefined> {
189+
async * findProviders (cid: CID<unknown, number, number, Version>, options?: AbortOptions | undefined): AsyncGenerator<Provider, void, undefined> {
189190
yield * MockContentRouting.providers.get(cid.toString()) ?? []
190191
}
191192

packages/interface/src/content-routing.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@ import type { RoutingOptions } from './index.js'
22
import type { PeerInfo } from './peer-info.js'
33
import type { CID } from 'multiformats/cid'
44

5+
export interface Provider extends PeerInfo {
6+
/**
7+
* Which routing subsystem found the provider
8+
*/
9+
routing: string
10+
}
11+
512
/**
613
* Any object that implements this Symbol as a property should return a
714
* Partial<ContentRouting> instance as the property value, similar to how
@@ -64,7 +71,7 @@ export interface ContentRouting {
6471
* }
6572
* ```
6673
*/
67-
findProviders(cid: CID, options?: RoutingOptions): AsyncIterable<PeerInfo>
74+
findProviders(cid: CID, options?: RoutingOptions): AsyncIterable<Provider>
6875

6976
/**
7077
* Puts a value corresponding to the passed key in a way that can later be

packages/kad-dht/src/kad-dht.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {
2424
timeOperationGenerator
2525
} from './utils.js'
2626
import type { KadDHTComponents, KadDHTInit, Validators, Selectors, KadDHT as KadDHTInterface, QueryEvent, PeerInfoMapper, SetModeOptions } from './index.js'
27-
import type { ContentRouting, CounterGroup, Logger, MetricGroup, PeerDiscovery, PeerDiscoveryEvents, PeerId, PeerInfo, PeerRouting, RoutingOptions, Startable } from '@libp2p/interface'
27+
import type { ContentRouting, CounterGroup, Logger, MetricGroup, PeerDiscovery, PeerDiscoveryEvents, PeerId, PeerInfo, PeerRouting, Provider, RoutingOptions, Startable } from '@libp2p/interface'
2828
import type { AbortOptions } from 'it-pushable'
2929
import type { CID } from 'multiformats/cid'
3030

@@ -46,10 +46,13 @@ class DHTContentRouting implements ContentRouting {
4646
await this.dht.cancelReprovide(key)
4747
}
4848

49-
async * findProviders (cid: CID, options: RoutingOptions = {}): AsyncGenerator<PeerInfo, void, undefined> {
49+
async * findProviders (cid: CID, options: RoutingOptions = {}): AsyncGenerator<Provider, void, undefined> {
5050
for await (const event of this.dht.findProviders(cid, options)) {
5151
if (event.name === 'PROVIDER') {
52-
yield * event.providers
52+
yield * event.providers.map(peer => ({
53+
...peer,
54+
routing: 'kad-dht'
55+
}))
5356
}
5457
}
5558
}

packages/libp2p/src/connection-manager/dial-queue.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,8 +515,8 @@ export class DialQueue {
515515
}
516516

517517
return true
518-
} catch (err) {
519-
this.log.trace('error calculating if multiaddr(s) were dialable', err)
518+
} catch {
519+
520520
}
521521

522522
return false

packages/libp2p/src/content-routing.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { PeerSet } from '@libp2p/peer-collections'
33
import merge from 'it-merge'
44
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
55
import { NoContentRoutersError } from './errors.js'
6-
import type { AbortOptions, ComponentLogger, ContentRouting, Metrics, PeerInfo, PeerRouting, PeerStore, RoutingOptions, Startable } from '@libp2p/interface'
6+
import type { AbortOptions, ComponentLogger, ContentRouting, Metrics, PeerRouting, PeerStore, Provider, RoutingOptions, Startable } from '@libp2p/interface'
77
import type { CID } from 'multiformats/cid'
88

99
export interface CompoundContentRoutingInit {
@@ -95,7 +95,7 @@ export class CompoundContentRouting implements ContentRouting, Startable {
9595
/**
9696
* Iterates over all content routers in parallel to find providers of the given key
9797
*/
98-
async * findProviders (key: CID, options: RoutingOptions = {}): AsyncGenerator<PeerInfo> {
98+
async * findProviders (key: CID, options: RoutingOptions = {}): AsyncGenerator<Provider> {
9999
if (this.routers.length === 0) {
100100
throw new NoContentRoutersError('No content routers available')
101101
}

packages/libp2p/test/content-routing/content-routing.spec.ts

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import sinon from 'sinon'
1313
import { stubInterface } from 'sinon-ts'
1414
import { createLibp2p } from '../../src/index.js'
1515
import type { Libp2p } from '../../src/index.js'
16-
import type { ContentRouting, PeerInfo } from '@libp2p/interface'
16+
import type { ContentRouting, Provider } from '@libp2p/interface'
1717
import type { StubbedInstance } from 'sinon-ts'
1818

1919
describe('content-routing', () => {
@@ -87,7 +87,8 @@ describe('content-routing', () => {
8787
id: peerIdFromPrivateKey(await generateKeyPair('Ed25519')),
8888
multiaddrs: [
8989
multiaddr('/ip4/123.123.123.123/tcp/4001')
90-
]
90+
],
91+
routing: 'test'
9192
}
9293
deferred.resolve()
9394
})
@@ -136,7 +137,8 @@ describe('content-routing', () => {
136137
delegate.findProviders.returns(async function * () {
137138
yield {
138139
id: node.peerId,
139-
multiaddrs: []
140+
multiaddrs: [],
141+
routing: 'test'
140142
}
141143
deferred.resolve()
142144
}())
@@ -173,7 +175,8 @@ describe('content-routing', () => {
173175
id: peerIdFromString(provider),
174176
multiaddrs: [
175177
multiaddr('/ip4/0.0.0.0/tcp/0')
176-
]
178+
],
179+
routing: 'test'
177180
}
178181
}())
179182

@@ -224,11 +227,12 @@ describe('content-routing', () => {
224227

225228
it('should store the multiaddrs of a peer', async () => {
226229
const providerPeerId = peerIdFromPrivateKey(await generateKeyPair('Ed25519'))
227-
const result: PeerInfo = {
230+
const result: Provider = {
228231
id: providerPeerId,
229232
multiaddrs: [
230233
multiaddr('/ip4/123.123.123.123/tcp/49320')
231-
]
234+
],
235+
routing: 'test'
232236
}
233237

234238
router.findProviders.callsFake(async function * () {})
@@ -252,7 +256,8 @@ describe('content-routing', () => {
252256
id: providerPeerId,
253257
multiaddrs: [
254258
multiaddr('/ip4/123.123.123.123/tcp/49320')
255-
]
259+
],
260+
routing: 'test'
256261
}
257262

258263
const defer = pDefer()
@@ -278,7 +283,8 @@ describe('content-routing', () => {
278283
id: providerPeerId,
279284
multiaddrs: [
280285
multiaddr('/ip4/123.123.123.123/tcp/49320')
281-
]
286+
],
287+
routing: 'test'
282288
}
283289

284290
router.findProviders.callsFake(async function * () {
@@ -299,13 +305,15 @@ describe('content-routing', () => {
299305
id: providerPeerId,
300306
multiaddrs: [
301307
multiaddr('/ip4/123.123.123.123/tcp/49320')
302-
]
308+
],
309+
routing: 'test'
303310
}
304311
const result2 = {
305312
id: providerPeerId,
306313
multiaddrs: [
307314
multiaddr('/ip4/213.213.213.213/tcp/2344')
308-
]
315+
],
316+
routing: 'test'
309317
}
310318

311319
router.findProviders.callsFake(async function * () {
@@ -352,7 +360,8 @@ describe('content-routing', () => {
352360
id: providerPeerId,
353361
multiaddrs: [
354362
multiaddr('/ip4/123.123.123.123/tcp/2341')
355-
]
363+
],
364+
routing: 'test'
356365
}]
357366

358367
router.findProviders.callsFake(async function * () {
@@ -377,7 +386,8 @@ describe('content-routing', () => {
377386
id: providerPeerId,
378387
multiaddrs: [
379388
multiaddr('/ip4/123.123.123.123/tcp/2341')
380-
]
389+
],
390+
routing: 'test'
381391
}]
382392

383393
router.findProviders.callsFake(async function * () {})

packages/logger/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ function formatError (v: Error): string {
107107
}
108108

109109
function isAggregateError (err?: any): err is AggregateError {
110-
return err?.name === 'AggregateError'
110+
return err instanceof AggregateError || (err?.name === 'AggregateError' && Array.isArray(err.errors))
111111
}
112112

113113
// Add a formatter for stringifying Errors

packages/transport-circuit-relay-v2/test/utils.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Circuit } from '@multiformats/multiaddr-matcher'
44
import pWaitFor from 'p-wait-for'
55
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
66
import { RELAY_V2_HOP_CODEC } from '../../../packages/transport-circuit-relay-v2/src/constants.js'
7-
import type { Libp2p, AbortOptions, ContentRouting, PeerId, PeerInfo } from '@libp2p/interface'
7+
import type { Libp2p, AbortOptions, ContentRouting, PeerId, Provider } from '@libp2p/interface'
88
import type { AddressManager } from '@libp2p/interface-internal'
99
import type { Multiaddr } from '@multiformats/multiaddr'
1010
import type { CID, Version } from 'multiformats'
@@ -133,7 +133,7 @@ export interface MockContentRoutingComponents {
133133
}
134134

135135
export class MockContentRouting implements ContentRouting {
136-
static providers = new Map<string, PeerInfo[]>()
136+
static providers = new Map<string, Provider[]>()
137137
static data = new Map<string, Uint8Array>()
138138

139139
static reset (): void {
@@ -155,7 +155,8 @@ export class MockContentRouting implements ContentRouting {
155155

156156
providers.push({
157157
id: this.peerId,
158-
multiaddrs: this.addressManager.getAddresses()
158+
multiaddrs: this.addressManager.getAddresses(),
159+
routing: 'mock-content-routing'
159160
})
160161

161162
MockContentRouting.providers.set(cid.toString(), providers)
@@ -165,7 +166,7 @@ export class MockContentRouting implements ContentRouting {
165166

166167
}
167168

168-
async * findProviders (cid: CID<unknown, number, number, Version>, options?: AbortOptions | undefined): AsyncGenerator<PeerInfo, void, undefined> {
169+
async * findProviders (cid: CID<unknown, number, number, Version>, options?: AbortOptions | undefined): AsyncGenerator<Provider, void, undefined> {
169170
yield * MockContentRouting.providers.get(cid.toString()) ?? []
170171
}
171172

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,32 @@
11
-----BEGIN CERTIFICATE-----
2-
MIICATCCAWoCCQDPufXH86n2QzANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJu
3-
bzETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
4-
cyBQdHkgTHRkMB4XDTEyMDEwMTE0NDQwMFoXDTIwMDMxOTE0NDQwMFowRTELMAkG
5-
A1UEBhMCbm8xEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0
6-
IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtrQ7
7-
+r//2iV/B6F+4boH0XqFn7alcV9lpjvAmwRXNKnxAoa0f97AjYPGNLKrjpkNXXhB
8-
JROIdbRbZnCNeC5fzX1a+JCo7KStzBXuGSZr27TtFmcV4H+9gIRIcNHtZmJLnxbJ
9-
sIhkGR8yVYdmJZe4eT5ldk1zoB1adgPF1hZhCBMCAwEAATANBgkqhkiG9w0BAQUF
10-
AAOBgQCeWBEHYJ4mCB5McwSSUox0T+/mJ4W48L/ZUE4LtRhHasU9hiW92xZkTa7E
11-
QLcoJKQiWfiLX2ysAro0NX4+V8iqLziMqvswnPzz5nezaOLE/9U/QvH3l8qqNkXu
12-
rNbsW1h/IO6FV8avWFYVFoutUwOaZ809k7iMh2F2JMgXQ5EymQ==
13-
-----END CERTIFICATE-----
2+
MIIFmTCCA4GgAwIBAgIUUx38wmpfZkoEknHx536f2klvD5IwDQYJKoZIhvcNAQEL
3+
BQAwXDELMAkGA1UEBhMCTm8xETAPBgNVBAgMCE5vbmVzdWNoMREwDwYDVQQHDAhO
4+
b25lc3VjaDETMBEGA1UECgwKU0VMRlNJR05FRDESMBAGA1UEAwwJbG9jYWxob3N0
5+
MB4XDTI1MTAyOTA4MDgxN1oXDTM1MTAyNzA4MDgxN1owXDELMAkGA1UEBhMCTm8x
6+
ETAPBgNVBAgMCE5vbmVzdWNoMREwDwYDVQQHDAhOb25lc3VjaDETMBEGA1UECgwK
7+
U0VMRlNJR05FRDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF
8+
AAOCAg8AMIICCgKCAgEAwi16U+e7H1SBM0KHcfrn9e6FfhS3TMP794vS0xcF3R7N
9+
5/kFR2dcO+uyTrJNjx22mkhUHsmTkYXam0j1RVPcrh4avSBRpBZabWu+krb7a9hf
10+
tZU8mk/99/EqRoBNHnGaaYmyEt6yBOo2pWRLXf09IfwWaSfregIXKETrfZtaEjGK
11+
Kq78cCQDunvbXmWy7+oitr8yOM2mIHsBvGeL32/AMwwzqz5RY2i1Ecay5cNv2dxv
12+
3pDxM/xwzghLTKNVPMzRyfy6xxv3lFi3JW6dECnaJ9lJjJROPXwAUr2U6rlouyeq
13+
C8XomtE9KRR1cWXNVrLIVH5s0lTIw+tLp8IT0gRS0SHMskINu867/3MYt9OCPO34
14+
Frz8qZFz0fEE5Mm0SC8v7mzPW5Kv36K2HQ+a6UQDT3fsUeGbUwdDrvy22ccrN517
15+
IXSL0lZ4PXsSD1gqsaWpVf4QNJAuaCLliXuY9M5u0JRykLDCfcCBAPhD+fXhLPCH
16+
95TFejSaOLEE7EJSb4P/+YfYinfjkuP5lljl7I+Az9FXUa7apIwTMUnWXx9z4JU1
17+
e3BdDRIBJei/wXdwQuKvREPVkFz4BRvdsUirWWXJOjcI7rhu9HImrke/chTI4322
18+
dykOoIpcTj8QyMDW02fMPfMiQ9DTRBoEXJJn/sRM4GOlWgAwqYne9xohraSrvj0C
19+
AwEAAaNTMFEwHQYDVR0OBBYEFNkJUT6m7NlsGbTscuXyVwohKgwwMB8GA1UdIwQY
20+
MBaAFNkJUT6m7NlsGbTscuXyVwohKgwwMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
21+
hvcNAQELBQADggIBAAq2DTXsVCisQlou498arum056CCGBxO3bXIYrFHrNFb9JaV
22+
Mjs7dFm8DbGrGSGUFsmlx2v+m35SQdvBsUV/8DMgNmqK+nQ1oP5Kp+Gg9EK/8ltk
23+
LYb2eeymOf8JHrl9quGEf92fBTTwMu3Z4P7HeBGJBrOA24E1Ubqt3OC+4nfnItnG
24+
AgKZsTzf2piAhmLvTAuktarVBXSSerG7E9QW//clot7JRP64H1SAozlMRzkNwBAl
25+
0+TVmBQ6NisOhqz27nvOZKECVyqEXkqtsB8DhEbNRH/182X/5gRj40/KNnw3Ivaw
26+
cTzTUVqx2Wo3SPviJnoJcFiR2ZLee6HmfzDzWppef+Z4ZbJfiEtjiLmiO+uKynMJ
27+
Z3/pMNStFqEPPmiOoxl0+4Hspa0wREnxqjmYBovxVWl6kwwG/DyYv319TtEdc7tI
28+
+BUEN3Uthdv78cglLonJg9gi1TgkbdSn90jfVFA7jXJUUH9ZzfX8sBCocAAwgx8v
29+
QPKCOZoTxhETarvgmKXqI7LOLzJcRszwVOROFEZ13CXD1oJ8picHRrg9pokgmgG4
30+
8b64rsxKvEci3n3W7vhcP3POll6n2NDvp0mJQj+7lvTWr1XncE5BZJucsyknfjd7
31+
eBTVm9QaWEF4aciAg543JZ4oBh8MdMBLQfsolY/mh0GFcYOby4rs/InoR918
32+
-----END CERTIFICATE-----
Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,52 @@
1-
-----BEGIN RSA PRIVATE KEY-----
2-
MIICXAIBAAKBgQC2tDv6v//aJX8HoX7hugfReoWftqVxX2WmO8CbBFc0qfEChrR/
3-
3sCNg8Y0squOmQ1deEElE4h1tFtmcI14Ll/NfVr4kKjspK3MFe4ZJmvbtO0WZxXg
4-
f72AhEhw0e1mYkufFsmwiGQZHzJVh2Yll7h5PmV2TXOgHVp2A8XWFmEIEwIDAQAB
5-
AoGAAlVY8sHi/aE+9xT77twWX3mGHV0SzdjfDnly40fx6S1Gc7bOtVdd9DC7pk6l
6-
3ENeJVR02IlgU8iC5lMHq4JEHPE272jtPrLlrpWLTGmHEqoVFv9AITPqUDLhB9Kk
7-
Hjl7h8NYBKbr2JHKICr3DIPKOT+RnXVb1PD4EORbJ3ooYmkCQQDfknUnVxPgxUGs
8-
ouABw1WJIOVgcCY/IFt4Ihf6VWTsxBgzTJKxn3HtgvE0oqTH7V480XoH0QxHhjLq
9-
DrgobWU9AkEA0TRJ8/ouXGnFEPAXjWr9GdPQRZ1Use2MrFjneH2+Sxc0CmYtwwqL
10-
Kr5kS6mqJrxprJeluSjBd+3/ElxURrEXjwJAUvmlN1OPEhXDmRHd92mKnlkyKEeX
11-
OkiFCiIFKih1S5Y/sRJTQ0781nyJjtJqO7UyC3pnQu1oFEePL+UEniRztQJAMfav
12-
AtnpYKDSM+1jcp7uu9BemYGtzKDTTAYfoiNF42EzSJiGrWJDQn4eLgPjY0T0aAf/
13-
yGz3Z9ErbhMm/Ysl+QJBAL4kBxRT8gM4ByJw4sdOvSeCCANFq8fhbgm8pGWlCPb5
14-
JGmX3/GHFM8x2tbWMGpyZP1DLtiNEFz7eCGktWK5rqE=
15-
-----END RSA PRIVATE KEY-----
1+
-----BEGIN PRIVATE KEY-----
2+
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
51+
ToRWjMwnNJPLw5FsCHIOB9kiw+87N5I=
52+
-----END PRIVATE KEY-----

0 commit comments

Comments
 (0)