libp2p 0.42.2 → 0.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. package/README.md +4 -4
  2. package/dist/index.min.js +29 -29
  3. package/dist/src/address-manager/index.d.ts +1 -10
  4. package/dist/src/address-manager/index.d.ts.map +1 -1
  5. package/dist/src/address-manager/index.js +46 -29
  6. package/dist/src/address-manager/index.js.map +1 -1
  7. package/dist/src/autonat/constants.d.ts +4 -0
  8. package/dist/src/autonat/constants.d.ts.map +1 -0
  9. package/dist/src/autonat/constants.js +4 -0
  10. package/dist/src/autonat/constants.js.map +1 -0
  11. package/dist/src/autonat/index.d.ts +64 -0
  12. package/dist/src/autonat/index.d.ts.map +1 -0
  13. package/dist/src/autonat/index.js +417 -0
  14. package/dist/src/autonat/index.js.map +1 -0
  15. package/dist/src/autonat/pb/index.d.ts +57 -0
  16. package/dist/src/autonat/pb/index.d.ts.map +1 -0
  17. package/dist/src/autonat/pb/index.js +250 -0
  18. package/dist/src/autonat/pb/index.js.map +1 -0
  19. package/dist/src/circuit/constants.d.ts +31 -6
  20. package/dist/src/circuit/constants.d.ts.map +1 -1
  21. package/dist/src/circuit/constants.js +37 -7
  22. package/dist/src/circuit/constants.js.map +1 -1
  23. package/dist/src/circuit/index.d.ts +16 -61
  24. package/dist/src/circuit/index.d.ts.map +1 -1
  25. package/dist/src/circuit/index.js +2 -68
  26. package/dist/src/circuit/index.js.map +1 -1
  27. package/dist/src/circuit/pb/index.d.ts +83 -43
  28. package/dist/src/circuit/pb/index.d.ts.map +1 -1
  29. package/dist/src/circuit/pb/index.js +363 -127
  30. package/dist/src/circuit/pb/index.js.map +1 -1
  31. package/dist/src/circuit/server/advert-service.d.ts +43 -0
  32. package/dist/src/circuit/server/advert-service.d.ts.map +1 -0
  33. package/dist/src/circuit/server/advert-service.js +69 -0
  34. package/dist/src/circuit/server/advert-service.js.map +1 -0
  35. package/dist/src/circuit/server/index.d.ts +60 -0
  36. package/dist/src/circuit/server/index.d.ts.map +1 -0
  37. package/dist/src/circuit/server/index.js +287 -0
  38. package/dist/src/circuit/server/index.js.map +1 -0
  39. package/dist/src/circuit/server/reservation-store.d.ts +49 -0
  40. package/dist/src/circuit/server/reservation-store.d.ts.map +1 -0
  41. package/dist/src/circuit/server/reservation-store.js +57 -0
  42. package/dist/src/circuit/server/reservation-store.js.map +1 -0
  43. package/dist/src/circuit/server/reservation-voucher.d.ts +18 -0
  44. package/dist/src/circuit/server/reservation-voucher.d.ts.map +1 -0
  45. package/dist/src/circuit/server/reservation-voucher.js +33 -0
  46. package/dist/src/circuit/server/reservation-voucher.js.map +1 -0
  47. package/dist/src/circuit/transport/discovery.d.ts +45 -0
  48. package/dist/src/circuit/transport/discovery.d.ts.map +1 -0
  49. package/dist/src/circuit/transport/discovery.js +82 -0
  50. package/dist/src/circuit/transport/discovery.js.map +1 -0
  51. package/dist/src/circuit/transport/index.d.ts +33 -0
  52. package/dist/src/circuit/transport/index.d.ts.map +1 -0
  53. package/dist/src/circuit/transport/index.js +225 -0
  54. package/dist/src/circuit/transport/index.js.map +1 -0
  55. package/dist/src/circuit/transport/listener.d.ts +9 -0
  56. package/dist/src/circuit/transport/listener.d.ts.map +1 -0
  57. package/dist/src/circuit/transport/listener.js +76 -0
  58. package/dist/src/circuit/transport/listener.js.map +1 -0
  59. package/dist/src/circuit/transport/reservation-store.d.ts +60 -0
  60. package/dist/src/circuit/transport/reservation-store.d.ts.map +1 -0
  61. package/dist/src/circuit/transport/reservation-store.js +165 -0
  62. package/dist/src/circuit/transport/reservation-store.js.map +1 -0
  63. package/dist/src/circuit/utils.d.ts +7 -0
  64. package/dist/src/circuit/utils.d.ts.map +1 -1
  65. package/dist/src/circuit/utils.js +87 -0
  66. package/dist/src/circuit/utils.js.map +1 -1
  67. package/dist/src/components.d.ts +2 -1
  68. package/dist/src/components.d.ts.map +1 -1
  69. package/dist/src/components.js +13 -13
  70. package/dist/src/components.js.map +1 -1
  71. package/dist/src/config.d.ts.map +1 -1
  72. package/dist/src/config.js +21 -25
  73. package/dist/src/config.js.map +1 -1
  74. package/dist/src/connection/index.d.ts +2 -2
  75. package/dist/src/connection/index.d.ts.map +1 -1
  76. package/dist/src/connection/index.js +4 -4
  77. package/dist/src/connection/index.js.map +1 -1
  78. package/dist/src/connection-manager/auto-dialler.d.ts +0 -4
  79. package/dist/src/connection-manager/auto-dialler.d.ts.map +1 -1
  80. package/dist/src/connection-manager/auto-dialler.js +18 -18
  81. package/dist/src/connection-manager/auto-dialler.js.map +1 -1
  82. package/dist/src/connection-manager/dialer/dial-request.d.ts.map +1 -1
  83. package/dist/src/connection-manager/dialer/dial-request.js +13 -6
  84. package/dist/src/connection-manager/dialer/dial-request.js.map +1 -1
  85. package/dist/src/connection-manager/dialer/index.d.ts +10 -1
  86. package/dist/src/connection-manager/dialer/index.d.ts.map +1 -1
  87. package/dist/src/connection-manager/dialer/index.js +24 -9
  88. package/dist/src/connection-manager/dialer/index.js.map +1 -1
  89. package/dist/src/connection-manager/index.d.ts +1 -4
  90. package/dist/src/connection-manager/index.d.ts.map +1 -1
  91. package/dist/src/connection-manager/index.js +8 -5
  92. package/dist/src/connection-manager/index.js.map +1 -1
  93. package/dist/src/connection-manager/latency-monitor.d.ts.map +1 -1
  94. package/dist/src/connection-manager/latency-monitor.js +1 -1
  95. package/dist/src/connection-manager/latency-monitor.js.map +1 -1
  96. package/dist/src/connection-manager/visibility-change-emitter.d.ts.map +1 -1
  97. package/dist/src/content-routing/index.d.ts +6 -4
  98. package/dist/src/content-routing/index.d.ts.map +1 -1
  99. package/dist/src/content-routing/index.js +9 -9
  100. package/dist/src/content-routing/index.js.map +1 -1
  101. package/dist/src/content-routing/utils.d.ts +3 -3
  102. package/dist/src/content-routing/utils.d.ts.map +1 -1
  103. package/dist/src/content-routing/utils.js +2 -2
  104. package/dist/src/content-routing/utils.js.map +1 -1
  105. package/dist/src/dht/dht-content-routing.d.ts +2 -1
  106. package/dist/src/dht/dht-content-routing.d.ts.map +1 -1
  107. package/dist/src/dht/dht-content-routing.js +2 -2
  108. package/dist/src/dht/dht-content-routing.js.map +1 -1
  109. package/dist/src/dht/dht-peer-routing.d.ts +3 -2
  110. package/dist/src/dht/dht-peer-routing.d.ts.map +1 -1
  111. package/dist/src/dht/dht-peer-routing.js +2 -2
  112. package/dist/src/dht/dht-peer-routing.js.map +1 -1
  113. package/dist/src/dht/dummy-dht.d.ts +1 -1
  114. package/dist/src/dht/dummy-dht.d.ts.map +1 -1
  115. package/dist/src/dht/dummy-dht.js +12 -12
  116. package/dist/src/dht/dummy-dht.js.map +1 -1
  117. package/dist/src/errors.d.ts +2 -1
  118. package/dist/src/errors.d.ts.map +1 -1
  119. package/dist/src/errors.js +1 -0
  120. package/dist/src/errors.js.map +1 -1
  121. package/dist/src/fetch/index.d.ts.map +1 -1
  122. package/dist/src/fetch/index.js +6 -6
  123. package/dist/src/fetch/index.js.map +1 -1
  124. package/dist/src/fetch/pb/proto.d.ts +3 -3
  125. package/dist/src/fetch/pb/proto.d.ts.map +1 -1
  126. package/dist/src/fetch/pb/proto.js +4 -3
  127. package/dist/src/fetch/pb/proto.js.map +1 -1
  128. package/dist/src/get-peer.js +2 -2
  129. package/dist/src/get-peer.js.map +1 -1
  130. package/dist/src/identify/index.d.ts +3 -1
  131. package/dist/src/identify/index.d.ts.map +1 -1
  132. package/dist/src/identify/index.js +19 -14
  133. package/dist/src/identify/index.js.map +1 -1
  134. package/dist/src/identify/pb/message.d.ts +2 -2
  135. package/dist/src/identify/pb/message.d.ts.map +1 -1
  136. package/dist/src/identify/pb/message.js +1 -0
  137. package/dist/src/identify/pb/message.js.map +1 -1
  138. package/dist/src/index.d.ts +14 -8
  139. package/dist/src/index.d.ts.map +1 -1
  140. package/dist/src/index.js.map +1 -1
  141. package/dist/src/insecure/index.d.ts.map +1 -1
  142. package/dist/src/insecure/index.js.map +1 -1
  143. package/dist/src/insecure/pb/proto.d.ts +3 -3
  144. package/dist/src/insecure/pb/proto.d.ts.map +1 -1
  145. package/dist/src/insecure/pb/proto.js +4 -5
  146. package/dist/src/insecure/pb/proto.js.map +1 -1
  147. package/dist/src/libp2p.d.ts +7 -3
  148. package/dist/src/libp2p.d.ts.map +1 -1
  149. package/dist/src/libp2p.js +35 -35
  150. package/dist/src/libp2p.js.map +1 -1
  151. package/dist/src/nat-manager.d.ts.map +1 -1
  152. package/dist/src/nat-manager.js +5 -3
  153. package/dist/src/nat-manager.js.map +1 -1
  154. package/dist/src/peer-record-updater.d.ts.map +1 -1
  155. package/dist/src/peer-routing.d.ts.map +1 -1
  156. package/dist/src/peer-routing.js +5 -5
  157. package/dist/src/peer-routing.js.map +1 -1
  158. package/dist/src/ping/index.d.ts.map +1 -1
  159. package/dist/src/ping/index.js +2 -2
  160. package/dist/src/ping/index.js.map +1 -1
  161. package/dist/src/pnet/crypto.d.ts +1 -1
  162. package/dist/src/pnet/crypto.d.ts.map +1 -1
  163. package/dist/src/pnet/crypto.js +1 -1
  164. package/dist/src/pnet/crypto.js.map +1 -1
  165. package/dist/src/pnet/index.js +3 -3
  166. package/dist/src/pnet/index.js.map +1 -1
  167. package/dist/src/pnet/key-generator.d.ts.map +1 -1
  168. package/dist/src/pubsub/dummy-pubsub.js +9 -9
  169. package/dist/src/pubsub/dummy-pubsub.js.map +1 -1
  170. package/dist/src/registrar.d.ts.map +1 -1
  171. package/dist/src/registrar.js +4 -4
  172. package/dist/src/registrar.js.map +1 -1
  173. package/dist/src/transport-manager.d.ts.map +1 -1
  174. package/dist/src/transport-manager.js +8 -9
  175. package/dist/src/transport-manager.js.map +1 -1
  176. package/dist/src/upgrader.d.ts +2 -1
  177. package/dist/src/upgrader.d.ts.map +1 -1
  178. package/dist/src/upgrader.js +38 -33
  179. package/dist/src/upgrader.js.map +1 -1
  180. package/dist/typedoc-urls.json +19 -6
  181. package/package.json +36 -33
  182. package/src/address-manager/index.ts +62 -35
  183. package/src/autonat/constants.ts +4 -0
  184. package/src/autonat/index.ts +567 -0
  185. package/src/autonat/pb/index.proto +35 -0
  186. package/src/autonat/pb/index.ts +320 -0
  187. package/src/circuit/constants.ts +48 -7
  188. package/src/circuit/index.ts +17 -129
  189. package/src/circuit/pb/index.proto +57 -32
  190. package/src/circuit/pb/index.ts +448 -138
  191. package/src/circuit/server/advert-service.ts +108 -0
  192. package/src/circuit/server/index.ts +421 -0
  193. package/src/circuit/server/reservation-store.ts +111 -0
  194. package/src/circuit/server/reservation-voucher.ts +51 -0
  195. package/src/circuit/transport/discovery.ts +127 -0
  196. package/src/circuit/transport/index.ts +325 -0
  197. package/src/circuit/transport/listener.ts +99 -0
  198. package/src/circuit/transport/reservation-store.ts +249 -0
  199. package/src/circuit/utils.ts +108 -0
  200. package/src/components.ts +22 -21
  201. package/src/config.ts +21 -25
  202. package/src/connection/index.ts +10 -10
  203. package/src/connection-manager/auto-dialler.ts +36 -40
  204. package/src/connection-manager/dialer/dial-request.ts +13 -6
  205. package/src/connection-manager/dialer/index.ts +34 -15
  206. package/src/connection-manager/index.ts +22 -23
  207. package/src/connection-manager/latency-monitor.ts +9 -9
  208. package/src/connection-manager/visibility-change-emitter.ts +4 -4
  209. package/src/content-routing/index.ts +18 -16
  210. package/src/content-routing/utils.ts +5 -5
  211. package/src/dht/dht-content-routing.ts +5 -4
  212. package/src/dht/dht-peer-routing.ts +5 -4
  213. package/src/dht/dummy-dht.ts +13 -13
  214. package/src/errors.ts +2 -1
  215. package/src/fetch/index.ts +13 -13
  216. package/src/fetch/pb/proto.ts +8 -7
  217. package/src/get-peer.ts +3 -3
  218. package/src/identify/index.ts +29 -24
  219. package/src/identify/pb/message.ts +3 -2
  220. package/src/index.ts +15 -8
  221. package/src/insecure/index.ts +2 -1
  222. package/src/insecure/pb/proto.ts +8 -9
  223. package/src/libp2p.ts +52 -46
  224. package/src/nat-manager.ts +11 -9
  225. package/src/peer-record-updater.ts +4 -4
  226. package/src/peer-routing.ts +9 -9
  227. package/src/ping/index.ts +6 -6
  228. package/src/pnet/crypto.ts +3 -3
  229. package/src/pnet/index.ts +3 -3
  230. package/src/pnet/key-generator.ts +1 -1
  231. package/src/pubsub/dummy-pubsub.ts +9 -9
  232. package/src/registrar.ts +12 -12
  233. package/src/transport-manager.ts +17 -18
  234. package/src/upgrader.ts +43 -42
  235. package/src/version.ts +1 -1
  236. package/dist/src/circuit/auto-relay.d.ts +0 -46
  237. package/dist/src/circuit/auto-relay.d.ts.map +0 -1
  238. package/dist/src/circuit/auto-relay.js +0 -220
  239. package/dist/src/circuit/auto-relay.js.map +0 -1
  240. package/dist/src/circuit/circuit/hop.d.ts +0 -42
  241. package/dist/src/circuit/circuit/hop.d.ts.map +0 -1
  242. package/dist/src/circuit/circuit/hop.js +0 -142
  243. package/dist/src/circuit/circuit/hop.js.map +0 -1
  244. package/dist/src/circuit/circuit/stop.d.ts +0 -24
  245. package/dist/src/circuit/circuit/stop.d.ts.map +0 -1
  246. package/dist/src/circuit/circuit/stop.js +0 -51
  247. package/dist/src/circuit/circuit/stop.js.map +0 -1
  248. package/dist/src/circuit/circuit/stream-handler.d.ts +0 -40
  249. package/dist/src/circuit/circuit/stream-handler.d.ts.map +0 -1
  250. package/dist/src/circuit/circuit/stream-handler.js +0 -59
  251. package/dist/src/circuit/circuit/stream-handler.js.map +0 -1
  252. package/dist/src/circuit/circuit/utils.d.ts +0 -7
  253. package/dist/src/circuit/circuit/utils.d.ts.map +0 -1
  254. package/dist/src/circuit/circuit/utils.js +0 -43
  255. package/dist/src/circuit/circuit/utils.js.map +0 -1
  256. package/dist/src/circuit/listener.d.ts +0 -9
  257. package/dist/src/circuit/listener.d.ts.map +0 -1
  258. package/dist/src/circuit/listener.js +0 -62
  259. package/dist/src/circuit/listener.js.map +0 -1
  260. package/dist/src/circuit/multicodec.d.ts +0 -2
  261. package/dist/src/circuit/multicodec.d.ts.map +0 -1
  262. package/dist/src/circuit/multicodec.js +0 -2
  263. package/dist/src/circuit/multicodec.js.map +0 -1
  264. package/dist/src/circuit/transport.d.ts +0 -51
  265. package/dist/src/circuit/transport.d.ts.map +0 -1
  266. package/dist/src/circuit/transport.js +0 -223
  267. package/dist/src/circuit/transport.js.map +0 -1
  268. package/dist/src/keychain/cms.d.ts +0 -33
  269. package/dist/src/keychain/cms.d.ts.map +0 -1
  270. package/dist/src/keychain/cms.js +0 -129
  271. package/dist/src/keychain/cms.js.map +0 -1
  272. package/dist/src/keychain/index.d.ts +0 -151
  273. package/dist/src/keychain/index.d.ts.map +0 -1
  274. package/dist/src/keychain/index.js +0 -519
  275. package/dist/src/keychain/index.js.map +0 -1
  276. package/dist/src/keychain/util.d.ts +0 -21
  277. package/dist/src/keychain/util.d.ts.map +0 -1
  278. package/dist/src/keychain/util.js +0 -79
  279. package/dist/src/keychain/util.js.map +0 -1
  280. package/src/circuit/IMPLEMENTATION_NOTES.md +0 -128
  281. package/src/circuit/README.md +0 -111
  282. package/src/circuit/auto-relay.ts +0 -292
  283. package/src/circuit/circuit/hop.ts +0 -220
  284. package/src/circuit/circuit/stop.ts +0 -83
  285. package/src/circuit/circuit/stream-handler.ts +0 -87
  286. package/src/circuit/circuit/utils.ts +0 -44
  287. package/src/circuit/listener.ts +0 -83
  288. package/src/circuit/multicodec.ts +0 -2
  289. package/src/circuit/transport.ts +0 -278
  290. package/src/keychain/README.md +0 -55
  291. package/src/keychain/cms.ts +0 -150
  292. package/src/keychain/doc/private-key.png +0 -0
  293. package/src/keychain/doc/private-key.xml +0 -1
  294. package/src/keychain/index.ts +0 -629
  295. package/src/keychain/util.ts +0 -82
