libp2p 0.42.2-593deefe → 0.42.2-5e63ee2d

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 (228) hide show
  1. package/dist/index.min.js +30 -30
  2. package/dist/src/address-manager/index.d.ts +1 -10
  3. package/dist/src/address-manager/index.d.ts.map +1 -1
  4. package/dist/src/address-manager/index.js +46 -29
  5. package/dist/src/address-manager/index.js.map +1 -1
  6. package/dist/src/autonat/constants.d.ts +4 -0
  7. package/dist/src/autonat/constants.d.ts.map +1 -0
  8. package/dist/src/autonat/constants.js +4 -0
  9. package/dist/src/autonat/constants.js.map +1 -0
  10. package/dist/src/autonat/index.d.ts +64 -0
  11. package/dist/src/autonat/index.d.ts.map +1 -0
  12. package/dist/src/autonat/index.js +417 -0
  13. package/dist/src/autonat/index.js.map +1 -0
  14. package/dist/src/autonat/pb/index.d.ts +57 -0
  15. package/dist/src/autonat/pb/index.d.ts.map +1 -0
  16. package/dist/src/autonat/pb/index.js +250 -0
  17. package/dist/src/autonat/pb/index.js.map +1 -0
  18. package/dist/src/circuit/constants.d.ts +29 -3
  19. package/dist/src/circuit/constants.d.ts.map +1 -1
  20. package/dist/src/circuit/constants.js +32 -5
  21. package/dist/src/circuit/constants.js.map +1 -1
  22. package/dist/src/circuit/index.d.ts +16 -61
  23. package/dist/src/circuit/index.d.ts.map +1 -1
  24. package/dist/src/circuit/index.js +2 -1
  25. package/dist/src/circuit/index.js.map +1 -1
  26. package/dist/src/circuit/server/advert-service.d.ts +43 -0
  27. package/dist/src/circuit/server/advert-service.d.ts.map +1 -0
  28. package/dist/src/circuit/server/advert-service.js +69 -0
  29. package/dist/src/circuit/server/advert-service.js.map +1 -0
  30. package/dist/src/circuit/server/index.d.ts +60 -0
  31. package/dist/src/circuit/server/index.d.ts.map +1 -0
  32. package/dist/src/circuit/server/index.js +287 -0
  33. package/dist/src/circuit/server/index.js.map +1 -0
  34. package/dist/src/circuit/{reservation-store.d.ts → server/reservation-store.d.ts} +17 -10
  35. package/dist/src/circuit/server/reservation-store.d.ts.map +1 -0
  36. package/dist/src/circuit/server/reservation-store.js +57 -0
  37. package/dist/src/circuit/server/reservation-store.js.map +1 -0
  38. package/dist/src/circuit/server/reservation-voucher.d.ts.map +1 -0
  39. package/dist/src/circuit/{reservation-voucher.js → server/reservation-voucher.js} +1 -1
  40. package/dist/src/circuit/server/reservation-voucher.js.map +1 -0
  41. package/dist/src/circuit/transport/discovery.d.ts +45 -0
  42. package/dist/src/circuit/transport/discovery.d.ts.map +1 -0
  43. package/dist/src/circuit/transport/discovery.js +82 -0
  44. package/dist/src/circuit/transport/discovery.js.map +1 -0
  45. package/dist/src/circuit/transport/index.d.ts +33 -0
  46. package/dist/src/circuit/transport/index.d.ts.map +1 -0
  47. package/dist/src/circuit/transport/index.js +225 -0
  48. package/dist/src/circuit/transport/index.js.map +1 -0
  49. package/dist/src/circuit/transport/listener.d.ts +9 -0
  50. package/dist/src/circuit/transport/listener.d.ts.map +1 -0
  51. package/dist/src/circuit/transport/listener.js +76 -0
  52. package/dist/src/circuit/transport/listener.js.map +1 -0
  53. package/dist/src/circuit/transport/reservation-store.d.ts +60 -0
  54. package/dist/src/circuit/transport/reservation-store.d.ts.map +1 -0
  55. package/dist/src/circuit/transport/reservation-store.js +165 -0
  56. package/dist/src/circuit/transport/reservation-store.js.map +1 -0
  57. package/dist/src/circuit/utils.d.ts +4 -2
  58. package/dist/src/circuit/utils.d.ts.map +1 -1
  59. package/dist/src/circuit/utils.js +75 -102
  60. package/dist/src/circuit/utils.js.map +1 -1
  61. package/dist/src/components.d.ts +2 -1
  62. package/dist/src/components.d.ts.map +1 -1
  63. package/dist/src/components.js.map +1 -1
  64. package/dist/src/config.d.ts.map +1 -1
  65. package/dist/src/config.js +17 -20
  66. package/dist/src/config.js.map +1 -1
  67. package/dist/src/connection/index.d.ts +2 -2
  68. package/dist/src/connection/index.d.ts.map +1 -1
  69. package/dist/src/connection/index.js +1 -1
  70. package/dist/src/connection/index.js.map +1 -1
  71. package/dist/src/connection-manager/auto-dialler.d.ts +0 -4
  72. package/dist/src/connection-manager/auto-dialler.d.ts.map +1 -1
  73. package/dist/src/connection-manager/auto-dialler.js +0 -9
  74. package/dist/src/connection-manager/auto-dialler.js.map +1 -1
  75. package/dist/src/connection-manager/dialer/dial-request.js +1 -1
  76. package/dist/src/connection-manager/dialer/dial-request.js.map +1 -1
  77. package/dist/src/connection-manager/dialer/index.d.ts +2 -1
  78. package/dist/src/connection-manager/dialer/index.d.ts.map +1 -1
  79. package/dist/src/connection-manager/dialer/index.js +3 -3
  80. package/dist/src/connection-manager/dialer/index.js.map +1 -1
  81. package/dist/src/connection-manager/index.d.ts +0 -4
  82. package/dist/src/connection-manager/index.d.ts.map +1 -1
  83. package/dist/src/connection-manager/index.js +1 -1
  84. package/dist/src/connection-manager/index.js.map +1 -1
  85. package/dist/src/connection-manager/latency-monitor.d.ts.map +1 -1
  86. package/dist/src/connection-manager/latency-monitor.js +1 -1
  87. package/dist/src/connection-manager/latency-monitor.js.map +1 -1
  88. package/dist/src/connection-manager/visibility-change-emitter.d.ts.map +1 -1
  89. package/dist/src/content-routing/index.d.ts +6 -4
  90. package/dist/src/content-routing/index.d.ts.map +1 -1
  91. package/dist/src/content-routing/index.js +1 -1
  92. package/dist/src/content-routing/index.js.map +1 -1
  93. package/dist/src/content-routing/utils.d.ts +3 -3
  94. package/dist/src/content-routing/utils.d.ts.map +1 -1
  95. package/dist/src/dht/dht-content-routing.d.ts +2 -1
  96. package/dist/src/dht/dht-content-routing.d.ts.map +1 -1
  97. package/dist/src/dht/dht-content-routing.js.map +1 -1
  98. package/dist/src/dht/dht-peer-routing.d.ts +3 -2
  99. package/dist/src/dht/dht-peer-routing.d.ts.map +1 -1
  100. package/dist/src/dht/dht-peer-routing.js.map +1 -1
  101. package/dist/src/dht/dummy-dht.d.ts +1 -1
  102. package/dist/src/dht/dummy-dht.d.ts.map +1 -1
  103. package/dist/src/fetch/index.d.ts.map +1 -1
  104. package/dist/src/identify/index.d.ts +3 -1
  105. package/dist/src/identify/index.d.ts.map +1 -1
  106. package/dist/src/identify/index.js +12 -7
  107. package/dist/src/identify/index.js.map +1 -1
  108. package/dist/src/index.d.ts +13 -7
  109. package/dist/src/index.d.ts.map +1 -1
  110. package/dist/src/index.js.map +1 -1
  111. package/dist/src/insecure/index.d.ts.map +1 -1
  112. package/dist/src/insecure/index.js.map +1 -1
  113. package/dist/src/libp2p.d.ts +6 -4
  114. package/dist/src/libp2p.d.ts.map +1 -1
  115. package/dist/src/libp2p.js +19 -28
  116. package/dist/src/libp2p.js.map +1 -1
  117. package/dist/src/nat-manager.d.ts.map +1 -1
  118. package/dist/src/nat-manager.js +3 -1
  119. package/dist/src/nat-manager.js.map +1 -1
  120. package/dist/src/peer-record-updater.d.ts.map +1 -1
  121. package/dist/src/peer-routing.d.ts.map +1 -1
  122. package/dist/src/ping/index.d.ts.map +1 -1
  123. package/dist/src/pnet/crypto.d.ts +1 -1
  124. package/dist/src/pnet/crypto.d.ts.map +1 -1
  125. package/dist/src/pnet/crypto.js +1 -1
  126. package/dist/src/pnet/crypto.js.map +1 -1
  127. package/dist/src/pnet/key-generator.d.ts.map +1 -1
  128. package/dist/src/registrar.d.ts.map +1 -1
  129. package/dist/src/transport-manager.d.ts.map +1 -1
  130. package/dist/src/transport-manager.js +1 -1
  131. package/dist/src/transport-manager.js.map +1 -1
  132. package/dist/src/upgrader.d.ts +2 -1
  133. package/dist/src/upgrader.d.ts.map +1 -1
  134. package/dist/src/upgrader.js +19 -14
  135. package/dist/src/upgrader.js.map +1 -1
  136. package/package.json +23 -18
  137. package/src/address-manager/index.ts +62 -35
  138. package/src/autonat/constants.ts +4 -0
  139. package/src/autonat/index.ts +567 -0
  140. package/src/autonat/pb/index.proto +35 -0
  141. package/src/autonat/pb/index.ts +320 -0
  142. package/src/circuit/constants.ts +40 -5
  143. package/src/circuit/index.ts +17 -67
  144. package/src/circuit/server/advert-service.ts +108 -0
  145. package/src/circuit/server/index.ts +421 -0
  146. package/src/circuit/server/reservation-store.ts +111 -0
  147. package/src/circuit/{reservation-voucher.ts → server/reservation-voucher.ts} +3 -3
  148. package/src/circuit/transport/discovery.ts +127 -0
  149. package/src/circuit/transport/index.ts +325 -0
  150. package/src/circuit/transport/listener.ts +99 -0
  151. package/src/circuit/transport/reservation-store.ts +249 -0
  152. package/src/circuit/utils.ts +78 -115
  153. package/src/components.ts +9 -8
  154. package/src/config.ts +17 -20
  155. package/src/connection/index.ts +7 -7
  156. package/src/connection-manager/auto-dialler.ts +4 -20
  157. package/src/connection-manager/dialer/dial-request.ts +1 -1
  158. package/src/connection-manager/dialer/index.ts +10 -9
  159. package/src/connection-manager/index.ts +14 -19
  160. package/src/connection-manager/latency-monitor.ts +9 -9
  161. package/src/connection-manager/visibility-change-emitter.ts +4 -4
  162. package/src/content-routing/index.ts +10 -8
  163. package/src/content-routing/utils.ts +3 -3
  164. package/src/dht/dht-content-routing.ts +3 -2
  165. package/src/dht/dht-peer-routing.ts +3 -2
  166. package/src/dht/dummy-dht.ts +1 -1
  167. package/src/fetch/index.ts +7 -7
  168. package/src/identify/index.ts +22 -17
  169. package/src/index.ts +14 -7
  170. package/src/insecure/index.ts +2 -1
  171. package/src/libp2p.ts +33 -41
  172. package/src/nat-manager.ts +9 -7
  173. package/src/peer-record-updater.ts +4 -4
  174. package/src/peer-routing.ts +4 -4
  175. package/src/ping/index.ts +4 -4
  176. package/src/pnet/crypto.ts +3 -3
  177. package/src/pnet/key-generator.ts +1 -1
  178. package/src/registrar.ts +8 -8
  179. package/src/transport-manager.ts +10 -10
  180. package/src/upgrader.ts +20 -19
  181. package/src/version.ts +1 -1
  182. package/dist/src/circuit/client.d.ts +0 -81
  183. package/dist/src/circuit/client.d.ts.map +0 -1
  184. package/dist/src/circuit/client.js +0 -285
  185. package/dist/src/circuit/client.js.map +0 -1
  186. package/dist/src/circuit/hop.d.ts +0 -23
  187. package/dist/src/circuit/hop.d.ts.map +0 -1
  188. package/dist/src/circuit/hop.js +0 -167
  189. package/dist/src/circuit/hop.js.map +0 -1
  190. package/dist/src/circuit/interfaces.d.ts +0 -27
  191. package/dist/src/circuit/interfaces.d.ts.map +0 -1
  192. package/dist/src/circuit/interfaces.js +0 -2
  193. package/dist/src/circuit/interfaces.js.map +0 -1
  194. package/dist/src/circuit/listener.d.ts +0 -9
  195. package/dist/src/circuit/listener.d.ts.map +0 -1
  196. package/dist/src/circuit/listener.js +0 -62
  197. package/dist/src/circuit/listener.js.map +0 -1
  198. package/dist/src/circuit/multicodec.d.ts +0 -3
  199. package/dist/src/circuit/multicodec.d.ts.map +0 -1
  200. package/dist/src/circuit/multicodec.js +0 -3
  201. package/dist/src/circuit/multicodec.js.map +0 -1
  202. package/dist/src/circuit/relay.d.ts +0 -34
  203. package/dist/src/circuit/relay.d.ts.map +0 -1
  204. package/dist/src/circuit/relay.js +0 -61
  205. package/dist/src/circuit/relay.js.map +0 -1
  206. package/dist/src/circuit/reservation-store.d.ts.map +0 -1
  207. package/dist/src/circuit/reservation-store.js +0 -59
  208. package/dist/src/circuit/reservation-store.js.map +0 -1
  209. package/dist/src/circuit/reservation-voucher.d.ts.map +0 -1
  210. package/dist/src/circuit/reservation-voucher.js.map +0 -1
  211. package/dist/src/circuit/stop.d.ts +0 -19
  212. package/dist/src/circuit/stop.d.ts.map +0 -1
  213. package/dist/src/circuit/stop.js +0 -67
  214. package/dist/src/circuit/stop.js.map +0 -1
  215. package/dist/src/circuit/transport.d.ts +0 -66
  216. package/dist/src/circuit/transport.d.ts.map +0 -1
  217. package/dist/src/circuit/transport.js +0 -238
  218. package/dist/src/circuit/transport.js.map +0 -1
  219. package/src/circuit/client.ts +0 -381
  220. package/src/circuit/hop.ts +0 -210
  221. package/src/circuit/interfaces.ts +0 -28
  222. package/src/circuit/listener.ts +0 -83
  223. package/src/circuit/multicodec.ts +0 -3
  224. package/src/circuit/relay.ts +0 -87
  225. package/src/circuit/reservation-store.ts +0 -106
  226. package/src/circuit/stop.ts +0 -92
  227. package/src/circuit/transport.ts +0 -313
  228. /package/dist/src/circuit/{reservation-voucher.d.ts → server/reservation-voucher.d.ts} +0 -0
