@helia/bitswap 4.0.8 → 4.0.9
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.
- package/dist/index.min.js +2 -1
- package/dist/index.min.js.map +4 -4
- package/dist/src/bitswap.d.ts.map +1 -1
- package/dist/src/bitswap.js +1 -0
- package/dist/src/bitswap.js.map +1 -1
- package/dist/src/constants.d.ts +2 -0
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +2 -0
- package/dist/src/constants.js.map +1 -1
- package/dist/src/index.d.ts +17 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/peer-want-lists/index.d.ts +11 -3
- package/dist/src/peer-want-lists/index.d.ts.map +1 -1
- package/dist/src/peer-want-lists/index.js +24 -15
- package/dist/src/peer-want-lists/index.js.map +1 -1
- package/dist/src/peer-want-lists/ledger.d.ts +11 -2
- package/dist/src/peer-want-lists/ledger.d.ts.map +1 -1
- package/dist/src/peer-want-lists/ledger.js +56 -2
- package/dist/src/peer-want-lists/ledger.js.map +1 -1
- package/package.json +2 -1
- package/src/bitswap.ts +1 -0
- package/src/constants.ts +2 -0
- package/src/index.ts +18 -3
- package/src/peer-want-lists/index.ts +33 -21
- package/src/peer-want-lists/ledger.ts +68 -4
|
@@ -4,8 +4,9 @@ import { Ledger } from './ledger.ts'
|
|
|
4
4
|
import type { BitswapNotifyProgressEvents, PeerWantListEntry } from '../index.ts'
|
|
5
5
|
import type { Network } from '../network.ts'
|
|
6
6
|
import type { BitswapMessage } from '../pb/message.ts'
|
|
7
|
-
import type { AbortOptions, ComponentLogger, Libp2p, Logger, Metrics, PeerId } from '@libp2p/interface'
|
|
7
|
+
import type { AbortOptions, ComponentLogger, Libp2p, Logger, Metrics, PeerId, Startable } from '@libp2p/interface'
|
|
8
8
|
import type { PeerMap } from '@libp2p/peer-collections'
|
|
9
|
+
import type { Queue } from '@libp2p/utils'
|
|
9
10
|
import type { Blockstore } from 'interface-blockstore'
|
|
10
11
|
import type { ProgressOptions } from 'progress-events'
|
|
11
12
|
|
|
@@ -13,6 +14,8 @@ export interface PeerWantListsInit {
|
|
|
13
14
|
maxSizeReplaceHasWithBlock?: number
|
|
14
15
|
doNotResendBlockWindow?: number
|
|
15
16
|
maxWantListSize?: number
|
|
17
|
+
sendBlocksConcurrency?: number
|
|
18
|
+
sendBlocksMaxQueueLength?: number
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
export interface PeerWantListsComponents {
|
|
@@ -29,15 +32,18 @@ export interface PeerLedger {
|
|
|
29
32
|
sent: number
|
|
30
33
|
received: number
|
|
31
34
|
exchanged: number
|
|
35
|
+
sendQueue: Queue
|
|
32
36
|
}
|
|
33
37
|
|
|
34
|
-
export class PeerWantLists {
|
|
38
|
+
export class PeerWantLists implements Startable {
|
|
35
39
|
public blockstore: Blockstore
|
|
36
40
|
public network: Network
|
|
37
41
|
public readonly ledgerMap: PeerMap<Ledger>
|
|
38
42
|
private readonly maxSizeReplaceHasWithBlock?: number
|
|
39
43
|
private readonly doNotResendBlockWindow?: number
|
|
40
44
|
private readonly maxWantListSize?: number
|
|
45
|
+
private readonly sendBlocksConcurrency?: number
|
|
46
|
+
private readonly sendBlocksMaxQueueLength?: number
|
|
41
47
|
private readonly log: Logger
|
|
42
48
|
private readonly logger: ComponentLogger
|
|
43
49
|
|
|
@@ -47,6 +53,8 @@ export class PeerWantLists {
|
|
|
47
53
|
this.maxSizeReplaceHasWithBlock = init.maxSizeReplaceHasWithBlock
|
|
48
54
|
this.doNotResendBlockWindow = init.doNotResendBlockWindow
|
|
49
55
|
this.maxWantListSize = init.maxWantListSize
|
|
56
|
+
this.sendBlocksConcurrency = init.sendBlocksConcurrency
|
|
57
|
+
this.sendBlocksMaxQueueLength = init.sendBlocksMaxQueueLength
|
|
50
58
|
this.log = components.logger.forComponent('helia:bitswap:peer-want-lists')
|
|
51
59
|
this.logger = components.logger
|
|
52
60
|
|
|
@@ -56,16 +64,27 @@ export class PeerWantLists {
|
|
|
56
64
|
})
|
|
57
65
|
|
|
58
66
|
this.network.addEventListener('bitswap:message', (evt) => {
|
|
59
|
-
|
|
60
|
-
.
|
|
61
|
-
|
|
62
|
-
|
|
67
|
+
try {
|
|
68
|
+
this.receiveMessage(evt.detail.connection.remotePeer, evt.detail.message)
|
|
69
|
+
} catch (err) {
|
|
70
|
+
this.log.error('error receiving bitswap message from %p - %e', evt.detail.connection.remotePeer, err)
|
|
71
|
+
}
|
|
63
72
|
})
|
|
64
73
|
this.network.addEventListener('peer:disconnected', evt => {
|
|
65
74
|
this.peerDisconnected(evt.detail)
|
|
66
75
|
})
|
|
67
76
|
}
|
|
68
77
|
|
|
78
|
+
start (): void {
|
|
79
|
+
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
stop (): void {
|
|
83
|
+
this.ledgerMap.forEach(ledger => {
|
|
84
|
+
ledger.stop()
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
|
|
69
88
|
ledgerForPeer (peerId: PeerId): PeerLedger | undefined {
|
|
70
89
|
const ledger = this.ledgerMap.get(peerId)
|
|
71
90
|
|
|
@@ -78,7 +97,8 @@ export class PeerWantLists {
|
|
|
78
97
|
value: ledger.debtRatio(),
|
|
79
98
|
sent: ledger.bytesSent,
|
|
80
99
|
received: ledger.bytesReceived,
|
|
81
|
-
exchanged: ledger.exchangeCount
|
|
100
|
+
exchanged: ledger.exchangeCount,
|
|
101
|
+
sendQueue: ledger.sendQueue
|
|
82
102
|
}
|
|
83
103
|
}
|
|
84
104
|
|
|
@@ -102,7 +122,7 @@ export class PeerWantLists {
|
|
|
102
122
|
/**
|
|
103
123
|
* Handle incoming messages
|
|
104
124
|
*/
|
|
105
|
-
|
|
125
|
+
receiveMessage (peerId: PeerId, message: BitswapMessage): void {
|
|
106
126
|
let ledger = this.ledgerMap.get(peerId)
|
|
107
127
|
|
|
108
128
|
if (ledger == null) {
|
|
@@ -114,22 +134,14 @@ export class PeerWantLists {
|
|
|
114
134
|
}, {
|
|
115
135
|
maxSizeReplaceHasWithBlock: this.maxSizeReplaceHasWithBlock,
|
|
116
136
|
doNotResendBlockWindow: this.doNotResendBlockWindow,
|
|
117
|
-
maxWantListSize: this.maxWantListSize
|
|
137
|
+
maxWantListSize: this.maxWantListSize,
|
|
138
|
+
sendBlocksConcurrency: this.sendBlocksConcurrency,
|
|
139
|
+
sendBlocksMaxQueueLength: this.sendBlocksMaxQueueLength
|
|
118
140
|
})
|
|
119
141
|
this.ledgerMap.set(peerId, ledger)
|
|
120
142
|
}
|
|
121
143
|
|
|
122
|
-
|
|
123
|
-
ledger.receivedBytes(message.blocks?.reduce((acc, curr) => acc + curr.data.byteLength, 0) ?? 0)
|
|
124
|
-
|
|
125
|
-
// remove any expired wants
|
|
126
|
-
ledger.removeExpiredWants()
|
|
127
|
-
|
|
128
|
-
// add new wants
|
|
129
|
-
ledger.addWants(message.wantlist)
|
|
130
|
-
|
|
131
|
-
this.log('send blocks to peer')
|
|
132
|
-
await ledger.sendBlocksToPeer()
|
|
144
|
+
ledger.queueSendOperation(message)
|
|
133
145
|
}
|
|
134
146
|
|
|
135
147
|
async receivedBlock (cid: CID, options: ProgressOptions<BitswapNotifyProgressEvents> & AbortOptions): Promise<void> {
|
|
@@ -142,7 +154,7 @@ export class PeerWantLists {
|
|
|
142
154
|
}
|
|
143
155
|
|
|
144
156
|
await Promise.all(
|
|
145
|
-
ledgers.map(async (ledger) => ledger.
|
|
157
|
+
ledgers.map(async (ledger) => ledger.queueSendOperation(undefined, options))
|
|
146
158
|
)
|
|
147
159
|
}
|
|
148
160
|
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
+
import { Queue } from '@libp2p/utils'
|
|
2
|
+
import { NotFoundError } from 'interface-store'
|
|
1
3
|
import toBuffer from 'it-to-buffer'
|
|
2
4
|
import { CID } from 'multiformats/cid'
|
|
3
5
|
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
|
4
|
-
import { DEFAULT_MAX_SIZE_REPLACE_HAS_WITH_BLOCK, DEFAULT_DO_NOT_RESEND_BLOCK_WINDOW, DEFAULT_MAX_WANTLIST_SIZE } from '../constants.ts'
|
|
6
|
+
import { DEFAULT_MAX_SIZE_REPLACE_HAS_WITH_BLOCK, DEFAULT_DO_NOT_RESEND_BLOCK_WINDOW, DEFAULT_MAX_WANTLIST_SIZE, DEFAULT_PEER_MESSAGE_SEND_CONCURRENCY, DEFAULT_PEER_MAX_MESSAGE_SEND_QUEUE_LENGTH } from '../constants.ts'
|
|
5
7
|
import { BlockPresenceType, WantType } from '../pb/message.ts'
|
|
6
8
|
import { QueuedBitswapMessage } from '../utils/bitswap-message.ts'
|
|
7
9
|
import { cidToPrefix } from '../utils/cid-prefix.ts'
|
|
10
|
+
import type { BitswapNotifyProgressEvents } from '../index.ts'
|
|
8
11
|
import type { Network } from '../network.ts'
|
|
9
|
-
import type { Wantlist } from '../pb/message.ts'
|
|
12
|
+
import type { BitswapMessage, Wantlist } from '../pb/message.ts'
|
|
10
13
|
import type { AbortOptions, ComponentLogger, Logger, PeerId } from '@libp2p/interface'
|
|
11
14
|
import type { Blockstore } from 'interface-blockstore'
|
|
15
|
+
import type { ProgressOptions } from 'progress-events'
|
|
12
16
|
|
|
13
17
|
export interface LedgerComponents {
|
|
14
18
|
peerId: PeerId
|
|
@@ -21,6 +25,9 @@ export interface LedgerInit {
|
|
|
21
25
|
maxSizeReplaceHasWithBlock?: number
|
|
22
26
|
doNotResendBlockWindow?: number
|
|
23
27
|
maxWantListSize?: number
|
|
28
|
+
sendBlocksConcurrency?: number
|
|
29
|
+
sendBlocksMaxQueueLength?: number
|
|
30
|
+
sendBlocksTimeout?: number
|
|
24
31
|
}
|
|
25
32
|
|
|
26
33
|
export interface PeerWantListEntry {
|
|
@@ -89,6 +96,7 @@ export class Ledger {
|
|
|
89
96
|
public bytesSent: number
|
|
90
97
|
public bytesReceived: number
|
|
91
98
|
public lastExchange?: number
|
|
99
|
+
public readonly sendQueue: Queue
|
|
92
100
|
private readonly maxSizeReplaceHasWithBlock: number
|
|
93
101
|
private readonly log: Logger
|
|
94
102
|
private readonly doNotResendBlockWindow: number
|
|
@@ -107,6 +115,15 @@ export class Ledger {
|
|
|
107
115
|
this.maxSizeReplaceHasWithBlock = init.maxSizeReplaceHasWithBlock ?? DEFAULT_MAX_SIZE_REPLACE_HAS_WITH_BLOCK
|
|
108
116
|
this.doNotResendBlockWindow = init.doNotResendBlockWindow ?? DEFAULT_DO_NOT_RESEND_BLOCK_WINDOW
|
|
109
117
|
this.maxWantListSize = init.maxWantListSize ?? DEFAULT_MAX_WANTLIST_SIZE
|
|
118
|
+
|
|
119
|
+
this.sendQueue = new Queue({
|
|
120
|
+
concurrency: init.sendBlocksConcurrency ?? DEFAULT_PEER_MESSAGE_SEND_CONCURRENCY,
|
|
121
|
+
maxSize: init.sendBlocksMaxQueueLength ?? DEFAULT_PEER_MAX_MESSAGE_SEND_QUEUE_LENGTH
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
stop (): void {
|
|
126
|
+
this.sendQueue.abort()
|
|
110
127
|
}
|
|
111
128
|
|
|
112
129
|
sentBytes (n: number): void {
|
|
@@ -261,7 +278,37 @@ export class Ledger {
|
|
|
261
278
|
return this.wants.has(cidStr)
|
|
262
279
|
}
|
|
263
280
|
|
|
264
|
-
public
|
|
281
|
+
public queueSendOperation (message?: BitswapMessage, options?: ProgressOptions<BitswapNotifyProgressEvents> & AbortOptions): void {
|
|
282
|
+
if (message != null) {
|
|
283
|
+
// record the amount of block data received
|
|
284
|
+
this.receivedBytes(message.blocks?.reduce((acc, curr) => acc + curr.data.byteLength, 0) ?? 0)
|
|
285
|
+
|
|
286
|
+
// add new wants
|
|
287
|
+
this.addWants(message.wantlist)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
try {
|
|
291
|
+
this.sendQueue.add(async (options) => {
|
|
292
|
+
this.log('send blocks to peer')
|
|
293
|
+
await this.sendBlocksToPeer(options)
|
|
294
|
+
}, options)
|
|
295
|
+
.catch(err => {
|
|
296
|
+
if (err.name === 'QueueFullError') {
|
|
297
|
+
this.log.error('Dropping bitswap message as peer send queue is full')
|
|
298
|
+
} else {
|
|
299
|
+
this.log.error('Error when trying to add queue a send operation')
|
|
300
|
+
}
|
|
301
|
+
})
|
|
302
|
+
} catch (err: any) {
|
|
303
|
+
if (err.name === 'QueueFullError') {
|
|
304
|
+
this.log.error('Dropping bitswap message as peer send queue is full')
|
|
305
|
+
} else {
|
|
306
|
+
throw err
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
private async sendBlocksToPeer (options?: AbortOptions): Promise<void> {
|
|
265
312
|
const message = new QueuedBitswapMessage()
|
|
266
313
|
const sentBlocks = new Set<string>()
|
|
267
314
|
|
|
@@ -270,7 +317,15 @@ export class Ledger {
|
|
|
270
317
|
|
|
271
318
|
// pick unsent wants
|
|
272
319
|
const unsent = [...this.wants.entries()]
|
|
273
|
-
.filter(([key, value]) =>
|
|
320
|
+
.filter(([key, value]) => {
|
|
321
|
+
// don't process the same want more than once per send iteration
|
|
322
|
+
return value.status === 'want'
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
// break out of the for loop early if we have no work to do
|
|
326
|
+
if (unsent.length === 0) {
|
|
327
|
+
return
|
|
328
|
+
}
|
|
274
329
|
|
|
275
330
|
// update status, ensure we don't send the same blocks repeatedly
|
|
276
331
|
unsent.forEach(([key, value]) => {
|
|
@@ -279,6 +334,15 @@ export class Ledger {
|
|
|
279
334
|
|
|
280
335
|
for (const [key, entry] of unsent) {
|
|
281
336
|
try {
|
|
337
|
+
// call `.has` and not `.get` because `.get` can cause network
|
|
338
|
+
// operations to occur
|
|
339
|
+
const has = await this.blockstore.has(entry.cid, options)
|
|
340
|
+
|
|
341
|
+
if (!has) {
|
|
342
|
+
// can't sent a block we don't have
|
|
343
|
+
throw new NotFoundError()
|
|
344
|
+
}
|
|
345
|
+
|
|
282
346
|
const block = await toBuffer(this.blockstore.get(entry.cid, options))
|
|
283
347
|
|
|
284
348
|
// ensure we still need to send the block/status, status may have
|