@@ -0,0 +1,127 @@
1
+ import { logger } from '@libp2p/logger'
2
+ import { namespaceToCid } from '../utils.js'
3
+ import {
4
+ RELAY_RENDEZVOUS_NS
5
+ , RELAY_V2_HOP_CODEC
6
+ } from '../constants.js'
7
+ import type { PeerId } from '@libp2p/interface-peer-id'
8
+ import type { PeerStore } from '@libp2p/interface-peer-store'
9
+ import { EventEmitter } from '@libp2p/interfaces/events'
10
+ import type { Startable } from '@libp2p/interfaces/startable'
11
+ import type { ConnectionManager } from '@libp2p/interface-connection-manager'
12
+ import type { TransportManager } from '@libp2p/interface-transport'
13
+ import type { ContentRouting } from '@libp2p/interface-content-routing'
14
+ import type { Registrar } from '@libp2p/interface-registrar'
15
+ import { createTopology } from '@libp2p/topology'
16
+
17
+ const log = logger('libp2p:circuit-relay:discover-relays')
18
+
19
+ export interface RelayDiscoveryEvents {
20
+ 'relay:discover': CustomEvent<PeerId>
21
+ }
22
+
23
+ export interface RelayDiscoveryComponents {
24
+ peerId: PeerId
25
+ peerStore: PeerStore
26
+ connectionManager: ConnectionManager
27
+ transportManager: TransportManager
28
+ contentRouting: ContentRouting
29
+ registrar: Registrar
30
+ }
31
+
32
+ /**
33
+ * ReservationManager automatically makes a circuit v2 reservation on any connected
34
+ * peers that support the circuit v2 HOP protocol.
35
+ */
36
+ export class RelayDiscovery extends EventEmitter<RelayDiscoveryEvents> implements Startable {
37
+ private readonly peerId: PeerId
38
+ private readonly peerStore: PeerStore
39
+ private readonly contentRouting: ContentRouting
40
+ private readonly registrar: Registrar
41
+ private started: boolean
42
+ private topologyId?: string
43
+
44
+ constructor (components: RelayDiscoveryComponents) {
45
+ super()
46
+ this.started = false
47
+ this.peerId = components.peerId
48
+ this.peerStore = components.peerStore
49
+ this.contentRouting = components.contentRouting
50
+ this.registrar = components.registrar
51
+ }
52
+
53
+ isStarted (): boolean {
54
+ return this.started
55
+ }
56
+
57
+ async start (): Promise<void> {
58
+ // register a topology listener for when new peers are encountered
59
+ // that support the hop protocol
60
+ this.topologyId = await this.registrar.register(RELAY_V2_HOP_CODEC, createTopology({
61
+ onConnect: (peerId) => {
62
+ this.safeDispatchEvent('relay:discover', { detail: peerId })
63
+ }
64
+ }))
65
+
66
+ void this.discover()
67
+ .catch(err => {
68
+ log.error('error listening on relays', err)
69
+ })
70
+
71
+ this.started = true
72
+ }
73
+
74
+ stop (): void {
75
+ if (this.topologyId != null) {
76
+ this.registrar.unregister(this.topologyId)
77
+ }
78
+
79
+ this.started = false
80
+ }
81
+
82
+ /**
83
+ * Try to listen on available hop relay connections.
84
+ * The following order will happen while we do not have enough relays:
85
+ *
86
+ * 1. Check the metadata store for known relays, try to listen on the ones we are already connected
87
+ * 2. Dial and try to listen on the peers we know that support hop but are not connected
88
+ * 3. Search the network
89
+ */
90
+ async discover (): Promise<void> {
91
+ log('searching peer store for relays')
92
+ const peers = (await this.peerStore.all())
93
+ // filter by a list of peers supporting RELAY_V2_HOP and ones we are not listening on
94
+ .filter(({ id, protocols }) => protocols.includes(RELAY_V2_HOP_CODEC))
95
+ .sort(() => Math.random() - 0.5)
96
+
97
+ for (const peer of peers) {
98
+ log('found relay peer %p in content peer store', peer.id)
99
+ this.safeDispatchEvent('relay:discover', { detail: peer.id })
100
+ }
101
+
102
+ log('found %d relay peers in peer store', peers.length)
103
+
104
+ try {
105
+ log('searching content routing for relays')
106
+ const cid = await namespaceToCid(RELAY_RENDEZVOUS_NS)
107
+
108
+ let found = 0
109
+
110
+ for await (const provider of this.contentRouting.findProviders(cid)) {
111
+ if (provider.multiaddrs.length > 0 && !provider.id.equals(this.peerId)) {
112
+ const peerId = provider.id
113
+
114
+ found++
115
+ log('found relay peer %p in content routing', peerId)
116
+ await this.peerStore.addressBook.add(peerId, provider.multiaddrs)
117
+
118
+ this.safeDispatchEvent('relay:discover', { detail: peerId })
119
+ }
120
+ }
121
+
122
+ log('found %d relay peers in content routing', found)
123
+ } catch (err: any) {
124
+ log.error('failed when finding relays on the network', err)
125
+ }
126
+ }
127
+ }
@@ -0,0 +1,325 @@
1
+ import { StopMessage, HopMessage, Status } from '../pb/index.js'
2
+ import { logger } from '@libp2p/logger'
3
+ import * as mafmt from '@multiformats/mafmt'
4
+ import { multiaddr } from '@multiformats/multiaddr'
5
+ import { codes } from '../../errors.js'
6
+ import { streamToMaConnection } from '@libp2p/utils/stream-to-ma-conn'
7
+ import { createListener } from './listener.js'
8
+ import { symbol, Upgrader } from '@libp2p/interface-transport'
9
+ import { peerIdFromBytes, peerIdFromString } from '@libp2p/peer-id'
10
+ import type { AbortOptions } from '@libp2p/interfaces'
11
+ import type { IncomingStreamData, Registrar } from '@libp2p/interface-registrar'
12
+ import type { Listener, Transport, CreateListenerOptions } from '@libp2p/interface-transport'
13
+ import type { Connection, Stream } from '@libp2p/interface-connection'
14
+ import type { ConnectionGater } from '@libp2p/interface-connection-gater'
15
+ import type { PeerId } from '@libp2p/interface-peer-id'
16
+ import type { Multiaddr } from '@multiformats/multiaddr'
17
+ import type { PeerStore } from '@libp2p/interface-peer-store'
18
+ import type { ConnectionManager } from '@libp2p/interface-connection-manager'
19
+ import type { AddressManager } from '@libp2p/interface-address-manager'
20
+ import { pbStream } from 'it-pb-stream'
21
+ import type { ContentRouting } from '@libp2p/interface-content-routing'
22
+ import { CIRCUIT_PROTO_CODE, RELAY_V2_HOP_CODEC, RELAY_V2_STOP_CODEC } from '../constants.js'
23
+ import { RelayStoreInit, ReservationStore } from './reservation-store.js'
24
+ import { RelayDiscovery, RelayDiscoveryComponents } from './discovery.js'
25
+ import { CodeError } from '@libp2p/interfaces/errors'
26
+
27
+ const log = logger('libp2p:circuit-relay:transport')
28
+
29
+ const isValidStop = (request: StopMessage): request is Required<StopMessage> => {
30
+ if (request.peer == null) {
31
+ return false
32
+ }
33
+
34
+ try {
35
+ request.peer.addrs.forEach(multiaddr)
36
+ } catch {
37
+ return false
38
+ }
39
+
40
+ return true
41
+ }
42
+
43
+ export interface CircuitRelayTransportComponents extends RelayDiscoveryComponents {
44
+ peerId: PeerId
45
+ peerStore: PeerStore
46
+ registrar: Registrar
47
+ connectionManager: ConnectionManager
48
+ upgrader: Upgrader
49
+ addressManager: AddressManager
50
+ contentRouting: ContentRouting
51
+ connectionGater: ConnectionGater
52
+ }
53
+
54
+ interface ConnectOptions {
55
+ stream: Stream
56
+ connection: Connection
57
+ destinationPeer: PeerId
58
+ destinationAddr: Multiaddr
59
+ relayAddr: Multiaddr
60
+ ma: Multiaddr
61
+ disconnectOnFailure: boolean
62
+ }
63
+
64
+ /**
65
+ * RelayConfig configures the circuit v2 relay transport.
66
+ */
67
+ export interface CircuitRelayTransportInit extends RelayStoreInit {
68
+ /**
69
+ * The number of peers running diable relays to search for and
70
+ * connect to. (default: 0)
71
+ */
72
+ discoverRelays?: number
73
+ }
74
+
75
+ class CircuitRelayTransport implements Transport {
76
+ private readonly discovery?: RelayDiscovery
77
+ private readonly registrar: Registrar
78
+ private readonly peerStore: PeerStore
79
+ private readonly connectionManager: ConnectionManager
80
+ private readonly peerId: PeerId
81
+ private readonly upgrader: Upgrader
82
+ private readonly addressManager: AddressManager
83
+ private readonly connectionGater: ConnectionGater
84
+ private readonly reservationStore: ReservationStore
85
+ private started: boolean
86
+
87
+ constructor (components: CircuitRelayTransportComponents, init: CircuitRelayTransportInit) {
88
+ this.registrar = components.registrar
89
+ this.peerStore = components.peerStore
90
+ this.connectionManager = components.connectionManager
91
+ this.peerId = components.peerId
92
+ this.upgrader = components.upgrader
93
+ this.addressManager = components.addressManager
94
+ this.connectionGater = components.connectionGater
95
+
96
+ if (init.discoverRelays != null && init.discoverRelays > 0) {
97
+ this.discovery = new RelayDiscovery(components)
98
+ this.discovery.addEventListener('relay:discover', (evt) => {
99
+ this.reservationStore.addRelay(evt.detail, 'discovered')
100
+ .catch(err => {
101
+ log.error('could not add discovered relay %p', evt.detail, err)
102
+ })
103
+ })
104
+ }
105
+
106
+ this.reservationStore = new ReservationStore(components, init)
107
+ this.reservationStore.addEventListener('relay:not-enough-relays', () => {
108
+ this.discovery?.discover()
109
+ .catch(err => {
110
+ log.error('could not discover relays', err)
111
+ })
112
+ })
113
+
114
+ this.started = false
115
+ }
116
+
117
+ isStarted (): boolean {
118
+ return this.started
119
+ }
120
+
121
+ async start (): Promise<void> {
122
+ await this.reservationStore.start()
123
+ await this.discovery?.start()
124
+
125
+ await this.registrar.handle(RELAY_V2_STOP_CODEC, (data) => {
126
+ void this.onStop(data).catch(err => {
127
+ log.error(err)
128
+ })
129
+ })
130
+
131
+ this.started = true
132
+ }
133
+
134
+ async stop (): Promise<void> {
135
+ this.discovery?.stop()
136
+ await this.reservationStore.stop()
137
+ await this.registrar.unhandle(RELAY_V2_STOP_CODEC)
138
+
139
+ this.started = false
140
+ }
141
+
142
+ get [symbol] (): true {
143
+ return true
144
+ }
145
+
146
+ get [Symbol.toStringTag] (): 'libp2p/circuit-relay-v2' {
147
+ return 'libp2p/circuit-relay-v2'
148
+ }
149
+
150
+ /**
151
+ * Dial a peer over a relay
152
+ */
153
+ async dial (ma: Multiaddr, options: AbortOptions = {}): Promise<Connection> {
154
+ if (ma.protoCodes().filter(code => code === CIRCUIT_PROTO_CODE).length !== 1) {
155
+ const errMsg = 'Invalid circuit relay address'
156
+ log.error(errMsg, ma)
157
+ throw new CodeError(errMsg, codes.ERR_RELAYED_DIAL)
158
+ }
159
+
160
+ // Check the multiaddr to see if it contains a relay and a destination peer
161
+ const addrs = ma.toString().split('/p2p-circuit')
162
+ const relayAddr = multiaddr(addrs[0])
163
+ const destinationAddr = multiaddr(addrs[addrs.length - 1])
164
+ const relayId = relayAddr.getPeerId()
165
+ const destinationId = destinationAddr.getPeerId()
166
+
167
+ if (relayId == null || destinationId == null) {
168
+ const errMsg = 'Circuit relay dial failed as addresses did not have peer id'
169
+ log.error(errMsg)
170
+ throw new CodeError(errMsg, codes.ERR_RELAYED_DIAL)
171
+ }
172
+
173
+ const relayPeer = peerIdFromString(relayId)
174
+ const destinationPeer = peerIdFromString(destinationId)
175
+
176
+ let disconnectOnFailure = false
177
+ const relayConnections = this.connectionManager.getConnections(relayPeer)
178
+ let relayConnection = relayConnections[0]
179
+
180
+ if (relayConnection == null) {
181
+ await this.peerStore.addressBook.add(relayPeer, [relayAddr])
182
+ relayConnection = await this.connectionManager.openConnection(relayPeer, options)
183
+ disconnectOnFailure = true
184
+ }
185
+
186
+ try {
187
+ const stream = await relayConnection.newStream([RELAY_V2_HOP_CODEC])
188
+
189
+ return await this.connectV2({
190
+ stream,
191
+ connection: relayConnection,
192
+ destinationPeer,
193
+ destinationAddr,
194
+ relayAddr,
195
+ ma,
196
+ disconnectOnFailure
197
+ })
198
+ } catch (err: any) {
199
+ log.error('Circuit relay dial failed', err)
200
+ disconnectOnFailure && await relayConnection.close()
201
+ throw err
202
+ }
203
+ }
204
+
205
+ async connectV2 (
206
+ {
207
+ stream, connection, destinationPeer,
208
+ destinationAddr, relayAddr, ma,
209
+ disconnectOnFailure
210
+ }: ConnectOptions
211
+ ): Promise<Connection> {
212
+ try {
213
+ const pbstr = pbStream(stream)
214
+ const hopstr = pbstr.pb(HopMessage)
215
+ hopstr.write({
216
+ type: HopMessage.Type.CONNECT,
217
+ peer: {
218
+ id: destinationPeer.toBytes(),
219
+ addrs: [multiaddr(destinationAddr).bytes]
220
+ }
221
+ })
222
+
223
+ const status = await hopstr.read()
224
+
225
+ if (status.status !== Status.OK) {
226
+ throw new CodeError(`failed to connect via relay with status ${status?.status?.toString() ?? 'undefined'}`, codes.ERR_HOP_REQUEST_FAILED)
227
+ }
228
+
229
+ // TODO: do something with limit and transient connection
230
+
231
+ const maConn = streamToMaConnection({
232
+ stream: pbstr.unwrap(),
233
+ remoteAddr: ma,
234
+ localAddr: relayAddr.encapsulate(`/p2p-circuit/p2p/${this.peerId.toString()}`)
235
+ })
236
+
237
+ log('new outbound connection %s', maConn.remoteAddr)
238
+ return await this.upgrader.upgradeOutbound(maConn)
239
+ } catch (err) {
240
+ log.error('Circuit relay dial failed', err)
241
+ disconnectOnFailure && await connection.close()
242
+ throw err
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Create a listener
248
+ */
249
+ createListener (options: CreateListenerOptions): Listener {
250
+ return createListener({
251
+ connectionManager: this.connectionManager,
252
+ relayStore: this.reservationStore
253
+ })
254
+ }
255
+
256
+ /**
257
+ * Filter check for all Multiaddrs that this transport can dial on
258
+ *
259
+ * @param {Multiaddr[]} multiaddrs
260
+ * @returns {Multiaddr[]}
261
+ */
262
+ filter (multiaddrs: Multiaddr[]): Multiaddr[] {
263
+ multiaddrs = Array.isArray(multiaddrs) ? multiaddrs : [multiaddrs]
264
+
265
+ return multiaddrs.filter((ma) => {
266
+ return mafmt.Circuit.matches(ma)
267
+ })
268
+ }
269
+
270
+ /**
271
+ * An incoming STOP request means a remote peer wants to dial us via a relay
272
+ */
273
+ async onStop ({ connection, stream }: IncomingStreamData): Promise<void> {
274
+ const pbstr = pbStream(stream)
275
+ const request = await pbstr.readPB(StopMessage)
276
+ log('received circuit v2 stop protocol request from %s', connection.remotePeer)
277
+
278
+ if (request?.type === undefined) {
279
+ return
280
+ }
281
+
282
+ const stopstr = pbstr.pb(StopMessage)
283
+ log('new circuit relay v2 stop stream from %s', connection.remotePeer)
284
+
285
+ // Validate the STOP request has the required input
286
+ if (request.type !== StopMessage.Type.CONNECT) {
287
+ log.error('invalid stop connect request via peer %s', connection.remotePeer)
288
+ stopstr.write({ type: StopMessage.Type.STATUS, status: Status.UNEXPECTED_MESSAGE })
289
+ return
290
+ }
291
+
292
+ if (!isValidStop(request)) {
293
+ log.error('invalid stop connect request via peer %s', connection.remotePeer)
294
+ stopstr.write({ type: StopMessage.Type.STATUS, status: Status.MALFORMED_MESSAGE })
295
+ return
296
+ }
297
+
298
+ const remotePeerId = peerIdFromBytes(request.peer.id)
299
+
300
+ if ((await this.connectionGater.denyInboundRelayedConnection?.(connection.remotePeer, remotePeerId)) === true) {
301
+ stopstr.write({ type: StopMessage.Type.STATUS, status: Status.PERMISSION_DENIED })
302
+ return
303
+ }
304
+
305
+ stopstr.write({ type: StopMessage.Type.STATUS, status: Status.OK })
306
+
307
+ const remoteAddr = connection.remoteAddr.encapsulate(`/p2p-circuit/p2p/${remotePeerId.toString()}`)
308
+ const localAddr = this.addressManager.getAddresses()[0]
309
+ const maConn = streamToMaConnection({
310
+ stream: pbstr.unwrap(),
311
+ remoteAddr,
312
+ localAddr
313
+ })
314
+
315
+ log('new inbound connection %s', maConn.remoteAddr)
316
+ await this.upgrader.upgradeInbound(maConn)
317
+ log('%s connection %s upgraded', 'inbound', maConn.remoteAddr)
318
+ }
319
+ }
320
+
321
+ export function circuitRelayTransport (init: CircuitRelayTransportInit = {}): (components: CircuitRelayTransportComponents) => Transport {
322
+ return (components) => {
323
+ return new CircuitRelayTransport(components, init)
324
+ }
325
+ }
@@ -0,0 +1,99 @@
1
+ import { CustomEvent, EventEmitter } from '@libp2p/interfaces/events'
2
+ import type { ConnectionManager } from '@libp2p/interface-connection-manager'
3
+ import type { Listener, ListenerEvents } from '@libp2p/interface-transport'
4
+ import type { Multiaddr } from '@multiformats/multiaddr'
5
+ import { multiaddr } from '@multiformats/multiaddr'
6
+ import type { ReservationStore } from './reservation-store'
7
+ import type { PeerId } from '@libp2p/interface-peer-id'
8
+ import { PeerMap } from '@libp2p/peer-collections'
9
+ import { logger } from '@libp2p/logger'
10
+
11
+ const log = logger('libp2p:circuit-relay:transport:listener')
12
+
13
+ export interface CircuitRelayTransportListenerComponents {
14
+ connectionManager: ConnectionManager
15
+ relayStore: ReservationStore
16
+ }
17
+
18
+ class CircuitRelayTransportListener extends EventEmitter<ListenerEvents> implements Listener {
19
+ private readonly connectionManager: ConnectionManager
20
+ private readonly relayStore: ReservationStore
21
+ private readonly listeningAddrs: PeerMap<Multiaddr>
22
+
23
+ constructor (components: CircuitRelayTransportListenerComponents) {
24
+ super()
25
+
26
+ this.connectionManager = components.connectionManager
27
+ this.relayStore = components.relayStore
28
+ this.listeningAddrs = new PeerMap()
29
+
30
+ // remove listening addrs when a relay is removed
31
+ this.relayStore.addEventListener('relay:removed', (evt) => {
32
+ this.#removeRelayPeer(evt.detail)
33
+ })
34
+
35
+ // remove listening addrs when a peer disconnects
36
+ this.connectionManager.addEventListener('peer:disconnect', (evt) => {
37
+ this.#removeRelayPeer(evt.detail.remotePeer)
38
+ })
39
+ }
40
+
41
+ async listen (addr: Multiaddr): Promise<void> {
42
+ log('listen on %s', addr)
43
+
44
+ const addrString = addr.toString().split('/p2p-circuit').find(a => a !== '')
45
+ const ma = multiaddr(addrString)
46
+ const relayConn = await this.connectionManager.openConnection(ma)
47
+
48
+ if (!this.relayStore.hasReservation(relayConn.remotePeer)) {
49
+ // addRelay calls transportManager.listen which calls this listen method
50
+ await this.relayStore.addRelay(relayConn.remotePeer, 'configured')
51
+ return
52
+ }
53
+
54
+ if (this.listeningAddrs.has(relayConn.remotePeer)) {
55
+ log('already listening on relay %p', relayConn.remotePeer)
56
+ return
57
+ }
58
+
59
+ this.listeningAddrs.set(relayConn.remotePeer, addr)
60
+ this.dispatchEvent(new CustomEvent('listening'))
61
+ }
62
+
63
+ /**
64
+ * Get fixed up multiaddrs
65
+ *
66
+ * NOTE: This method will grab the peers multiaddrs and expand them such that:
67
+ *
68
+ * a) If it's an existing /p2p-circuit address for a specific relay i.e.
69
+ * `/ip4/0.0.0.0/tcp/0/ipfs/QmRelay/p2p-circuit` this method will expand the
70
+ * address to `/ip4/0.0.0.0/tcp/0/ipfs/QmRelay/p2p-circuit/ipfs/QmPeer` where
71
+ * `QmPeer` is this peers id
72
+ * b) If it's not a /p2p-circuit address, it will encapsulate the address as a /p2p-circuit
73
+ * addr, such when dialing over a relay with this address, it will create the circuit using
74
+ * the encapsulated transport address. This is useful when for example, a peer should only
75
+ * be dialed over TCP rather than any other transport
76
+ */
77
+ getAddrs (): Multiaddr[] {
78
+ return [...this.listeningAddrs.values()]
79
+ }
80
+
81
+ async close (): Promise<void> {
82
+
83
+ }
84
+
85
+ #removeRelayPeer (peerId: PeerId): void {
86
+ const had = this.listeningAddrs.has(peerId)
87
+
88
+ this.listeningAddrs.delete(peerId)
89
+
90
+ if (had) {
91
+ // Announce listen addresses change
92
+ this.dispatchEvent(new CustomEvent('close'))
93
+ }
94
+ }
95
+ }
96
+
97
+ export function createListener (options: CircuitRelayTransportListenerComponents): Listener {
98
+ return new CircuitRelayTransportListener(options)
99
+ }