@@ -1,381 +0,0 @@
1
- import { logger } from '@libp2p/logger'
2
- import { RELAY_V2_HOP_CODEC } from './multicodec.js'
3
- import { getExpiration, namespaceToCid } from './utils.js'
4
- import {
5
- CIRCUIT_PROTO_CODE,
6
- DEFAULT_MAX_RESERVATIONS,
7
- RELAY_RENDEZVOUS_NS
8
- } from './constants.js'
9
- import type { PeerId } from '@libp2p/interface-peer-id'
10
- import type { AddressSorter } from '@libp2p/interface-peer-store'
11
- import type { Connection } from '@libp2p/interface-connection'
12
- import sort from 'it-sort'
13
- import all from 'it-all'
14
- import { pipe } from 'it-pipe'
15
- import { publicAddressesFirst } from '@libp2p/utils/address-sort'
16
- import { reserve } from './hop.js'
17
- import { EventEmitter, CustomEvent } from '@libp2p/interfaces/events'
18
- import type { Startable } from '@libp2p/interfaces/startable'
19
- import type { Components } from '../components.js'
20
- import type { RelayReservationManagerConfig } from './index.js'
21
- import { PeerSet, PeerMap, PeerList } from '@libp2p/peer-collections'
22
-
23
- const log = logger('libp2p:circuit:client')
24
-
25
- const noop = () => {}
26
-
27
- /**
28
- * CircuitServiceInit initializes the circuit service using values
29
- * from the provided config and an @type{AddressSorter}.
30
- */
31
- export interface CircuitServiceInit extends RelayReservationManagerConfig {
32
- /**
33
- * Allows prioritizing addresses from the peerstore for dialing. The
34
- * default behavior is to prioritise public addresses.
35
- */
36
- addressSorter?: AddressSorter
37
- /**
38
- * A callback to invoke when an error occurs in the circuit service.
39
- */
40
- onError?: (error: Error) => void
41
- }
42
-
43
- export interface RelayReservationManagerEvents {
44
- 'relay:reservation': CustomEvent
45
- }
46
-
47
- /**
48
- * ReservationManager automatically makes a circuit v2 reservation on any connected
49
- * peers that support the circuit v2 HOP protocol.
50
- */
51
- export class RelayReservationManager extends EventEmitter<RelayReservationManagerEvents> implements Startable {
52
- private readonly components: Components
53
- private readonly addressSorter: AddressSorter
54
- private readonly maxReservations: number
55
- private readonly relays: PeerSet
56
- private readonly reservationMap: PeerMap<ReturnType<typeof setTimeout>>
57
- private readonly onError: (error: Error) => void
58
- private started: boolean
59
-
60
- constructor (components: Components, init: CircuitServiceInit) {
61
- super()
62
- this.started = false
63
- this.components = components
64
- this.addressSorter = init.addressSorter ?? publicAddressesFirst
65
- this.maxReservations = init.maxReservations ?? DEFAULT_MAX_RESERVATIONS
66
- this.relays = new PeerSet()
67
- this.reservationMap = new PeerMap()
68
- this.onError = init.onError ?? noop
69
-
70
- this._onProtocolChange = this._onProtocolChange.bind(this)
71
- this._onPeerDisconnected = this._onPeerDisconnected.bind(this)
72
- this._onPeerConnect = this._onPeerConnect.bind(this)
73
-
74
- this.components.peerStore.addEventListener('change:protocols', (evt) => {
75
- void this._onProtocolChange(evt.detail).catch(err => {
76
- log.error('handling protocol change failed', err)
77
- })
78
- })
79
-
80
- this.components.connectionManager.addEventListener('peer:disconnect', this._onPeerDisconnected)
81
- this.components.connectionManager.addEventListener('peer:connect', this._onPeerConnect)
82
- }
83
-
84
- isStarted () {
85
- return this.started
86
- }
87
-
88
- start () {
89
- void this._listenOnAvailableHopRelays().catch(err => { log.error('error listening on relays', err) })
90
- this.started = true
91
- }
92
-
93
- async stop () {
94
- this.reservationMap.forEach((timer) => clearTimeout(timer))
95
- this.reservationMap.clear()
96
- this.relays.clear()
97
- }
98
-
99
- /**
100
- * Check if a peer supports the relay protocol.
101
- * If the protocol is not supported, check if it was supported before and remove it as a listen relay.
102
- * If the protocol is supported, check if the peer supports **HOP** and add it as a listener if
103
- * inside the threshold.
104
- */
105
- async _onProtocolChange ({ peerId, protocols }: {peerId: PeerId, protocols: string[]}) {
106
- if (peerId.equals(this.components.peerId)) {
107
- return
108
- }
109
-
110
- // Check if it has the protocol
111
- const hasProtocol = protocols.includes(RELAY_V2_HOP_CODEC)
112
- log.trace('Peer %p protocol change %p', peerId, this.components.peerId)
113
-
114
- // If no protocol, check if we were keeping the peer before as a listenRelay
115
- if (!hasProtocol) {
116
- if (this.relays.has(peerId)) {
117
- await this._removeListenRelay(peerId)
118
- }
119
- return
120
- }
121
-
122
- if (this.relays.has(peerId)) {
123
- return
124
- }
125
-
126
- // If protocol, check if can hop, store info in the metadataBook and listen on it
127
- try {
128
- const connections = this.components.connectionManager.getConnections(peerId)
129
-
130
- // if no connections, try to listen on relay
131
- if (connections.length === 0) {
132
- void this._tryToListenOnRelay(peerId)
133
- return
134
- }
135
- const connection = connections[0]
136
-
137
- // Do not hop on a relayed connection
138
- if (connection.remoteAddr.protoCodes().includes(CIRCUIT_PROTO_CODE)) {
139
- log('relayed connection to %p will not be used to hop on', peerId)
140
- return
141
- }
142
-
143
- await this._addListenRelay(connection, peerId)
144
- } catch (err: any) {
145
- log.error('could not add %p as relay', peerId)
146
- this.onError(err)
147
- }
148
- }
149
-
150
- /**
151
- * Handle case when peer connects. If we already have the peer in the protobook,
152
- * we treat this event as an `onProtocolChange`.
153
- */
154
- _onPeerConnect ({ detail: connection }: CustomEvent<Connection>) {
155
- void this.components.peerStore.protoBook.get(connection.remotePeer)
156
- .then((protocols) => {
157
- void this._onProtocolChange({ peerId: connection.remotePeer, protocols })
158
- .catch((err) => log.error('handling reconnect failed', err))
159
- },
160
- (err) => {
161
- // this is not necessarily an error as we will only have the protocols stored
162
- // in case of a reconnect
163
- log.trace('could not fetch protocols for peer: %p', connection.remotePeer, err)
164
- })
165
- }
166
-
167
- /**
168
- * Peer disconnects
169
- */
170
- _onPeerDisconnected (evt: CustomEvent<Connection>) {
171
- const connection = evt.detail
172
- const peerId = connection.remotePeer
173
- clearTimeout(this.reservationMap.get(peerId))
174
- this.reservationMap.delete(peerId)
175
-
176
- // Not listening on this relay
177
- if (!this.relays.has(peerId)) {
178
- return
179
- }
180
-
181
- this._removeListenRelay(peerId).catch(err => {
182
- log.error(err)
183
- })
184
- }
185
-
186
- /**
187
- * Attempt to listen on the given relay connection
188
- */
189
- async _addListenRelay (connection: Connection, peerId: PeerId): Promise<void> {
190
- log.trace('peerId %p is being added as relay', peerId)
191
- try {
192
- // Check if already enough relay reservations
193
- if (this.relays.size >= this.maxReservations) {
194
- return
195
- }
196
-
197
- await this.createOrRefreshReservation(peerId)
198
-
199
- // Get peer known addresses and sort them with public addresses first
200
- const remoteAddrs = await pipe(
201
- await this.components.peerStore.addressBook.get(connection.remotePeer),
202
- (source) => sort(source, this.addressSorter),
203
- async (source) => await all(source)
204
- )
205
-
206
- // Attempt to listen on relay
207
- const result = await Promise.all(
208
- remoteAddrs.map(async addr => {
209
- let multiaddr = addr.multiaddr
210
-
211
- if (multiaddr.getPeerId() == null) {
212
- multiaddr = multiaddr.encapsulate(`/p2p/${connection.remotePeer.toString()}`)
213
- }
214
- multiaddr = multiaddr.encapsulate('/p2p-circuit')
215
- try {
216
- // Announce multiaddrs will update on listen success by TransportManager event being triggered
217
- await this.components.transportManager.listen([multiaddr])
218
- return true
219
- } catch (err: any) {
220
- log.error('error listening on circuit address', multiaddr, err)
221
- this.onError(err)
222
- }
223
-
224
- return false
225
- })
226
- )
227
-
228
- if (result.includes(true)) {
229
- this.relays.add(peerId)
230
- }
231
- } catch (err: any) {
232
- this.relays.delete(peerId)
233
- log.error('error adding relay for %p %s', peerId, err)
234
- this.onError(err)
235
- }
236
- }
237
-
238
- /**
239
- * Remove listen relay
240
- */
241
- async _removeListenRelay (PeerId: PeerId) {
242
- const recheck = this.relays.has(PeerId)
243
- this.relays.delete(PeerId)
244
- if (recheck) {
245
- // TODO: this should be responsibility of the connMgr
246
- await this._listenOnAvailableHopRelays(new PeerList([PeerId]))
247
- }
248
- }
249
-
250
- /**
251
- * Try to listen on available hop relay connections.
252
- * The following order will happen while we do not have enough relays.
253
- * 1. Check the metadata store for known relays, try to listen on the ones we are already connected.
254
- * 2. Dial and try to listen on the peers we know that support hop but are not connected.
255
- * 3. Search the network.
256
- */
257
- async _listenOnAvailableHopRelays (peersToIgnore: PeerList = new PeerList([])) {
258
- // Check if already listening on enough relays
259
- if (this.relays.size >= this.maxReservations) {
260
- return
261
- }
262
-
263
- const knownHopsToDial: PeerId[] = []
264
- const peers = (await this.components.peerStore.all())
265
- // filter by a list of peers supporting RELAY_V2_HOP and ones we are not listening on
266
- .filter(({ id, protocols }) =>
267
- protocols.includes(RELAY_V2_HOP_CODEC) && !this.relays.has(id) && !peersToIgnore.includes(id)
268
- )
269
- .map(({ id }) => {
270
- const connections = this.components.connectionManager.getConnections(id)
271
- if (connections.length === 0) {
272
- knownHopsToDial.push(id)
273
- return [id, null]
274
- }
275
- return [id, connections[0]]
276
- })
277
- .sort(() => Math.random() - 0.5)
278
-
279
- // Check if we have known hop peers to use and attempt to listen on the already connected
280
- for (const [id, conn] of peers) {
281
- await this._addListenRelay(conn as Connection, id as PeerId)
282
-
283
- // Check if already listening on enough relays
284
- if (this.relays.size >= this.maxReservations) {
285
- return
286
- }
287
- }
288
-
289
- // Try to listen on known peers that are not connected
290
- for (const peerId of knownHopsToDial) {
291
- // Check if already listening on enough relays
292
- if (this.relays.size >= this.maxReservations) {
293
- return
294
- }
295
-
296
- await this._tryToListenOnRelay(peerId)
297
- }
298
-
299
- // Try to find relays to hop on the network
300
- try {
301
- const cid = await namespaceToCid(RELAY_RENDEZVOUS_NS)
302
- for await (const provider of this.components.contentRouting.findProviders(cid)) {
303
- if (
304
- provider.multiaddrs.length > 0 &&
305
- !provider.id.equals(this.components.peerId)
306
- ) {
307
- const peerId = provider.id
308
-
309
- await this.components.peerStore.addressBook.add(peerId, provider.multiaddrs)
310
- await this._tryToListenOnRelay(peerId)
311
-
312
- // Check if already listening on enough relays
313
- if (this.relays.size >= this.maxReservations) {
314
- return
315
- }
316
- }
317
- }
318
- } catch (err: any) {
319
- log.error('failed when finding relays on the network', err)
320
- this.onError(err)
321
- }
322
- }
323
-
324
- async _tryToListenOnRelay (peerId: PeerId) {
325
- try {
326
- if (peerId.equals(this.components.peerId)) {
327
- log.trace('Skipping dialling self %p', peerId.toString())
328
- return
329
- }
330
- const connection = await this.components.connectionManager.openConnection(peerId)
331
- await this._addListenRelay(connection, peerId)
332
- } catch (err: any) {
333
- log.error('Could not connect and listen on relay %p', peerId, err)
334
- this.onError(err)
335
- }
336
- }
337
-
338
- private readonly createOrRefreshReservation = async (peerId: PeerId) => {
339
- try {
340
- const connections = this.components.connectionManager.getConnections(peerId)
341
-
342
- if (connections.length === 0) {
343
- throw new Error('No connections to peer')
344
- }
345
-
346
- const connection = connections[0]
347
-
348
- const reservation = await reserve(connection)
349
-
350
- const refreshReservation = this.createOrRefreshReservation
351
-
352
- if (reservation != null) {
353
- log('new reservation on %p', peerId)
354
-
355
- // clear any previous timeouts
356
- const previous = this.reservationMap.get(peerId)
357
- if (previous != null) {
358
- clearTimeout(previous)
359
- }
360
-
361
- const timeout = setTimeout(
362
- (peerId: PeerId) => {
363
- void refreshReservation(peerId).catch(err => {
364
- log.error('error refreshing reservation for %p', peerId, err)
365
- })
366
- },
367
- Math.max(getExpiration(reservation.expire) - 100, 0),
368
- peerId
369
- )
370
- this.reservationMap.set(
371
- peerId,
372
- timeout
373
- )
374
- this.dispatchEvent(new CustomEvent<unknown>('relay:reservation'))
375
- }
376
- } catch (err: any) {
377
- log.error(err)
378
- await this._removeListenRelay(peerId)
379
- }
380
- }
381
- }
@@ -1,210 +0,0 @@
1
- import type { PeerId } from '@libp2p/interface-peer-id'
2
- import { RecordEnvelope } from '@libp2p/peer-record'
3
- import { logger } from '@libp2p/logger'
4
- import type { Connection, Stream } from '@libp2p/interface-connection'
5
- import { HopMessage, Limit, Reservation, Status, StopMessage } from './pb/index.js'
6
- import type { Multiaddr } from '@multiformats/multiaddr'
7
- import { multiaddr } from '@multiformats/multiaddr'
8
- import type { Acl, ReservationStore } from './interfaces.js'
9
- import { RELAY_V2_HOP_CODEC } from './multicodec.js'
10
- import { stop } from './stop.js'
11
- import { ReservationVoucherRecord } from './reservation-voucher.js'
12
- import { peerIdFromBytes } from '@libp2p/peer-id'
13
- import type { ConnectionManager } from '@libp2p/interface-connection-manager'
14
- import type { ProtobufStream } from 'it-pb-stream'
15
- import { pbStream } from 'it-pb-stream'
16
- import { CIRCUIT_PROTO_CODE, RELAY_DESTINATION_TAG } from './constants.js'
17
- import type { PeerStore } from '@libp2p/interface-peer-store'
18
- import { createLimitedRelay } from './utils.js'
19
-
20
- const log = logger('libp2p:circuit:v2:hop')
21
-
22
- export interface HopProtocolOptions {
23
- connection: Connection
24
- request: HopMessage
25
- stream: ProtobufStream<Stream>
26
- relayPeer: PeerId
27
- relayAddrs: Multiaddr[]
28
- limit?: Limit
29
- acl?: Acl
30
- reservationStore: ReservationStore
31
- connectionManager: ConnectionManager
32
- peerStore: PeerStore
33
- }
34
-
35
- export async function handleHopProtocol (options: HopProtocolOptions): Promise<void> {
36
- const { stream, request } = options
37
- log('received hop message')
38
- switch (request.type) {
39
- case HopMessage.Type.RESERVE: await handleReserve(options); break
40
- case HopMessage.Type.CONNECT: await handleConnect(options); break
41
- default: {
42
- log.error('invalid hop request type %s via peer %s', options.request.type, options.connection.remotePeer)
43
- stream.pb(HopMessage).write({ type: HopMessage.Type.STATUS, status: Status.UNEXPECTED_MESSAGE })
44
- }
45
- }
46
- }
47
-
48
- export async function reserve (connection: Connection): Promise<Reservation> {
49
- log('requesting reservation from %s', connection.remotePeer)
50
- const stream = await connection.newStream([RELAY_V2_HOP_CODEC])
51
- const pbstr = pbStream(stream)
52
- const hopstr = pbstr.pb(HopMessage)
53
- hopstr.write({ type: HopMessage.Type.RESERVE })
54
-
55
- let response: HopMessage
56
- try {
57
- response = await hopstr.read()
58
- } catch (err: any) {
59
- log.error('error passing reserve message response from %s because', connection.remotePeer, err.message)
60
- stream.close()
61
- throw err
62
- }
63
-
64
- if (response.status === Status.OK && (response.reservation != null)) {
65
- return response.reservation
66
- }
67
- const errMsg = `reservation failed with status ${response.status ?? 'undefined'}`
68
- log.error(errMsg)
69
- throw new Error(errMsg)
70
- }
71
-
72
- const isRelayAddr = (ma: Multiaddr): boolean => ma.protoCodes().includes(CIRCUIT_PROTO_CODE)
73
-
74
- async function handleReserve ({ connection, stream: pbstr, relayPeer, relayAddrs, acl, reservationStore, peerStore }: HopProtocolOptions): Promise<void> {
75
- const hopstr = pbstr.pb(HopMessage)
76
- log('hop reserve request from %s', connection.remotePeer)
77
-
78
- if (isRelayAddr(connection.remoteAddr)) {
79
- log.error('relay reservation over circuit connection denied for peer: %p', connection.remotePeer)
80
- hopstr.write({ type: HopMessage.Type.STATUS, status: Status.PERMISSION_DENIED })
81
- return
82
- }
83
-
84
- if ((await acl?.allowReserve?.(connection.remotePeer, connection.remoteAddr)) === false) {
85
- log.error('acl denied reservation to %s', connection.remotePeer)
86
- hopstr.write({ type: HopMessage.Type.STATUS, status: Status.PERMISSION_DENIED })
87
- return
88
- }
89
-
90
- const result = await reservationStore.reserve(connection.remotePeer, connection.remoteAddr)
91
-
92
- if (result.status !== Status.OK) {
93
- hopstr.write({ type: HopMessage.Type.STATUS, status: result.status })
94
- return
95
- }
96
-
97
- try {
98
- // tag relayed peer
99
- // result.expire is non-null if `ReservationStore.reserve` returns with status == OK
100
- if (result.expire != null) {
101
- const ttl = new Date().getTime() - result.expire
102
- await peerStore.tagPeer(relayPeer, RELAY_DESTINATION_TAG, { value: 1, ttl })
103
- }
104
- hopstr.write({
105
- type: HopMessage.Type.STATUS,
106
- status: Status.OK,
107
- reservation: await makeReservation(relayAddrs, relayPeer, connection.remotePeer, BigInt(result.expire ?? 0)),
108
- limit: (await reservationStore.get(relayPeer))?.limit
109
- })
110
- log('sent confirmation response to %s', connection.remotePeer)
111
- } catch (err) {
112
- log.error('failed to send confirmation response to %s', connection.remotePeer)
113
- await reservationStore.removeReservation(connection.remotePeer)
114
- }
115
- }
116
-
117
- async function handleConnect (options: HopProtocolOptions): Promise<void> {
118
- const { connection, stream, request, reservationStore, connectionManager, acl } = options
119
- const hopstr = stream.pb(HopMessage)
120
-
121
- log('hop connect request from %s', connection.remotePeer)
122
-
123
- let dstPeer: PeerId
124
- try {
125
- if (request.peer == null) {
126
- log.error('no peer info in hop connect request')
127
- throw new Error('no peer info in request')
128
- }
129
- request.peer.addrs.forEach(multiaddr)
130
- dstPeer = peerIdFromBytes(request.peer.id)
131
- } catch (err) {
132
- log.error('invalid hop connect request via peer %p %s', connection.remotePeer, err)
133
- hopstr.write({ type: HopMessage.Type.STATUS, status: Status.MALFORMED_MESSAGE })
134
- return
135
- }
136
-
137
- if (acl?.allowConnect !== undefined) {
138
- const status = await acl.allowConnect(connection.remotePeer, connection.remoteAddr, dstPeer)
139
- if (status !== Status.OK) {
140
- log.error('hop connect denied for %s with status %s', connection.remotePeer, status)
141
- hopstr.write({ type: HopMessage.Type.STATUS, status: status })
142
- return
143
- }
144
- }
145
-
146
- if (!await reservationStore.hasReservation(dstPeer)) {
147
- log.error('hop connect denied for %s with status %s', connection.remotePeer, Status.NO_RESERVATION)
148
- hopstr.write({ type: HopMessage.Type.STATUS, status: Status.NO_RESERVATION })
149
- return
150
- }
151
-
152
- const connections = connectionManager.getConnections(dstPeer)
153
- if (connections.length === 0) {
154
- log('hop connect denied for %s as there is no destination connection', connection.remotePeer)
155
- hopstr.write({ type: HopMessage.Type.STATUS, status: Status.NO_RESERVATION })
156
- return
157
- }
158
- const destinationConnection = connections[0]
159
- log('hop connect request from %s to %s is valid', connection.remotePeer, dstPeer)
160
-
161
- const destinationStream = await stop({
162
- connection: destinationConnection,
163
- request: {
164
- type: StopMessage.Type.CONNECT,
165
- peer: {
166
- id: connection.remotePeer.toBytes(),
167
- addrs: [multiaddr('/p2p/' + connection.remotePeer.toString()).bytes]
168
- }
169
- }
170
- })
171
-
172
- if (destinationStream == null) {
173
- log.error('failed to open stream to destination peer %s', destinationConnection?.remotePeer)
174
- hopstr.write({ type: HopMessage.Type.STATUS, status: Status.CONNECTION_FAILED })
175
- return
176
- }
177
-
178
- hopstr.write({ type: HopMessage.Type.STATUS, status: Status.OK })
179
- const sourceStream = stream.unwrap()
180
-
181
- log('connection to destination established, short circuiting streams...')
182
- const limit = (await reservationStore.get(dstPeer))?.limit
183
- // Short circuit the two streams to create the relayed connection
184
- return createLimitedRelay(sourceStream, destinationStream, limit)
185
- }
186
-
187
- async function makeReservation (
188
- relayAddrs: Multiaddr[],
189
- relayPeerId: PeerId,
190
- remotePeer: PeerId,
191
- expire: bigint
192
- ): Promise<Reservation> {
193
- const addrs = []
194
-
195
- for (const relayAddr of relayAddrs) {
196
- addrs.push(relayAddr.bytes)
197
- }
198
-
199
- const voucher = await RecordEnvelope.seal(new ReservationVoucherRecord({
200
- peer: remotePeer,
201
- relay: relayPeerId,
202
- expiration: Number(expire)
203
- }), relayPeerId)
204
-
205
- return {
206
- addrs,
207
- expire,
208
- voucher: voucher.marshal()
209
- }
210
- }
@@ -1,28 +0,0 @@
1
- import type { PeerId } from '@libp2p/interface-peer-id'
2
- import type { Multiaddr } from '@multiformats/multiaddr'
3
- import type { Limit, Status } from './pb/index.js'
4
-
5
- export type ReservationStatus = Status.OK | Status.PERMISSION_DENIED | Status.RESERVATION_REFUSED
6
-
7
- export interface Reservation {
8
- addr: Multiaddr
9
- expire: Date
10
- limit?: Limit
11
- }
12
-
13
- export interface ReservationStore {
14
- reserve: (peer: PeerId, addr: Multiaddr, limit?: Limit) => {status: ReservationStatus, expire?: number}
15
- removeReservation: (peer: PeerId) => void
16
- hasReservation: (dst: PeerId) => boolean
17
- get: (peer: PeerId) => Reservation | undefined
18
- }
19
-
20
- export type AclStatus = Status.OK | Status.RESOURCE_LIMIT_EXCEEDED | Status.PERMISSION_DENIED
21
-
22
- export interface Acl {
23
- allowReserve: (peer: PeerId, addr: Multiaddr) => Promise<boolean>
24
- /**
25
- * Checks if connection should be allowed
26
- */
27
- allowConnect: (src: PeerId, addr: Multiaddr, dst: PeerId) => Promise<AclStatus>
28
- }
@@ -1,83 +0,0 @@
1
- import { CustomEvent, EventEmitter } from '@libp2p/interfaces/events'
2
- import type { ConnectionManager } from '@libp2p/interface-connection-manager'
3
- import type { PeerStore } from '@libp2p/interface-peer-store'
4
- import type { Listener } from '@libp2p/interface-transport'
5
- import { peerIdFromString } from '@libp2p/peer-id'
6
- import type { Multiaddr } from '@multiformats/multiaddr'
7
- import { multiaddr } from '@multiformats/multiaddr'
8
-
9
- export interface ListenerOptions {
10
- peerStore: PeerStore
11
- connectionManager: ConnectionManager
12
- }
13
-
14
- export function createListener (options: ListenerOptions): Listener {
15
- const listeningAddrs = new Map()
16
-
17
- /**
18
- * Add swarm handler and listen for incoming connections
19
- */
20
- async function listen (addr: Multiaddr): Promise<void> {
21
- const addrString = addr.toString().split('/p2p-circuit').find(a => a !== '')
22
- const ma = multiaddr(addrString)
23
-
24
- const relayPeerStr = ma.getPeerId()
25
-
26
- if (relayPeerStr == null) {
27
- throw new Error('Could not determine relay peer from multiaddr')
28
- }
29
-
30
- const relayPeerId = peerIdFromString(relayPeerStr)
31
-
32
- await options.peerStore.addressBook.add(relayPeerId, [ma])
33
-
34
- const relayConn = await options.connectionManager.openConnection(relayPeerId)
35
- const relayedAddr = relayConn.remoteAddr.encapsulate('/p2p-circuit')
36
-
37
- listeningAddrs.set(relayConn.remotePeer.toString(), relayedAddr)
38
- listener.dispatchEvent(new CustomEvent('listening'))
39
- }
40
-
41
- /**
42
- * Get fixed up multiaddrs
43
- *
44
- * NOTE: This method will grab the peers multiaddrs and expand them such that:
45
- *
46
- * a) If it's an existing /p2p-circuit address for a specific relay i.e.
47
- * `/ip4/0.0.0.0/tcp/0/ipfs/QmRelay/p2p-circuit` this method will expand the
48
- * address to `/ip4/0.0.0.0/tcp/0/ipfs/QmRelay/p2p-circuit/ipfs/QmPeer` where
49
- * `QmPeer` is this peers id
50
- * b) If it's not a /p2p-circuit address, it will encapsulate the address as a /p2p-circuit
51
- * addr, such when dialing over a relay with this address, it will create the circuit using
52
- * the encapsulated transport address. This is useful when for example, a peer should only
53
- * be dialed over TCP rather than any other transport
54
- *
55
- * @returns {Multiaddr[]}
56
- */
57
- function getAddrs () {
58
- const addrs = []
59
- for (const addr of listeningAddrs.values()) {
60
- addrs.push(addr)
61
- }
62
- return addrs
63
- }
64
-
65
- const listener: Listener = Object.assign(new EventEmitter(), {
66
- close: async () => await Promise.resolve(),
67
- listen,
68
- getAddrs
69
- })
70
-
71
- // Remove listeningAddrs when a peer disconnects
72
- options.connectionManager.addEventListener('peer:disconnect', (evt) => {
73
- const { detail: connection } = evt
74
- const deleted = listeningAddrs.delete(connection.remotePeer.toString())
75
-
76
- if (deleted) {
77
- // Announce listen addresses change
78
- listener.dispatchEvent(new CustomEvent('close'))
79
- }
80
- })
81
-
82
- return listener
83
- }