@peerbit/shared-log 13.2.11 → 13.2.13

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 (36) hide show
  1. package/dist/benchmark/receive-prune.js +31 -29
  2. package/dist/benchmark/receive-prune.js.map +1 -1
  3. package/dist/src/checked-prune.d.ts +43 -10
  4. package/dist/src/checked-prune.d.ts.map +1 -1
  5. package/dist/src/checked-prune.js +257 -27
  6. package/dist/src/checked-prune.js.map +1 -1
  7. package/dist/src/exchange-heads.d.ts +26 -0
  8. package/dist/src/exchange-heads.d.ts.map +1 -1
  9. package/dist/src/exchange-heads.js +99 -0
  10. package/dist/src/exchange-heads.js.map +1 -1
  11. package/dist/src/index.d.ts +71 -14
  12. package/dist/src/index.d.ts.map +1 -1
  13. package/dist/src/index.js +3492 -1493
  14. package/dist/src/index.js.map +1 -1
  15. package/dist/src/ranges.d.ts +12 -1
  16. package/dist/src/ranges.d.ts.map +1 -1
  17. package/dist/src/ranges.js +472 -110
  18. package/dist/src/ranges.js.map +1 -1
  19. package/dist/src/sync/index.d.ts +2 -0
  20. package/dist/src/sync/index.d.ts.map +1 -1
  21. package/dist/src/sync/rateless-iblt.d.ts +96 -20
  22. package/dist/src/sync/rateless-iblt.d.ts.map +1 -1
  23. package/dist/src/sync/rateless-iblt.js +1616 -428
  24. package/dist/src/sync/rateless-iblt.js.map +1 -1
  25. package/dist/src/sync/simple.d.ts +176 -1
  26. package/dist/src/sync/simple.d.ts.map +1 -1
  27. package/dist/src/sync/simple.js +2919 -525
  28. package/dist/src/sync/simple.js.map +1 -1
  29. package/package.json +13 -13
  30. package/src/checked-prune.ts +338 -29
  31. package/src/exchange-heads.ts +52 -0
  32. package/src/index.ts +6370 -2792
  33. package/src/ranges.ts +648 -127
  34. package/src/sync/index.ts +2 -1
  35. package/src/sync/rateless-iblt.ts +2036 -498
  36. package/src/sync/simple.ts +3779 -634
@@ -10,10 +10,18 @@ export type CheckedPruneEntry<T, R extends "u32" | "u64"> =
10
10
  | EntryReplicated<R>;
11
11
 
12
12
  export type CheckedPrunePendingDelete = {
13
+ requestId: Uint8Array;
14
+ retryOnInvalidation?: boolean;
13
15
  promise: DeferredPromise<void>;
14
16
  clear: () => void;
15
- resolve: (publicKeyHash: string) => Promise<void> | void;
16
- reject(reason: any): Promise<void> | void;
17
+ resolve: (
18
+ publicKeyHash: string,
19
+ requestId: Uint8Array,
20
+ ) => Promise<void> | void;
21
+ reject(
22
+ reason: any,
23
+ options?: { preserveRetry?: boolean },
24
+ ): Promise<void> | void;
17
25
  };
18
26
 
