@optimystic/db-core 0.22.0 → 0.24.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 (141) hide show
  1. package/README.md +336 -336
  2. package/dist/src/cluster/structs.d.ts +39 -1
  3. package/dist/src/cluster/structs.d.ts.map +1 -1
  4. package/dist/src/cluster/structs.js +24 -0
  5. package/dist/src/cluster/structs.js.map +1 -1
  6. package/dist/src/collection/collection.d.ts +17 -0
  7. package/dist/src/collection/collection.d.ts.map +1 -1
  8. package/dist/src/collection/collection.js +24 -2
  9. package/dist/src/collection/collection.js.map +1 -1
  10. package/dist/src/collections/tree/tree.d.ts +5 -0
  11. package/dist/src/collections/tree/tree.d.ts.map +1 -1
  12. package/dist/src/collections/tree/tree.js +7 -0
  13. package/dist/src/collections/tree/tree.js.map +1 -1
  14. package/dist/src/network/i-peer-network.d.ts +16 -0
  15. package/dist/src/network/i-peer-network.d.ts.map +1 -1
  16. package/dist/src/network/struct.d.ts +39 -2
  17. package/dist/src/network/struct.d.ts.map +1 -1
  18. package/dist/src/network/struct.js +18 -0
  19. package/dist/src/network/struct.js.map +1 -1
  20. package/dist/src/testing/test-transactor.d.ts +95 -8
  21. package/dist/src/testing/test-transactor.d.ts.map +1 -1
  22. package/dist/src/testing/test-transactor.js +121 -8
  23. package/dist/src/testing/test-transactor.js.map +1 -1
  24. package/dist/src/transaction/transaction.d.ts +1 -1
  25. package/dist/src/transaction/transaction.js +1 -1
  26. package/dist/src/transactor/network-transactor.d.ts.map +1 -1
  27. package/dist/src/transactor/network-transactor.js +48 -13
  28. package/dist/src/transactor/network-transactor.js.map +1 -1
  29. package/dist/src/transactor/transactor-source.d.ts.map +1 -1
  30. package/dist/src/transactor/transactor-source.js +25 -2
  31. package/dist/src/transactor/transactor-source.js.map +1 -1
  32. package/package.json +1 -1
  33. package/src/cluster/membership.ts +85 -85
  34. package/src/cluster/structs.ts +43 -4
  35. package/src/cohort-topic/addressing.ts +120 -120
  36. package/src/cohort-topic/antidos/bootstrap-evidence-envelope.ts +253 -253
  37. package/src/cohort-topic/antidos/bootstrap-evidence.ts +106 -106
  38. package/src/cohort-topic/antidos/index.ts +5 -5
  39. package/src/cohort-topic/antidos/rate-limiter.ts +210 -210
  40. package/src/cohort-topic/antidos/replay-guard.ts +146 -146
  41. package/src/cohort-topic/antidos/topic-budget.ts +160 -160
  42. package/src/cohort-topic/antiflood/index.ts +2 -2
  43. package/src/cohort-topic/antiflood/invariants.ts +108 -108
  44. package/src/cohort-topic/antiflood/jitter.ts +117 -117
  45. package/src/cohort-topic/coldstart.ts +237 -237
  46. package/src/cohort-topic/dmax.ts +88 -88
  47. package/src/cohort-topic/gossip/bus.ts +254 -254
  48. package/src/cohort-topic/gossip/index.ts +3 -3
  49. package/src/cohort-topic/gossip/records.ts +45 -45
  50. package/src/cohort-topic/gossip/view.ts +91 -91
  51. package/src/cohort-topic/index.ts +20 -20
  52. package/src/cohort-topic/load/barometer.ts +134 -134
  53. package/src/cohort-topic/load/index.ts +1 -1
  54. package/src/cohort-topic/member-engine.ts +430 -430
  55. package/src/cohort-topic/membership/index.ts +3 -3
  56. package/src/cohort-topic/membership/publisher.ts +163 -163
  57. package/src/cohort-topic/membership/source.ts +41 -41
  58. package/src/cohort-topic/membership/verifier.ts +461 -461
  59. package/src/cohort-topic/ports.ts +157 -157
  60. package/src/cohort-topic/promotion.ts +405 -405
  61. package/src/cohort-topic/registration/bytes.ts +37 -37
  62. package/src/cohort-topic/registration/handoff.ts +154 -154
  63. package/src/cohort-topic/registration/index.ts +6 -6
  64. package/src/cohort-topic/registration/renewal.ts +495 -495
  65. package/src/cohort-topic/registration/sharding.ts +61 -61
  66. package/src/cohort-topic/registration/store.ts +81 -81
  67. package/src/cohort-topic/registration/types.ts +91 -91
  68. package/src/cohort-topic/ring-hash.ts +50 -50
  69. package/src/cohort-topic/service.ts +416 -416
  70. package/src/cohort-topic/sig/index.ts +2 -2
  71. package/src/cohort-topic/sig/payloads.ts +59 -59
  72. package/src/cohort-topic/sig/threshold.ts +64 -64
  73. package/src/cohort-topic/tiers.ts +74 -74
  74. package/src/cohort-topic/traffic.ts +233 -233
  75. package/src/cohort-topic/walk.ts +326 -326
  76. package/src/cohort-topic/willingness.ts +237 -237
  77. package/src/cohort-topic/wire/codec.ts +216 -216
  78. package/src/cohort-topic/wire/index.ts +18 -18
  79. package/src/cohort-topic/wire/payloads.ts +126 -126
  80. package/src/cohort-topic/wire/primitives.ts +188 -188
  81. package/src/cohort-topic/wire/types.ts +475 -475
  82. package/src/cohort-topic/wire/validate.ts +512 -512
  83. package/src/collection/collection-type-registry.ts +37 -37
  84. package/src/collection/collection.ts +25 -2
  85. package/src/collections/diary/diary.ts +68 -68
  86. package/src/collections/tree/readme.md +4 -0
  87. package/src/collections/tree/tree.ts +320 -312
  88. package/src/matchmaking/capability-filter.ts +45 -45
  89. package/src/matchmaking/config.ts +98 -98
  90. package/src/matchmaking/index.ts +21 -21
  91. package/src/matchmaking/multi-cohort-seeker.ts +234 -234
  92. package/src/matchmaking/provider.ts +123 -123
  93. package/src/matchmaking/query-eval.ts +105 -105
  94. package/src/matchmaking/seeker-walk.ts +127 -127
  95. package/src/matchmaking/seeker.ts +86 -86
  96. package/src/matchmaking/topic-anchor.ts +90 -90
  97. package/src/matchmaking/voting-quorum.ts +394 -394
  98. package/src/matchmaking/wire.ts +603 -603
  99. package/src/network/i-peer-network.ts +17 -0
  100. package/src/network/stale-failure.ts +43 -43
  101. package/src/network/struct.ts +41 -2
  102. package/src/network/types.ts +37 -37
  103. package/src/reactivity/backfill.ts +220 -220
  104. package/src/reactivity/backpressure.ts +191 -191
  105. package/src/reactivity/checkpoint.ts +308 -308
  106. package/src/reactivity/config.ts +172 -172
  107. package/src/reactivity/dedupe.ts +132 -132
  108. package/src/reactivity/forwarder.ts +87 -87
  109. package/src/reactivity/index.ts +34 -34
  110. package/src/reactivity/notification.ts +123 -123
  111. package/src/reactivity/policy.ts +79 -79
  112. package/src/reactivity/push-state.ts +310 -310
  113. package/src/reactivity/recover.ts +153 -153
  114. package/src/reactivity/replay-buffer.ts +141 -141
  115. package/src/reactivity/resume.ts +549 -549
  116. package/src/reactivity/rotation.ts +415 -415
  117. package/src/reactivity/subscriber.ts +132 -132
  118. package/src/reactivity/subscription.ts +66 -66
  119. package/src/reactivity/topic-anchor.ts +71 -71
  120. package/src/reactivity/verify.ts +73 -73
  121. package/src/reactivity/wire-validate.ts +13 -13
  122. package/src/reactivity/wire.ts +224 -224
  123. package/src/testing/async-wait.ts +65 -65
  124. package/src/testing/index.ts +2 -2
  125. package/src/testing/test-transactor.ts +638 -502
  126. package/src/transaction/errors.ts +91 -91
  127. package/src/transaction/operations-hash.ts +196 -196
  128. package/src/transaction/read-dependency-collector.ts +78 -78
  129. package/src/transaction/transaction.ts +1 -1
  130. package/src/transactor/change-notifier.ts +80 -80
  131. package/src/transactor/index.ts +5 -5
  132. package/src/transactor/network-transactor.ts +49 -14
  133. package/src/transactor/transactor-source.ts +25 -2
  134. package/src/transform/atomic-proxy.ts +92 -92
  135. package/src/transform/helpers.ts +159 -159
  136. package/src/utility/backoff.ts +95 -95
  137. package/src/utility/batch-coordinator.ts +191 -191
  138. package/dist/src/transaction/context.d.ts +0 -60
  139. package/dist/src/transaction/context.d.ts.map +0 -1
  140. package/dist/src/transaction/context.js +0 -91
  141. package/dist/src/transaction/context.js.map +0 -1
