@peerbit/stream 5.0.1-dac5207 → 5.0.2
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/benchmark/chunk-transfer.d.ts +2 -0
- package/dist/benchmark/chunk-transfer.d.ts.map +1 -0
- package/dist/benchmark/chunk-transfer.js +221 -0
- package/dist/benchmark/chunk-transfer.js.map +1 -0
- package/dist/benchmark/index.d.ts +1 -0
- package/dist/benchmark/index.d.ts.map +1 -1
- package/dist/benchmark/index.js +8 -2
- package/dist/benchmark/index.js.map +1 -1
- package/dist/benchmark/transfer.js +233 -72
- package/dist/benchmark/transfer.js.map +1 -1
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +48 -37
- package/dist/src/index.js.map +1 -1
- package/package.json +10 -8
- package/src/index.ts +90 -70
package/src/index.ts
CHANGED
|
@@ -19,6 +19,7 @@ import { type Multiaddr, multiaddr } from "@multiformats/multiaddr";
|
|
|
19
19
|
import { Circuit } from "@multiformats/multiaddr-matcher";
|
|
20
20
|
import { Cache } from "@peerbit/cache";
|
|
21
21
|
import {
|
|
22
|
+
PreHash,
|
|
22
23
|
PublicSignKey,
|
|
23
24
|
getKeypairFromPrivateKey,
|
|
24
25
|
getPublicKeyFromPeerId,
|
|
@@ -29,6 +30,7 @@ import {
|
|
|
29
30
|
import type { SignatureWithKey } from "@peerbit/crypto";
|
|
30
31
|
import {
|
|
31
32
|
ACK,
|
|
33
|
+
ACK_CONTROL_PRIORITY,
|
|
32
34
|
AcknowledgeAnyWhere,
|
|
33
35
|
AcknowledgeDelivery,
|
|
34
36
|
AnyWhere,
|
|
@@ -41,10 +43,18 @@ import {
|
|
|
41
43
|
MultiAddrinfo,
|
|
42
44
|
NotStartedError,
|
|
43
45
|
SilentDelivery,
|
|
46
|
+
Signatures,
|
|
44
47
|
TracedDelivery,
|
|
48
|
+
appendDeliveryHop,
|
|
45
49
|
coercePeerRefsToHashes,
|
|
46
50
|
deliveryModeHasReceiver,
|
|
51
|
+
getMessageExpiresAt,
|
|
47
52
|
getMsgId,
|
|
53
|
+
getDeliveryHopTrace,
|
|
54
|
+
getResponsePriorityFromMessage,
|
|
55
|
+
hasDeliveryHop,
|
|
56
|
+
isAcknowledgedDeliveryMode,
|
|
57
|
+
setDeliveryOriginHop,
|
|
48
58
|
} from "@peerbit/stream-interface";
|
|
49
59
|
import type {
|
|
50
60
|
DirectStreamAckRouteHint,
|
|
@@ -204,7 +214,7 @@ type PeerOutboundQueueOptions = Pick<
|
|
|
204
214
|
>;
|
|
205
215
|
interface OutboundCandidate {
|
|
206
216
|
raw: Stream;
|
|
207
|
-
pushable: PushableLanes<Uint8Array>;
|
|
217
|
+
pushable: PushableLanes<Uint8Array | Uint8ArrayList>;
|
|
208
218
|
created: number;
|
|
209
219
|
bytesDelivered: number;
|
|
210
220
|
aborted: boolean;
|
|
@@ -308,7 +318,9 @@ export class PeerStreams extends TypedEventEmitter<PeerStreamEvents> {
|
|
|
308
318
|
public get rawOutboundStreams(): Stream[] {
|
|
309
319
|
return this.outboundStreams.map((c) => c.raw);
|
|
310
320
|
}
|
|
311
|
-
public _getActiveOutboundPushable():
|
|
321
|
+
public _getActiveOutboundPushable():
|
|
322
|
+
| PushableLanes<Uint8Array | Uint8ArrayList>
|
|
323
|
+
| undefined {
|
|
312
324
|
return this.outboundStreams[0]?.pushable;
|
|
313
325
|
}
|
|
314
326
|
public getOutboundQueuedBytes(): number {
|
|
@@ -351,15 +363,15 @@ export class PeerStreams extends TypedEventEmitter<PeerStreamEvents> {
|
|
|
351
363
|
private _addOutboundCandidate(raw: Stream): OutboundCandidate {
|
|
352
364
|
const existing = this.outboundStreams.find((c) => c.raw === raw);
|
|
353
365
|
if (existing) return existing;
|
|
354
|
-
const pushableInst = pushableLanes<Uint8Array>({
|
|
366
|
+
const pushableInst = pushableLanes<Uint8Array | Uint8ArrayList>({
|
|
355
367
|
lanes: PRIORITY_LANES,
|
|
356
368
|
maxBufferedBytes: this.outboundQueue?.maxBufferedBytes,
|
|
357
369
|
overflow: "throw",
|
|
358
370
|
onBufferSize: () => {
|
|
359
371
|
this.dispatchEvent(new CustomEvent("queue:outbound"));
|
|
360
372
|
},
|
|
361
|
-
onPush: (val
|
|
362
|
-
candidate.bytesDelivered += val.
|
|
373
|
+
onPush: (val) => {
|
|
374
|
+
candidate.bytesDelivered += val.byteLength;
|
|
363
375
|
},
|
|
364
376
|
});
|
|
365
377
|
const candidate: OutboundCandidate = {
|
|
@@ -383,9 +395,7 @@ export class PeerStreams extends TypedEventEmitter<PeerStreamEvents> {
|
|
|
383
395
|
new AbortError("Outbound stream aborted")
|
|
384
396
|
);
|
|
385
397
|
}
|
|
386
|
-
|
|
387
|
-
chunk instanceof Uint8ArrayList ? chunk.subarray() : chunk;
|
|
388
|
-
if (!raw.send(bytes)) {
|
|
398
|
+
if (!raw.send(chunk)) {
|
|
389
399
|
await waitForDrain(raw, this.outboundAbortController.signal);
|
|
390
400
|
}
|
|
391
401
|
}
|
|
@@ -547,7 +557,7 @@ export class PeerStreams extends TypedEventEmitter<PeerStreamEvents> {
|
|
|
547
557
|
}
|
|
548
558
|
|
|
549
559
|
// Write to all current outbound streams (normally 1, but >1 during grace)
|
|
550
|
-
const
|
|
560
|
+
const payloadBytes = data.byteLength;
|
|
551
561
|
let successes = 0;
|
|
552
562
|
let failures: any[] = [];
|
|
553
563
|
const failed: OutboundCandidate[] = [];
|
|
@@ -559,8 +569,8 @@ export class PeerStreams extends TypedEventEmitter<PeerStreamEvents> {
|
|
|
559
569
|
}
|
|
560
570
|
|
|
561
571
|
try {
|
|
562
|
-
this.assertQueueCapacity(c,
|
|
563
|
-
c.pushable.push(
|
|
572
|
+
this.assertQueueCapacity(c, payloadBytes, priority);
|
|
573
|
+
c.pushable.push(data, getLaneFromPriority(priority));
|
|
564
574
|
successes++;
|
|
565
575
|
} catch (e) {
|
|
566
576
|
failures.push(e);
|
|
@@ -606,7 +616,7 @@ export class PeerStreams extends TypedEventEmitter<PeerStreamEvents> {
|
|
|
606
616
|
else this.dispatchEvent(new CustomEvent("stream:outbound"));
|
|
607
617
|
}
|
|
608
618
|
}
|
|
609
|
-
this.usedBandWidthTracker.add(
|
|
619
|
+
this.usedBandWidthTracker.add(payloadBytes);
|
|
610
620
|
}
|
|
611
621
|
|
|
612
622
|
/**
|
|
@@ -1077,6 +1087,7 @@ export abstract class DirectStream<
|
|
|
1077
1087
|
public publicKey: PublicSignKey;
|
|
1078
1088
|
public publicKeyHash: string;
|
|
1079
1089
|
public sign: (bytes: Uint8Array) => Promise<SignatureWithKey>;
|
|
1090
|
+
private signPreparedSha256: (bytes: Uint8Array) => Promise<SignatureWithKey>;
|
|
1080
1091
|
|
|
1081
1092
|
public started: boolean;
|
|
1082
1093
|
public stopping: boolean;
|
|
@@ -1172,7 +1183,12 @@ export abstract class DirectStream<
|
|
|
1172
1183
|
|
|
1173
1184
|
const signKey = getKeypairFromPrivateKey(components.privateKey);
|
|
1174
1185
|
this.seekTimeout = seekTimeout;
|
|
1175
|
-
this.sign = signKey.sign.
|
|
1186
|
+
this.sign = (bytes) => signKey.sign(bytes, PreHash.SHA_256);
|
|
1187
|
+
this.signPreparedSha256 = async (bytes) => {
|
|
1188
|
+
const signature = await signKey.sign(bytes, PreHash.NONE);
|
|
1189
|
+
signature.prehash = PreHash.SHA_256;
|
|
1190
|
+
return signature;
|
|
1191
|
+
};
|
|
1176
1192
|
this.peerId = components.peerId;
|
|
1177
1193
|
this.publicKey = signKey.publicKey;
|
|
1178
1194
|
if (inboundIdleTimeout != null)
|
|
@@ -2126,8 +2142,10 @@ export abstract class DirectStream<
|
|
|
2126
2142
|
}
|
|
2127
2143
|
|
|
2128
2144
|
private async modifySeenCache(
|
|
2129
|
-
message: Uint8Array,
|
|
2130
|
-
getIdFn: (
|
|
2145
|
+
message: Uint8Array | Uint8ArrayList,
|
|
2146
|
+
getIdFn: (
|
|
2147
|
+
bytes: Uint8Array | Uint8ArrayList,
|
|
2148
|
+
) => Promise<string> = getMsgId,
|
|
2131
2149
|
) {
|
|
2132
2150
|
const msgId = await getIdFn(message);
|
|
2133
2151
|
const seen = this.seenCache.get(msgId);
|
|
@@ -2180,6 +2198,13 @@ export abstract class DirectStream<
|
|
|
2180
2198
|
}
|
|
2181
2199
|
|
|
2182
2200
|
public shouldIgnore(message: DataMessage, seenBefore: number) {
|
|
2201
|
+
if (isAcknowledgedDeliveryMode(message.header.mode)) {
|
|
2202
|
+
if (hasDeliveryHop(message.header.mode, this.publicKeyHash)) {
|
|
2203
|
+
return true;
|
|
2204
|
+
}
|
|
2205
|
+
return seenBefore >= message.header.mode.redundancy;
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2183
2208
|
const signedBySelf =
|
|
2184
2209
|
message.header.signatures?.publicKeys.some((x) =>
|
|
2185
2210
|
x.equals(this.publicKey),
|
|
@@ -2189,15 +2214,6 @@ export abstract class DirectStream<
|
|
|
2189
2214
|
return true;
|
|
2190
2215
|
}
|
|
2191
2216
|
|
|
2192
|
-
// For acknowledged modes, allow limited duplicate forwarding so that we can
|
|
2193
|
-
// discover and maintain multiple candidate routes (distance=seenCounter).
|
|
2194
|
-
if (
|
|
2195
|
-
message.header.mode instanceof AcknowledgeDelivery ||
|
|
2196
|
-
message.header.mode instanceof AcknowledgeAnyWhere
|
|
2197
|
-
) {
|
|
2198
|
-
return seenBefore >= message.header.mode.redundancy;
|
|
2199
|
-
}
|
|
2200
|
-
|
|
2201
2217
|
return seenBefore > 0;
|
|
2202
2218
|
}
|
|
2203
2219
|
|
|
@@ -2237,7 +2253,7 @@ export abstract class DirectStream<
|
|
|
2237
2253
|
|
|
2238
2254
|
await this.maybeAcknowledgeMessage(peerStream, message, seenBefore);
|
|
2239
2255
|
|
|
2240
|
-
if (seenBefore === 0 && message.
|
|
2256
|
+
if (seenBefore === 0 && message.hasData) {
|
|
2241
2257
|
this.dispatchEvent(
|
|
2242
2258
|
new CustomEvent("data", {
|
|
2243
2259
|
detail: message,
|
|
@@ -2310,11 +2326,9 @@ export abstract class DirectStream<
|
|
|
2310
2326
|
) {
|
|
2311
2327
|
return;
|
|
2312
2328
|
}
|
|
2313
|
-
const signers = message.header.
|
|
2314
|
-
x.hashcode(),
|
|
2315
|
-
);
|
|
2329
|
+
const signers = [...getDeliveryHopTrace(message.header.mode)];
|
|
2316
2330
|
|
|
2317
|
-
|
|
2331
|
+
void this.publishMessage(
|
|
2318
2332
|
this.publicKey,
|
|
2319
2333
|
await new ACK({
|
|
2320
2334
|
messageIdToAcknowledge: message.id,
|
|
@@ -2323,6 +2337,8 @@ export abstract class DirectStream<
|
|
|
2323
2337
|
header: new MessageHeader({
|
|
2324
2338
|
mode: new TracedDelivery(signers),
|
|
2325
2339
|
session: this.session,
|
|
2340
|
+
priority: getResponsePriorityFromMessage(message),
|
|
2341
|
+
expires: getMessageExpiresAt(message),
|
|
2326
2342
|
|
|
2327
2343
|
// include our origin for route-learning/dialer hints (best-effort privacy/anti-spam control):
|
|
2328
2344
|
// only include once (seenBefore=0) and only if we have not recently pruned
|
|
@@ -2331,15 +2347,15 @@ export abstract class DirectStream<
|
|
|
2331
2347
|
(message.header.mode instanceof AcknowledgeAnyWhere ||
|
|
2332
2348
|
message.header.mode instanceof AcknowledgeDelivery) &&
|
|
2333
2349
|
seenBefore === 0 &&
|
|
2334
|
-
!
|
|
2335
|
-
this.prunedConnectionsCache?.has(x
|
|
2350
|
+
!signers.find((x) =>
|
|
2351
|
+
this.prunedConnectionsCache?.has(x),
|
|
2336
2352
|
)
|
|
2337
2353
|
? new MultiAddrinfo(
|
|
2338
2354
|
this.components.addressManager
|
|
2339
2355
|
.getAddresses()
|
|
2340
2356
|
.map((x) => x.toString()),
|
|
2341
2357
|
)
|
|
2342
|
-
|
|
2358
|
+
: undefined,
|
|
2343
2359
|
}),
|
|
2344
2360
|
}).sign(this.sign),
|
|
2345
2361
|
[peerStream],
|
|
@@ -2353,11 +2369,7 @@ export abstract class DirectStream<
|
|
|
2353
2369
|
messageBytes: Uint8ArrayList | Uint8Array,
|
|
2354
2370
|
message: DataMessage,
|
|
2355
2371
|
) {
|
|
2356
|
-
const seenBefore = await this.modifySeenCache(
|
|
2357
|
-
messageBytes instanceof Uint8ArrayList
|
|
2358
|
-
? messageBytes.subarray()
|
|
2359
|
-
: messageBytes,
|
|
2360
|
-
);
|
|
2372
|
+
const seenBefore = await this.modifySeenCache(messageBytes);
|
|
2361
2373
|
|
|
2362
2374
|
return this.onDataMessage(from, peerStream, message, seenBefore);
|
|
2363
2375
|
}
|
|
@@ -2372,7 +2384,8 @@ export abstract class DirectStream<
|
|
|
2372
2384
|
messageBytes instanceof Uint8Array
|
|
2373
2385
|
? messageBytes
|
|
2374
2386
|
: messageBytes.subarray(),
|
|
2375
|
-
(bytes) =>
|
|
2387
|
+
(bytes) =>
|
|
2388
|
+
sha256Base64(bytes instanceof Uint8Array ? bytes : bytes.subarray()),
|
|
2376
2389
|
);
|
|
2377
2390
|
|
|
2378
2391
|
if (seenBefore > 0) {
|
|
@@ -2493,6 +2506,8 @@ export abstract class DirectStream<
|
|
|
2493
2506
|
to: remotes,
|
|
2494
2507
|
redundancy: DEFAULT_SILENT_MESSAGE_REDUDANCY,
|
|
2495
2508
|
}),
|
|
2509
|
+
priority: ACK_CONTROL_PRIORITY,
|
|
2510
|
+
responsePriority: ACK_CONTROL_PRIORITY,
|
|
2496
2511
|
});
|
|
2497
2512
|
return true;
|
|
2498
2513
|
} catch (e: any) {
|
|
@@ -2565,8 +2580,10 @@ export abstract class DirectStream<
|
|
|
2565
2580
|
}
|
|
2566
2581
|
}
|
|
2567
2582
|
|
|
2583
|
+
setDeliveryOriginHop(mode, this.publicKeyHash);
|
|
2584
|
+
|
|
2568
2585
|
const message = new DataMessage({
|
|
2569
|
-
data
|
|
2586
|
+
data,
|
|
2570
2587
|
header: new MessageHeader({
|
|
2571
2588
|
id: options.id,
|
|
2572
2589
|
mode,
|
|
@@ -2579,7 +2596,7 @@ export abstract class DirectStream<
|
|
|
2579
2596
|
|
|
2580
2597
|
// TODO allow messages to also be sent unsigned (signaturePolicy property)
|
|
2581
2598
|
|
|
2582
|
-
await
|
|
2599
|
+
await this.signDataMessage(message);
|
|
2583
2600
|
if (options.extraSigners) {
|
|
2584
2601
|
for (const signer of options.extraSigners) {
|
|
2585
2602
|
await message.sign(signer);
|
|
@@ -2631,6 +2648,17 @@ export abstract class DirectStream<
|
|
|
2631
2648
|
return message.id;
|
|
2632
2649
|
}
|
|
2633
2650
|
|
|
2651
|
+
private async signDataMessage(message: DataMessage) {
|
|
2652
|
+
const signature = await this.signPreparedSha256(
|
|
2653
|
+
await message.getPreparedSignableBytes(PreHash.SHA_256),
|
|
2654
|
+
);
|
|
2655
|
+
const signatures = message.header.signatures;
|
|
2656
|
+
message.header.signatures = new Signatures(
|
|
2657
|
+
signatures ? [...signatures.signatures, signature] : [signature],
|
|
2658
|
+
);
|
|
2659
|
+
return message;
|
|
2660
|
+
}
|
|
2661
|
+
|
|
2634
2662
|
public async relayMessage(
|
|
2635
2663
|
from: PublicSignKey,
|
|
2636
2664
|
message: Message,
|
|
@@ -2638,11 +2666,8 @@ export abstract class DirectStream<
|
|
|
2638
2666
|
) {
|
|
2639
2667
|
if (this.canRelayMessage) {
|
|
2640
2668
|
if (message instanceof DataMessage) {
|
|
2641
|
-
if (
|
|
2642
|
-
message.header.mode
|
|
2643
|
-
message.header.mode instanceof AcknowledgeAnyWhere
|
|
2644
|
-
) {
|
|
2645
|
-
await message.sign(this.sign);
|
|
2669
|
+
if (isAcknowledgedDeliveryMode(message.header.mode)) {
|
|
2670
|
+
appendDeliveryHop(message.header.mode, this.publicKeyHash);
|
|
2646
2671
|
}
|
|
2647
2672
|
}
|
|
2648
2673
|
if (deliveryModeHasReceiver(message.header.mode)) {
|
|
@@ -2814,9 +2839,7 @@ export abstract class DirectStream<
|
|
|
2814
2839
|
fastestNodesReached,
|
|
2815
2840
|
);
|
|
2816
2841
|
const msgMeta = `msgType=${message.constructor.name} dataBytes=${
|
|
2817
|
-
message instanceof DataMessage
|
|
2818
|
-
? (message.data?.byteLength ?? 0)
|
|
2819
|
-
: 0
|
|
2842
|
+
message instanceof DataMessage ? message.dataByteLength : 0
|
|
2820
2843
|
} relayed=${relayed ? 1 : 0}`;
|
|
2821
2844
|
deliveryDeferredPromise.reject(
|
|
2822
2845
|
new DeliveryError(
|
|
@@ -2989,8 +3012,7 @@ export abstract class DirectStream<
|
|
|
2989
3012
|
const bytes = message.bytes();
|
|
2990
3013
|
|
|
2991
3014
|
if (!isRelayed) {
|
|
2992
|
-
|
|
2993
|
-
await this.modifySeenCache(bytesArray);
|
|
3015
|
+
await this.modifySeenCache(bytes);
|
|
2994
3016
|
}
|
|
2995
3017
|
|
|
2996
3018
|
/**
|
|
@@ -3089,21 +3111,17 @@ export abstract class DirectStream<
|
|
|
3089
3111
|
if (recipient === from.hashcode()) continue; // never send back to previous hop
|
|
3090
3112
|
const stream = this.peers.get(recipient);
|
|
3091
3113
|
if (!stream) continue;
|
|
3092
|
-
if (
|
|
3093
|
-
message.header.signatures?.publicKeys.find(
|
|
3094
|
-
(x) => x.hashcode() === recipient,
|
|
3095
|
-
)
|
|
3096
|
-
) {
|
|
3114
|
+
if (hasDeliveryHop(message.header.mode, recipient)) {
|
|
3097
3115
|
continue; // recipient already signed/seen this message
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3116
|
+
}
|
|
3117
|
+
message.header.mode.to = [recipient];
|
|
3118
|
+
promises.push(
|
|
3119
|
+
this.waitForPeerWrite(
|
|
3120
|
+
stream,
|
|
3121
|
+
message.bytes(),
|
|
3122
|
+
message.header.priority,
|
|
3123
|
+
),
|
|
3124
|
+
);
|
|
3107
3125
|
}
|
|
3108
3126
|
message.header.mode.to = originalTo;
|
|
3109
3127
|
if (promises.length > 0) {
|
|
@@ -3134,18 +3152,20 @@ export abstract class DirectStream<
|
|
|
3134
3152
|
if (id.publicKey.equals(from)) {
|
|
3135
3153
|
continue;
|
|
3136
3154
|
}
|
|
3137
|
-
// Dont send message back to any
|
|
3155
|
+
// Dont send message back to any peer already present in the path.
|
|
3138
3156
|
if (
|
|
3139
3157
|
message.header.signatures?.publicKeys.find((x) =>
|
|
3140
3158
|
x.equals(id.publicKey),
|
|
3141
|
-
)
|
|
3159
|
+
) ||
|
|
3160
|
+
hasDeliveryHop(message.header.mode, id.publicKey.hashcode())
|
|
3142
3161
|
) {
|
|
3143
3162
|
continue;
|
|
3144
|
-
}
|
|
3145
|
-
|
|
3146
|
-
sentOnce = true;
|
|
3147
|
-
promises.push(this.waitForPeerWrite(id, bytes, message.header.priority));
|
|
3148
3163
|
}
|
|
3164
|
+
sentOnce = true;
|
|
3165
|
+
promises.push(
|
|
3166
|
+
this.waitForPeerWrite(id, bytes, message.header.priority),
|
|
3167
|
+
);
|
|
3168
|
+
}
|
|
3149
3169
|
await Promise.all(promises);
|
|
3150
3170
|
|
|
3151
3171
|
if (!sentOnce) {
|