19
27
  export type CheckedPruneRetryState<T, R extends "u32" | "u64"> = {
@@ -23,6 +31,18 @@ export type CheckedPruneRetryState<T, R extends "u32" | "u64"> = {
23
31
  leaders: CheckedPruneLeaderMap | Set<string>;
24
32
  };
25
33
 
34
+ export type CheckedPruneInvalidatedGeneration<T, R extends "u32" | "u64"> = {
35
+ hash: string;
36
+ pending: CheckedPrunePendingDelete;
37
+ entry: CheckedPruneEntry<T, R>;
38
+ leaders: CheckedPruneLeaderMap | Set<string>;
39
+ };
40
+
41
+ export type CheckedPruneRestartCandidate<T, R extends "u32" | "u64"> = Omit<
42
+ CheckedPruneInvalidatedGeneration<T, R>,
43
+ "pending"
44
+ >;
45
+
26
46
  type CheckedPruneSessionPhase =
27
47
  | "candidate"
28
48
  | "requested"
@@ -40,6 +60,7 @@ type CheckedPruneSession<T, R extends "u32" | "u64"> = {
40
60
  retry?: CheckedPruneRetryState<T, R>;
41
61
  contacted: Set<string>;
42
62
  confirmed: Set<string>;
63
+ revoked: Set<string>;
43
64
  };
44
65
 
45
66
  export class CheckedPruneCoordinator<T, R extends "u32" | "u64"> {
@@ -48,6 +69,10 @@ export class CheckedPruneCoordinator<T, R extends "u32" | "u64"> {
48
69
  readonly responseReplicatorSet = new Map<string, Set<string>>();
49
70
  readonly retries = new Map<string, CheckedPruneRetryState<T, R>>();
50
71
  private readonly sessions = new Map<string, CheckedPruneSession<T, R>>();
72
+ private readonly grantSends = new Map<string, Set<Promise<void>>>();
73
+ private readonly peerRemovalFences = new Map<string, number>();
74
+ private readonly restartReservations = new Map<string, object>();
75
+ private readonly candidateTokens = new Map<string, object>();
51
76
 
52
77
  private getOrCreateSession(hash: string): CheckedPruneSession<T, R> {
53
78
  let session = this.sessions.get(hash);
@@ -56,6 +81,7 @@ export class CheckedPruneCoordinator<T, R extends "u32" | "u64"> {
56
81
  phase: "candidate",
57
82
  contacted: new Set(),
58
83
  confirmed: new Set(),
84
+ revoked: new Set(),
59
85
  };
60
86
  this.sessions.set(hash, session);
61
87
  }
@@ -82,7 +108,8 @@ export class CheckedPruneCoordinator<T, R extends "u32" | "u64"> {
82
108
  this.pendingDeletes.has(hash) ||
83
109
  this.requestIPruneSent.has(hash) ||
84
110
  this.responseReplicatorSet.has(hash) ||
85
- this.retries.has(hash)
111
+ this.retries.has(hash) ||
112
+ this.candidateTokens.has(hash)
86
113
  ) {
87
114
  return;
88
115
  }
@@ -94,10 +121,27 @@ export class CheckedPruneCoordinator<T, R extends "u32" | "u64"> {
94
121
  entry: CheckedPruneEntry<T, R>,
95
122
  leaders: CheckedPruneLeaderMap | Set<string>,
96
123
  ) {
124
+ this.restartReservations.delete(hash);
97
125
  const session = this.remember(hash, entry, leaders);
98
126
  if (!this.hasActiveWork(hash)) {
99
127
  session.phase = "candidate";
100
128
  }
129
+ const token = {};
130
+ this.candidateTokens.set(hash, token);
131
+ return token;
132
+ }
133
+
134
+ isCandidateTokenCurrent(hash: string, token: object) {
135
+ return this.candidateTokens.get(hash) === token;
136
+ }
137
+
138
+ hasCandidate(hash: string) {
139
+ return this.candidateTokens.has(hash);
140
+ }
141
+
142
+ invalidateCandidateToken(hash: string) {
143
+ this.candidateTokens.delete(hash);
144
+ this.deleteSessionIfIdle(hash);
101
145
  }
102
146
 
103
147
  hasActiveWork(hash: string) {
@@ -105,7 +149,8 @@ export class CheckedPruneCoordinator<T, R extends "u32" | "u64"> {
105
149
  this.pendingDeletes.has(hash) ||
106
150
  this.requestIPruneSent.has(hash) ||
107
151
  this.responseReplicatorSet.has(hash) ||
108
- this.retries.has(hash)
152
+ this.retries.has(hash) ||
153
+ this.candidateTokens.has(hash)
109
154
  );
110
155
  }
111
156
 
@@ -117,15 +162,39 @@ export class CheckedPruneCoordinator<T, R extends "u32" | "u64"> {
117
162
  return this.pendingDeletes.has(hash);
118
163
  }
119
164
 
165
+ getRestartCandidate(
166
+ hash: string,
167
+ ): CheckedPruneRestartCandidate<T, R> | undefined {
168
+ const session = this.sessions.get(hash);
169
+ if (!session?.entry || !session.leaders) {
170
+ return undefined;
171
+ }
172
+ return {
173
+ hash,
174
+ entry: session.entry,
175
+ leaders:
176
+ session.leaders instanceof Map
177
+ ? new Map(session.leaders)
178
+ : new Set(session.leaders),
179
+ };
180
+ }
181
+
120
182
  setPendingDelete(
121
183
  hash: string,
122
184
  pending: CheckedPrunePendingDelete,
123
185
  entry: CheckedPruneEntry<T, R>,
124
186
  leaders: CheckedPruneLeaderMap | Set<string>,
125
187
  ) {
188
+ this.restartReservations.delete(hash);
189
+ this.candidateTokens.delete(hash);
190
+ this.requestIPruneSent.delete(hash);
191
+ this.responseReplicatorSet.delete(hash);
126
192
  this.pendingDeletes.set(hash, pending);
127
193
  const session = this.remember(hash, entry, leaders);
128
194
  session.pending = pending;
195
+ session.contacted.clear();
196
+ session.confirmed.clear();
197
+ session.revoked.clear();
129
198
  session.phase = "requested";
130
199
  }
131
200
 
@@ -133,9 +202,14 @@ export class CheckedPruneCoordinator<T, R extends "u32" | "u64"> {
133
202
  const current = this.pendingDeletes.get(hash);
134
203
  if (!pending || current === pending) {
135
204
  this.pendingDeletes.delete(hash);
205
+ this.requestIPruneSent.delete(hash);
206
+ this.responseReplicatorSet.delete(hash);
136
207
  const session = this.sessions.get(hash);
137
208
  if (session && session.pending === current) {
138
209
  session.pending = undefined;
210
+ session.contacted.clear();
211
+ session.confirmed.clear();
212
+ session.revoked.clear();
139
213
  }
140
214
  this.deleteSessionIfIdle(hash);
141
215
  }
@@ -150,6 +224,8 @@ export class CheckedPruneCoordinator<T, R extends "u32" | "u64"> {
150
224
  }
151
225
 
152
226
  setRetry(hash: string, state: CheckedPruneRetryState<T, R>) {
227
+ this.restartReservations.delete(hash);
228
+ this.candidateTokens.delete(hash);
153
229
  this.retries.set(hash, state);
154
230
  const session = this.remember(hash, state.entry, state.leaders);
155
231
  session.retry = state;
@@ -157,6 +233,8 @@ export class CheckedPruneCoordinator<T, R extends "u32" | "u64"> {
157
233
  }
158
234
 
159
235
  clearRetry(hash: string) {
236
+ this.restartReservations.delete(hash);
237
+ this.candidateTokens.delete(hash);
160
238
  const state = this.retries.get(hash);
161
239
  if (state?.timer) {
162
240
  clearTimeout(state.timer);
@@ -178,34 +256,78 @@ export class CheckedPruneCoordinator<T, R extends "u32" | "u64"> {
178
256
  return state;
179
257
  }
180
258
 
181
- addRequestSent(hash: string, peer: string) {
259
+ isCurrentRequest(hash: string, pending: CheckedPrunePendingDelete) {
260
+ return this.pendingDeletes.get(hash) === pending;
261
+ }
262
+
263
+ isCurrentRequestId(
264
+ hash: string,
265
+ pending: CheckedPrunePendingDelete,
266
+ requestId: Uint8Array,
267
+ ) {
268
+ if (!this.isCurrentRequest(hash, pending)) {
269
+ return false;
270
+ }
271
+ if (pending.requestId.byteLength !== requestId.byteLength) {
272
+ return false;
273
+ }
274
+ return pending.requestId.every(
275
+ (value, index) => value === requestId[index],
276
+ );
277
+ }
278
+
279
+ addRequestSent(
280
+ hash: string,
281
+ peer: string,
282
+ pending: CheckedPrunePendingDelete,
283
+ ) {
284
+ if (!this.isCurrentRequest(hash, pending)) {
285
+ return false;
286
+ }
287
+ const session = this.getOrCreateSession(hash);
288
+ if (session.revoked.has(peer)) {
289
+ return false;
290
+ }
182
291
  let set = this.requestIPruneSent.get(hash);
183
292
  if (!set) {
184
293
  set = new Set();
185
294
  this.requestIPruneSent.set(hash, set);
186
295
  }
187
296
  set.add(peer);
188
- const session = this.getOrCreateSession(hash);
189
297
  session.contacted.add(peer);
190
298
  if (session.phase === "candidate") {
191
299
  session.phase = "requested";
192
300
  }
301
+ return true;
193
302
  }
194
303
 
195
304
  removeRequestSent(hash: string, peer?: string) {
196
305
  if (!peer) {
197
- this.requestIPruneSent.delete(hash);
198
306
  const session = this.sessions.get(hash);
307
+ if (session?.pending) {
308
+ for (const contactedPeer of session.contacted) {
309
+ session.revoked.add(contactedPeer);
310
+ }
311
+ }
312
+ this.requestIPruneSent.delete(hash);
199
313
  session?.contacted.clear();
314
+ this.clearConfirmedReplicators(hash);
200
315
  this.deleteSessionIfIdle(hash);
201
316
  return;
202
317
  }
318
+ const session = this.sessions.get(hash);
319
+ if (session?.pending) {
320
+ // A contact removed during this pending generation must never become
321
+ // authorized again by a delayed receipt carrying the old generation ID.
322
+ session.revoked.add(peer);
323
+ }
203
324
  const set = this.requestIPruneSent.get(hash);
204
325
  if (!set) {
326
+ this.removeConfirmedReplicator(hash, peer);
205
327
  return;
206
328
  }
207
329
  set.delete(peer);
208
- const session = this.sessions.get(hash);
330
+ this.removeConfirmedReplicator(hash, peer);
209
331
  session?.contacted.delete(peer);
210
332
  if (set.size === 0) {
211
333
  this.requestIPruneSent.delete(hash);
@@ -214,15 +336,23 @@ export class CheckedPruneCoordinator<T, R extends "u32" | "u64"> {
214
336
  }
215
337
 
216
338
  removeRequestsSent(hashes: Iterable<string>, peer?: string) {
217
- if (this.requestIPruneSent.size === 0) {
218
- return;
219
- }
220
339
  for (const hash of hashes) {
221
340
  this.removeRequestSent(hash, peer);
222
341
  }
223
342
  }
224
343
 
225
- addConfirmedReplicator(hash: string, peer: string) {
344
+ addConfirmedReplicator(
345
+ hash: string,
346
+ peer: string,
347
+ pending: CheckedPrunePendingDelete,
348
+ requestId: Uint8Array,
349
+ ) {
350
+ if (
351
+ !this.isCurrentRequestId(hash, pending, requestId) ||
352
+ !this.requestIPruneSent.get(hash)?.has(peer)
353
+ ) {
354
+ return undefined;
355
+ }
226
356
  let set = this.responseReplicatorSet.get(hash);
227
357
  if (!set) {
228
358
  set = new Set();
@@ -282,24 +412,178 @@ export class CheckedPruneCoordinator<T, R extends "u32" | "u64"> {
282
412
  return this.requestIPruneSent.get(hash);
283
413
  }
284
414
 
285
- markRemoving(hash: string) {
415
+ hasRevokedLeader(
416
+ hash: string,
417
+ pending: CheckedPrunePendingDelete,
418
+ leaders: CheckedPruneLeaderMap | Set<string>,
419
+ ) {
420
+ if (!this.isCurrentRequest(hash, pending)) {
421
+ return false;
422
+ }
423
+ const revoked = this.sessions.get(hash)?.revoked;
424
+ if (!revoked || revoked.size === 0) {
425
+ return false;
426
+ }
427
+ for (const leader of leaders.keys()) {
428
+ if (revoked.has(leader)) {
429
+ return true;
430
+ }
431
+ }
432
+ return false;
433
+ }
434
+
435
+ trackGrantSend(hashes: Iterable<string>, send: Promise<void>) {
436
+ const uniqueHashes = [...new Set(hashes)];
437
+ const observed = send.then(
438
+ () => undefined,
439
+ () => undefined,
440
+ );
441
+ for (const hash of uniqueHashes) {
442
+ let sends = this.grantSends.get(hash);
443
+ if (!sends) {
444
+ sends = new Set();
445
+ this.grantSends.set(hash, sends);
446
+ }
447
+ sends.add(observed);
448
+ }
449
+ void observed.finally(() => {
450
+ for (const hash of uniqueHashes) {
451
+ const sends = this.grantSends.get(hash);
452
+ sends?.delete(observed);
453
+ if (sends?.size === 0) {
454
+ this.grantSends.delete(hash);
455
+ }
456
+ }
457
+ });
458
+ return observed;
459
+ }
460
+
461
+ waitForGrantSends(hash: string): Promise<void> | undefined {
462
+ const sends = this.grantSends.get(hash);
463
+ if (!sends || sends.size === 0) {
464
+ return undefined;
465
+ }
466
+ return Promise.all(sends).then(() => undefined);
467
+ }
468
+
469
+ reserveRestart(hash: string) {
470
+ const reservation = {};
471
+ this.restartReservations.set(hash, reservation);
472
+ return reservation;
473
+ }
474
+
475
+ consumeRestartReservation(hash: string, reservation: object) {
476
+ if (this.restartReservations.get(hash) !== reservation) {
477
+ return false;
478
+ }
479
+ this.restartReservations.delete(hash);
480
+ return true;
481
+ }
482
+
483
+ cancelRestartReservation(hash: string, reservation: object) {
484
+ if (this.restartReservations.get(hash) === reservation) {
485
+ this.restartReservations.delete(hash);
486
+ }
487
+ }
488
+
489
+ hasRestartReservation(hash: string) {
490
+ return this.restartReservations.has(hash);
491
+ }
492
+
493
+ getExactConfirmedReplicators(
494
+ hash: string,
495
+ pending: CheckedPrunePendingDelete,
496
+ ) {
497
+ const exact = new Set<string>();
498
+ if (!this.isCurrentRequest(hash, pending)) {
499
+ return exact;
500
+ }
501
+ const contacted = this.requestIPruneSent.get(hash);
502
+ const confirmed = this.responseReplicatorSet.get(hash);
503
+ const revoked = this.sessions.get(hash)?.revoked;
504
+ if (!contacted || !confirmed) {
505
+ return exact;
506
+ }
507
+ for (const peer of confirmed) {
508
+ if (
509
+ contacted.has(peer) &&
510
+ !revoked?.has(peer) &&
511
+ !this.isPeerRemovalFenced(peer)
512
+ ) {
513
+ exact.add(peer);
514
+ }
515
+ }
516
+ return exact;
517
+ }
518
+
519
+ fencePeerRemoval(peer: string) {
520
+ this.peerRemovalFences.set(
521
+ peer,
522
+ (this.peerRemovalFences.get(peer) ?? 0) + 1,
523
+ );
524
+ let released = false;
525
+ return () => {
526
+ if (released) {
527
+ return;
528
+ }
529
+ released = true;
530
+ const remaining = (this.peerRemovalFences.get(peer) ?? 1) - 1;
531
+ if (remaining > 0) {
532
+ this.peerRemovalFences.set(peer, remaining);
533
+ } else {
534
+ this.peerRemovalFences.delete(peer);
535
+ }
536
+ };
537
+ }
538
+
539
+ isPeerRemovalFenced(peer: string) {
540
+ return (this.peerRemovalFences.get(peer) ?? 0) > 0;
541
+ }
542
+
543
+ markRemoving(hash: string, pending?: CheckedPrunePendingDelete) {
544
+ if (pending && !this.isCurrentRequest(hash, pending)) {
545
+ return false;
546
+ }
286
547
  const session = this.getOrCreateSession(hash);
287
548
  session.phase = "removing";
549
+ return true;
288
550
  }
289
551
 
290
- markDone(hash: string) {
552
+ markDone(hash: string, pending?: CheckedPrunePendingDelete) {
553
+ if (pending && !this.isCurrentRequest(hash, pending)) {
554
+ return false;
555
+ }
291
556
  const session = this.sessions.get(hash);
292
557
  if (session) {
293
558
  session.phase = "done";
294
559
  }
560
+ this.restartReservations.delete(hash);
561
+ this.candidateTokens.delete(hash);
295
562
  this.pendingDeletes.delete(hash);
296
563
  this.requestIPruneSent.delete(hash);
297
564
  this.responseReplicatorSet.delete(hash);
298
565
  this.clearRetry(hash);
299
566
  this.sessions.delete(hash);
567
+ return true;
300
568
  }
301
569
 
302
- markCancelled(hash: string, options?: { preserveRetry?: boolean }) {
570
+ markCancelled(
571
+ hash: string,
572
+ pendingOrOptions?: CheckedPrunePendingDelete | { preserveRetry?: boolean },
573
+ options?: { preserveRetry?: boolean },
574
+ ) {
575
+ const pending =
576
+ pendingOrOptions && "promise" in pendingOrOptions
577
+ ? pendingOrOptions
578
+ : undefined;
579
+ const resolvedOptions: { preserveRetry?: boolean } | undefined = pending
580
+ ? options
581
+ : (pendingOrOptions as { preserveRetry?: boolean } | undefined);
582
+ if (pending && !this.isCurrentRequest(hash, pending)) {
583
+ return false;
584
+ }
585
+ this.restartReservations.delete(hash);
586
+ this.candidateTokens.delete(hash);
303
587
  const retry = this.retries.get(hash);
304
588
  const session = this.sessions.get(hash);
305
589
  if (session) {
@@ -307,36 +591,57 @@ export class CheckedPruneCoordinator<T, R extends "u32" | "u64"> {
307
591
  session.pending = undefined;
308
592
  session.contacted.clear();
309
593
  session.confirmed.clear();
310
- if (!options?.preserveRetry || session.retry !== retry) {
594
+ session.revoked.clear();
595
+ if (!resolvedOptions?.preserveRetry || session.retry !== retry) {
311
596
  session.retry = undefined;
312
597
  }
313
598
  }
599
+ if (!pending || this.pendingDeletes.get(hash) === pending) {
600
+ this.pendingDeletes.delete(hash);
601
+ }
314
602
  this.requestIPruneSent.delete(hash);
315
603
  this.responseReplicatorSet.delete(hash);
316
- if (!options?.preserveRetry) {
604
+ if (!resolvedOptions?.preserveRetry) {
317
605
  this.clearRetry(hash);
318
606
  }
319
607
  this.deleteSessionIfIdle(hash);
608
+ return true;
320
609
  }
321
610
 
322
611
  cleanupPeer(peer: string) {
323
- for (const [hash, peers] of this.requestIPruneSent) {
324
- peers.delete(peer);
325
- this.sessions.get(hash)?.contacted.delete(peer);
326
- if (peers.size === 0) {
327
- this.requestIPruneSent.delete(hash);
328
- this.deleteSessionIfIdle(hash);
612
+ const invalidated: CheckedPruneInvalidatedGeneration<T, R>[] = [];
613
+ // Fence the peer from every active generation, including generations that
614
+ // have not emitted their first request yet. A removal can begin between
615
+ // generation creation and message emission.
616
+ for (const [hash, session] of this.sessions) {
617
+ const pending = session.pending;
618
+ if (pending && this.pendingDeletes.get(hash) === pending) {
619
+ session.revoked.add(peer);
620
+ const candidate = this.getRestartCandidate(hash);
621
+ if (
622
+ candidate &&
623
+ (session.contacted.has(peer) || candidate.leaders.has(peer))
624
+ ) {
625
+ invalidated.push({
626
+ ...candidate,
627
+ pending,
628
+ });
629
+ }
630
+ }
631
+ }
632
+
633
+ for (const [hash, peers] of [...this.requestIPruneSent]) {
634
+ if (peers.has(peer)) {
635
+ this.removeRequestSent(hash, peer);
329
636
  }
330
637
  }
331
638
 
332
- for (const [hash, peers] of this.responseReplicatorSet) {
333
- peers.delete(peer);
334
- this.sessions.get(hash)?.confirmed.delete(peer);
335
- if (peers.size === 0) {
336
- this.responseReplicatorSet.delete(hash);
337
- this.deleteSessionIfIdle(hash);
639
+ for (const [hash, peers] of [...this.responseReplicatorSet]) {
640
+ if (peers.has(peer)) {
641
+ this.removeConfirmedReplicator(hash, peer);
338
642
  }
339
643
  }
644
+ return invalidated;
340
645
  }
341
646
 
342
647
  close() {
@@ -354,5 +659,9 @@ export class CheckedPruneCoordinator<T, R extends "u32" | "u64"> {
354
659
  this.responseReplicatorSet.clear();
355
660
  this.retries.clear();
356
661
  this.sessions.clear();
662
+ this.grantSends.clear();
663
+ this.peerRemovalFences.clear();
664
+ this.restartReservations.clear();
665
+ this.candidateTokens.clear();
357
666
  }
358
667
  }
@@ -1106,6 +1106,58 @@ export class ResponseIPrune extends TransportMessage {
1106
1106
  }
1107
1107
  }
1108
1108
 
1109
+ @variant(0)
1110
+ export class CheckedPruneRequest {
1111
+ @field({ type: "string" })
1112
+ hash: string;
1113
+
1114
+ @field({ type: fixedArray("u8", 32) })
1115
+ requestId: Uint8Array;
1116
+
1117
+ constructor(props: { hash: string; requestId: Uint8Array }) {
1118
+ this.hash = props.hash;
1119
+ this.requestId = props.requestId;
1120
+ }
1121
+ }
1122
+
1123
+ @variant([0, 11])
1124
+ export class RequestIPruneV2 extends TransportMessage {
1125
+ @field({ type: vec(CheckedPruneRequest) })
1126
+ requests: CheckedPruneRequest[];
1127
+
1128
+ constructor(props: {
1129
+ requests: Array<
1130
+ CheckedPruneRequest | { hash: string; requestId: Uint8Array }
1131
+ >;
1132
+ }) {
1133
+ super();
1134
+ this.requests = props.requests.map((request) =>
1135
+ request instanceof CheckedPruneRequest
1136
+ ? request
1137
+ : new CheckedPruneRequest(request),
1138
+ );
1139
+ }
1140
+ }
1141
+
1142
+ @variant([0, 12])
1143
+ export class ResponseIPruneV2 extends TransportMessage {
1144
+ @field({ type: vec(CheckedPruneRequest) })
1145
+ requests: CheckedPruneRequest[];
1146
+
1147
+ constructor(props: {
1148
+ requests: Array<
1149
+ CheckedPruneRequest | { hash: string; requestId: Uint8Array }
1150
+ >;
1151
+ }) {
1152
+ super();
1153
+ this.requests = props.requests.map((request) =>
1154
+ request instanceof CheckedPruneRequest
1155
+ ? request
1156
+ : new CheckedPruneRequest(request),
1157
+ );
1158
+ }
1159
+ }
1160
+
1109
1161
  const MAX_EXCHANGE_MESSAGE_SIZE = 1e5; // 100kb. Too large size might not be faster (even if we can do 5mb)
1110
1162
  export const MAX_RAW_EXCHANGE_MESSAGE_SIZE = 512 * 1024;
1111
1163
  export const EXCHANGE_HEADS_RESOLVE_BATCH_SIZE = 256;