@@ -1,120 +1,120 @@
1
- /**
2
- * Cohort-topic substrate — tier addressing (`coord_d`).
3
- *
4
- * Transcribed from `docs/cohort-topic.md` §Tier addressing:
5
- *
6
- * ```
7
- * coord_0(_, topicId) = H(0x00 ‖ topicId)
8
- * coord_d(P, topicId) = H(d ‖ prefix(H(P), d·log₂F) ‖ topicId) for d ≥ 1
9
- * ```
10
- *
11
- * `P` is ring-hashed before the prefix so the shard input is uniformly distributed across
12
- * participants (the raw peer-id string bytes share a near-constant `12D3Koo…` prefix that would
13
- * collapse all tier-`d` shards to one coordinate). The wire field `participantCoord` keeps the
14
- * unmodified peer id so the Ed25519 key remains recoverable; the ring-hash is applied only inside
15
- * the addressing math.
16
- *
17
- * `H` is the injected {@link IRingHash} (db-core's own SHA-256 truncated to the ring width — **not**
18
- * a FRET import). `prefix(P, n)` is the `n` most-significant bits of peer id `P`, left-padded if
19
- * shorter. `F` is the fan-out (default 16, `log₂F = 4`); tier `d` has exactly `F^d` coordinates.
20
- *
21
- * The db-p2p binding is responsible for ensuring the coord byte layout (ring width) matches FRET's
22
- * `RING_BITS` so the routing keys produced here line up with FRET's ring on the wire.
23
- */
24
-
25
- import type { IRingHash, RingCoord } from "./ports.js";
26
-
27
- /** Tier-addressing surface — derives the ring coordinate for tier `d` of a topic. */
28
- export interface TierAddressing {
29
- /** Fan-out per tier (default 16). */
30
- readonly F: number;
31
- /** Tier-0 root coordinate: `H(0x00 ‖ topicId)`. Peer-independent. */
32
- coord0(topicId: Uint8Array): RingCoord;
33
- /** Tier-`d` coordinate for `d ≥ 1`: `H(d ‖ prefix(H(P), d·log₂F) ‖ topicId)` where `H(P)` is the ring-hash of `peerId`. */
34
- coordD(d: number, peerId: Uint8Array, topicId: Uint8Array): RingCoord;
35
- /** Dispatches `d === 0` to {@link coord0}, otherwise to {@link coordD}. */
36
- coord(d: number, peerId: Uint8Array, topicId: Uint8Array): RingCoord;
37
- }
38
-
39
- /** Default fan-out per tier (`log₂16 = 4`). */
40
- export const DEFAULT_FANOUT = 16;
41
-
42
- /**
43
- * `prefix(P, n)` — the `n` most-significant bits of `P`, packed MSB-first into `⌈n/8⌉` bytes with
44
- * the trailing partial byte's unused low bits zeroed. If `P` carries fewer than `n` bits it is
45
- * **left-padded**: the high `(n − bits(P))` positions are zero and `P`'s bits occupy the low end, so
46
- * the result is always exactly `n` bits wide. `n === 0` yields an empty array (the tier-0 case).
47
- *
48
- * Exported for tests; not part of the public substrate surface.
49
- */
50
- export function prefixBits(peerId: Uint8Array, n: number): Uint8Array {
51
- if (!Number.isInteger(n) || n < 0) {
52
- throw new RangeError(`prefix bit count must be a non-negative integer, got ${n}`);
53
- }
54
- const outBytes = Math.ceil(n / 8);
55
- const out = new Uint8Array(outBytes);
56
- const available = peerId.length * 8;
57
- const pad = Math.max(0, n - available);
58
- for (let j = 0; j < n; j++) {
59
- // Result bit j (MSB-first). High `pad` positions are zero (left-pad); the rest map to P.
60
- if (j < pad) continue;
61
- const srcBit = j - pad;
62
- const srcByte = peerId[srcBit >>> 3]!;
63
- const bit = (srcByte >>> (7 - (srcBit & 7))) & 1;
64
- if (bit) out[j >>> 3]! |= 1 << (7 - (j & 7));
65
- }
66
- return out;
67
- }
68
-
69
- /** Implements {@link TierAddressing} over an injected {@link IRingHash}. */
70
- export class HashTierAddressing implements TierAddressing {
71
- public readonly F: number;
72
- private readonly log2F: number;
73
-
74
- constructor(private readonly hash: IRingHash, F: number = DEFAULT_FANOUT) {
75
- if (!Number.isInteger(F) || F < 2) {
76
- throw new RangeError(`fan-out F must be an integer ≥ 2, got ${F}`);
77
- }
78
- const log2F = Math.log2(F);
79
- if (!Number.isInteger(log2F)) {
80
- throw new RangeError(`fan-out F must be a power of two, got ${F}`);
81
- }
82
- this.F = F;
83
- this.log2F = log2F;
84
- }
85
-
86
- coord0(topicId: Uint8Array): RingCoord {
87
- // H(0x00 ‖ topicId)
88
- const input = new Uint8Array(1 + topicId.length);
89
- input[0] = 0x00;
90
- input.set(topicId, 1);
91
- return this.hash.H(input);
92
- }
93
-
94
- coordD(d: number, peerId: Uint8Array, topicId: Uint8Array): RingCoord {
95
- if (!Number.isInteger(d) || d < 1) {
96
- throw new RangeError(`coordD requires an integer tier d ≥ 1, got ${d}`);
97
- }
98
- if (d > 255) {
99
- throw new RangeError(`tier d must fit in one byte (≤ 255), got ${d}`);
100
- }
101
- // H(d ‖ prefix(H(P), d·log₂F) ‖ topicId) — ring-hash P first so the shard input is uniform
102
- // NOTE: re-hashes peerId on every coordD call; a walk over a tier ladder recomputes H(self) per
103
- // tier. Negligible today (walk steps are network-bound); if coord becomes hot, cache H(peerId).
104
- const prefix = prefixBits(this.hash.H(peerId), d * this.log2F);
105
- const input = new Uint8Array(1 + prefix.length + topicId.length);
106
- input[0] = d;
107
- input.set(prefix, 1);
108
- input.set(topicId, 1 + prefix.length);
109
- return this.hash.H(input);
110
- }
111
-
112
- coord(d: number, peerId: Uint8Array, topicId: Uint8Array): RingCoord {
113
- return d === 0 ? this.coord0(topicId) : this.coordD(d, peerId, topicId);
114
- }
115
- }
116
-
117
- /** Convenience factory mirroring the db-p2p adapter construction style. */
118
- export function createTierAddressing(hash: IRingHash, F: number = DEFAULT_FANOUT): TierAddressing {
119
- return new HashTierAddressing(hash, F);
120
- }
1
+ /**
2
+ * Cohort-topic substrate — tier addressing (`coord_d`).
3
+ *
4
+ * Transcribed from `docs/cohort-topic.md` §Tier addressing:
5
+ *
6
+ * ```
7
+ * coord_0(_, topicId) = H(0x00 ‖ topicId)
8
+ * coord_d(P, topicId) = H(d ‖ prefix(H(P), d·log₂F) ‖ topicId) for d ≥ 1
9
+ * ```
10
+ *
11
+ * `P` is ring-hashed before the prefix so the shard input is uniformly distributed across
12
+ * participants (the raw peer-id string bytes share a near-constant `12D3Koo…` prefix that would
13
+ * collapse all tier-`d` shards to one coordinate). The wire field `participantCoord` keeps the
14
+ * unmodified peer id so the Ed25519 key remains recoverable; the ring-hash is applied only inside
15
+ * the addressing math.
16
+ *
17
+ * `H` is the injected {@link IRingHash} (db-core's own SHA-256 truncated to the ring width — **not**
18
+ * a FRET import). `prefix(P, n)` is the `n` most-significant bits of peer id `P`, left-padded if
19
+ * shorter. `F` is the fan-out (default 16, `log₂F = 4`); tier `d` has exactly `F^d` coordinates.
20
+ *
21
+ * The db-p2p binding is responsible for ensuring the coord byte layout (ring width) matches FRET's
22
+ * `RING_BITS` so the routing keys produced here line up with FRET's ring on the wire.
23
+ */
24
+
25
+ import type { IRingHash, RingCoord } from "./ports.js";
26
+
27
+ /** Tier-addressing surface — derives the ring coordinate for tier `d` of a topic. */
28
+ export interface TierAddressing {
29
+ /** Fan-out per tier (default 16). */
30
+ readonly F: number;
31
+ /** Tier-0 root coordinate: `H(0x00 ‖ topicId)`. Peer-independent. */
32
+ coord0(topicId: Uint8Array): RingCoord;
33
+ /** Tier-`d` coordinate for `d ≥ 1`: `H(d ‖ prefix(H(P), d·log₂F) ‖ topicId)` where `H(P)` is the ring-hash of `peerId`. */
34
+ coordD(d: number, peerId: Uint8Array, topicId: Uint8Array): RingCoord;
35
+ /** Dispatches `d === 0` to {@link coord0}, otherwise to {@link coordD}. */
36
+ coord(d: number, peerId: Uint8Array, topicId: Uint8Array): RingCoord;
37
+ }
38
+
39
+ /** Default fan-out per tier (`log₂16 = 4`). */
40
+ export const DEFAULT_FANOUT = 16;
41
+
42
+ /**
43
+ * `prefix(P, n)` — the `n` most-significant bits of `P`, packed MSB-first into `⌈n/8⌉` bytes with
44
+ * the trailing partial byte's unused low bits zeroed. If `P` carries fewer than `n` bits it is
45
+ * **left-padded**: the high `(n − bits(P))` positions are zero and `P`'s bits occupy the low end, so
46
+ * the result is always exactly `n` bits wide. `n === 0` yields an empty array (the tier-0 case).
47
+ *
48
+ * Exported for tests; not part of the public substrate surface.
49
+ */
50
+ export function prefixBits(peerId: Uint8Array, n: number): Uint8Array {
51
+ if (!Number.isInteger(n) || n < 0) {
52
+ throw new RangeError(`prefix bit count must be a non-negative integer, got ${n}`);
53
+ }
54
+ const outBytes = Math.ceil(n / 8);
55
+ const out = new Uint8Array(outBytes);
56
+ const available = peerId.length * 8;
57
+ const pad = Math.max(0, n - available);
58
+ for (let j = 0; j < n; j++) {
59
+ // Result bit j (MSB-first). High `pad` positions are zero (left-pad); the rest map to P.
60
+ if (j < pad) continue;
61
+ const srcBit = j - pad;
62
+ const srcByte = peerId[srcBit >>> 3]!;
63
+ const bit = (srcByte >>> (7 - (srcBit & 7))) & 1;
64
+ if (bit) out[j >>> 3]! |= 1 << (7 - (j & 7));
65
+ }
66
+ return out;
67
+ }
68
+
69
+ /** Implements {@link TierAddressing} over an injected {@link IRingHash}. */
70
+ export class HashTierAddressing implements TierAddressing {
71
+ public readonly F: number;
72
+ private readonly log2F: number;
73
+
74
+ constructor(private readonly hash: IRingHash, F: number = DEFAULT_FANOUT) {
75
+ if (!Number.isInteger(F) || F < 2) {
76
+ throw new RangeError(`fan-out F must be an integer ≥ 2, got ${F}`);
77
+ }
78
+ const log2F = Math.log2(F);
79
+ if (!Number.isInteger(log2F)) {
80
+ throw new RangeError(`fan-out F must be a power of two, got ${F}`);
81
+ }
82
+ this.F = F;
83
+ this.log2F = log2F;
84
+ }
85
+
86
+ coord0(topicId: Uint8Array): RingCoord {
87
+ // H(0x00 ‖ topicId)
88
+ const input = new Uint8Array(1 + topicId.length);
89
+ input[0] = 0x00;
90
+ input.set(topicId, 1);
91
+ return this.hash.H(input);
92
+ }
93
+
94
+ coordD(d: number, peerId: Uint8Array, topicId: Uint8Array): RingCoord {
95
+ if (!Number.isInteger(d) || d < 1) {
96
+ throw new RangeError(`coordD requires an integer tier d ≥ 1, got ${d}`);
97
+ }
98
+ if (d > 255) {
99
+ throw new RangeError(`tier d must fit in one byte (≤ 255), got ${d}`);
100
+ }
101
+ // H(d ‖ prefix(H(P), d·log₂F) ‖ topicId) — ring-hash P first so the shard input is uniform
102
+ // NOTE: re-hashes peerId on every coordD call; a walk over a tier ladder recomputes H(self) per
103
+ // tier. Negligible today (walk steps are network-bound); if coord becomes hot, cache H(peerId).
104
+ const prefix = prefixBits(this.hash.H(peerId), d * this.log2F);
105
+ const input = new Uint8Array(1 + prefix.length + topicId.length);
106
+ input[0] = d;
107
+ input.set(prefix, 1);
108
+ input.set(topicId, 1 + prefix.length);
109
+ return this.hash.H(input);
110
+ }
111
+
112
+ coord(d: number, peerId: Uint8Array, topicId: Uint8Array): RingCoord {
113
+ return d === 0 ? this.coord0(topicId) : this.coordD(d, peerId, topicId);
114
+ }
115
+ }
116
+
117
+ /** Convenience factory mirroring the db-p2p adapter construction style. */
118
+ export function createTierAddressing(hash: IRingHash, F: number = DEFAULT_FANOUT): TierAddressing {
119
+ return new HashTierAddressing(hash, F);
120
+ }