@serfab/cadre-core 1.17.0 → 1.18.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.
- package/README.md +3 -2
- package/dist/cadre-invite-protocol.d.ts +35 -13
- package/dist/cadre-invite-protocol.js +90 -25
- package/dist/cadre-invite-protocol.js.map +1 -1
- package/dist/cadre-node.d.ts +586 -255
- package/dist/cadre-node.js +1176 -564
- package/dist/cadre-node.js.map +1 -1
- package/dist/control-cohort.d.ts +66 -9
- package/dist/control-cohort.js +67 -9
- package/dist/control-cohort.js.map +1 -1
- package/dist/control-database.d.ts +451 -193
- package/dist/control-database.js +701 -359
- package/dist/control-database.js.map +1 -1
- package/dist/control-formation-recorder.d.ts +46 -43
- package/dist/control-formation-recorder.js +77 -78
- package/dist/control-formation-recorder.js.map +1 -1
- package/dist/control-protocol-guard.d.ts +6 -0
- package/dist/control-protocol-guard.js +14 -2
- package/dist/control-protocol-guard.js.map +1 -1
- package/dist/control-schema-version.d.ts +48 -31
- package/dist/control-schema-version.js +67 -45
- package/dist/control-schema-version.js.map +1 -1
- package/dist/control-schema.d.ts +8 -8
- package/dist/control-schema.js +16 -16
- package/dist/control-schema.js.map +1 -1
- package/dist/control-write-retry.d.ts +42 -7
- package/dist/control-write-retry.js +87 -19
- package/dist/control-write-retry.js.map +1 -1
- package/dist/enrolled-machine-store.d.ts +3 -3
- package/dist/enrolled-machine-store.js +3 -3
- package/dist/formation-token.d.ts +48 -0
- package/dist/formation-token.js +26 -0
- package/dist/formation-token.js.map +1 -0
- package/dist/index.d.ts +14 -13
- package/dist/index.js +16 -13
- package/dist/index.js.map +1 -1
- package/dist/joined-strand-store.d.ts +26 -9
- package/dist/joined-strand-store.js +63 -24
- package/dist/joined-strand-store.js.map +1 -1
- package/dist/link-budget.d.ts +9 -7
- package/dist/link-budget.js +9 -7
- package/dist/link-budget.js.map +1 -1
- package/dist/member-redemption.d.ts +15 -9
- package/dist/member-redemption.js +13 -8
- package/dist/member-redemption.js.map +1 -1
- package/dist/membership-view.d.ts +91 -0
- package/dist/membership-view.js +110 -0
- package/dist/membership-view.js.map +1 -0
- package/dist/owner-grant-protocol.d.ts +11 -7
- package/dist/owner-grant-protocol.js +31 -17
- package/dist/owner-grant-protocol.js.map +1 -1
- package/dist/peer-addr-book.d.ts +10 -1
- package/dist/peer-addr-book.js +4 -3
- package/dist/peer-addr-book.js.map +1 -1
- package/dist/peer-join-backfill.d.ts +89 -20
- package/dist/peer-join-backfill.js +265 -108
- package/dist/peer-join-backfill.js.map +1 -1
- package/dist/pending-join-runner.d.ts +48 -18
- package/dist/pending-join-runner.js +74 -56
- package/dist/pending-join-runner.js.map +1 -1
- package/dist/seed-bootstrap.d.ts +47 -40
- package/dist/seed-bootstrap.js +66 -61
- package/dist/seed-bootstrap.js.map +1 -1
- package/dist/strand-database.d.ts +23 -2
- package/dist/strand-database.js +26 -6
- package/dist/strand-database.js.map +1 -1
- package/dist/strand-first-sync-gate.d.ts +176 -89
- package/dist/strand-first-sync-gate.js +288 -122
- package/dist/strand-first-sync-gate.js.map +1 -1
- package/dist/strand-formation-deadlines.d.ts +9 -9
- package/dist/strand-formation-deadlines.js +9 -9
- package/dist/strand-formation-manager.d.ts +23 -17
- package/dist/strand-formation-manager.js +46 -44
- package/dist/strand-formation-manager.js.map +1 -1
- package/dist/strand-formation-protocol.d.ts +5 -8
- package/dist/strand-formation-protocol.js +101 -16
- package/dist/strand-formation-protocol.js.map +1 -1
- package/dist/strand-instance-manager.d.ts +26 -17
- package/dist/strand-instance-manager.js +119 -50
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-membership-reconciler.d.ts +16 -13
- package/dist/strand-membership-reconciler.js +30 -22
- package/dist/strand-membership-reconciler.js.map +1 -1
- package/dist/strand-membership-writer.d.ts +40 -28
- package/dist/strand-membership-writer.js +212 -153
- package/dist/strand-membership-writer.js.map +1 -1
- package/dist/strand-move.js +5 -2
- package/dist/strand-move.js.map +1 -1
- package/dist/strand-revocation-enforcer.d.ts +134 -60
- package/dist/strand-revocation-enforcer.js +144 -71
- package/dist/strand-revocation-enforcer.js.map +1 -1
- package/dist/strand-solicitation.d.ts +50 -39
- package/dist/strand-solicitation.js +10 -3
- package/dist/strand-solicitation.js.map +1 -1
- package/dist/strand-watcher.d.ts +80 -13
- package/dist/strand-watcher.js +152 -48
- package/dist/strand-watcher.js.map +1 -1
- package/dist/table-change-watch.d.ts +63 -0
- package/dist/table-change-watch.js +209 -0
- package/dist/table-change-watch.js.map +1 -0
- package/dist/timeout-scheduler.d.ts +4 -3
- package/dist/timeout-scheduler.js +4 -3
- package/dist/timeout-scheduler.js.map +1 -1
- package/dist/types.d.ts +90 -49
- package/dist/types.js +4 -4
- package/dist/types.js.map +1 -1
- package/package.json +8 -8
- package/src/cadre-invite-protocol.ts +119 -31
- package/src/cadre-node.ts +1282 -584
- package/src/control-cohort.ts +86 -9
- package/src/control-database.ts +848 -403
- package/src/control-formation-recorder.ts +359 -353
- package/src/control-protocol-guard.ts +16 -2
- package/src/control-schema-version.ts +101 -51
- package/src/control-schema.ts +16 -16
- package/src/control-write-retry.ts +91 -19
- package/src/delegate-admission.ts +351 -351
- package/src/enrolled-machine-store.ts +3 -3
- package/src/formation-token.ts +63 -0
- package/src/index.ts +30 -17
- package/src/joined-strand-store.ts +69 -24
- package/src/link-budget.ts +9 -7
- package/src/member-redemption.ts +20 -13
- package/src/membership-view.ts +144 -0
- package/src/owner-grant-protocol.ts +33 -18
- package/src/peer-addr-book.ts +4 -3
- package/src/peer-join-backfill.ts +971 -761
- package/src/pending-join-runner.ts +76 -53
- package/src/seed-bootstrap.ts +72 -67
- package/src/strand-database.ts +352 -322
- package/src/strand-first-sync-gate.ts +334 -134
- package/src/strand-formation-deadlines.ts +227 -227
- package/src/strand-formation-manager.ts +731 -725
- package/src/strand-formation-protocol.ts +122 -24
- package/src/strand-instance-manager.ts +2092 -2026
- package/src/strand-membership-reconciler.ts +33 -25
- package/src/strand-membership-writer.ts +2093 -2019
- package/src/strand-move.ts +5 -2
- package/src/strand-revocation-enforcer.ts +740 -654
- package/src/strand-solicitation.ts +61 -34
- package/src/strand-watcher.ts +175 -56
- package/src/table-change-watch.ts +285 -0
- package/src/timeout-scheduler.ts +29 -28
- package/src/types.ts +89 -51
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Libp2p, PeerId } from '@libp2p/interface';
|
|
2
2
|
import type { IPeerNetwork } from '@optimystic/db-core';
|
|
3
3
|
import { BlockTransferClient, type IRawStorage } from '@optimystic/db-p2p';
|
|
4
|
+
import type { Libp2pNodeWithRepo } from './types.js';
|
|
4
5
|
/**
|
|
5
6
|
* The block-transfer protocol's hard cap on one length-prefixed message. Mirrors
|
|
6
7
|
* `MAX_BLOCK_MESSAGE_BYTES` in `@optimystic/db-p2p`'s `protocol-limits.ts` (8 MiB), which
|
|
@@ -19,7 +20,10 @@ export declare const PEER_JOIN_BACKFILL_WARN_AFTER_FAILURES = 3;
|
|
|
19
20
|
export interface PeerJoinBackfillConfig {
|
|
20
21
|
/** Default true. False disables the catch-up entirely (the pre-existing behaviour). */
|
|
21
22
|
enabled?: boolean;
|
|
22
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Settle time before re-running a peer this instance has already run for (a denied or failed
|
|
25
|
+
* peer's next schedule), ms. Default 1000. A peer never run for is run at once.
|
|
26
|
+
*/
|
|
23
27
|
debounceMs?: number;
|
|
24
28
|
/** Ceiling on blocks copied in one catch-up. Default 10_000. Reaching it is LOGGED, never silent. */
|
|
25
29
|
maxBlocks?: number;
|
|
@@ -76,6 +80,12 @@ export interface PeerJoinBackfillDeps {
|
|
|
76
80
|
* see the module comment for why the strand no-gate argument does not carry over.
|
|
77
81
|
*/
|
|
78
82
|
authorizePeer?: (peerId: string) => Promise<boolean>;
|
|
83
|
+
/**
|
|
84
|
+
* The node's `reportBlockHeld` ({@link Libp2pNodeWithRepo.reportBlockHeld}), told of each block a
|
|
85
|
+
* peer accepted so Optimystic's under-replication drain does not push the peer the same block
|
|
86
|
+
* again, one request per block. Absent = nothing reported, and the drain re-sends.
|
|
87
|
+
*/
|
|
88
|
+
reportBlockHeld?: Libp2pNodeWithRepo['reportBlockHeld'];
|
|
79
89
|
/**
|
|
80
90
|
* Test seam: build the per-peer push client. Defaults to a real
|
|
81
91
|
* `BlockTransferClient` over {@link peerNetwork} + {@link protocolPrefix}.
|
|
@@ -84,11 +94,21 @@ export interface PeerJoinBackfillDeps {
|
|
|
84
94
|
}
|
|
85
95
|
/** What one peer's catch-up actually did. Returned for tests and logged at the end of each run. */
|
|
86
96
|
export interface PeerJoinBackfillResult {
|
|
87
|
-
/** Blocks offered: had a committed `latest` AND materialized content locally. */
|
|
97
|
+
/** Blocks offered: had a committed `latest` AND materialized content locally, and the peer was not known to hold it. */
|
|
88
98
|
offered: number;
|
|
99
|
+
/**
|
|
100
|
+
* Skipped: the peer already accepted or refused this revision from this node, or signed its
|
|
101
|
+
* commit (see "What is pushed" in the module comment). Not offered, so not counted toward
|
|
102
|
+
* `maxBlocks`.
|
|
103
|
+
*/
|
|
104
|
+
alreadyHeld: number;
|
|
89
105
|
/** Blocks the remote reported it persisted. */
|
|
90
106
|
accepted: number;
|
|
91
|
-
/**
|
|
107
|
+
/**
|
|
108
|
+
* Block ids the remote reported in `missing` (unparseable, not persisted, or pushed without a
|
|
109
|
+
* commit proof it accepts). Remembered per revision; not offered to that peer again until the
|
|
110
|
+
* local revision moves.
|
|
111
|
+
*/
|
|
92
112
|
rejected: string[];
|
|
93
113
|
/** Skipped: metadata has no `latest` (pending-only — not yet a durability claim here). */
|
|
94
114
|
uncommitted: number;
|
|
@@ -109,8 +129,8 @@ export interface PeerJoinBackfillResult {
|
|
|
109
129
|
*
|
|
110
130
|
* Best-effort throughout: nothing here throws into a libp2p event handler or into a
|
|
111
131
|
* runtime bring-up; a failed chunk is logged and the run continues. A peer is marked
|
|
112
|
-
*
|
|
113
|
-
*
|
|
132
|
+
* caught up only after a run with no thrown chunk, so a peer whose catch-up failed is
|
|
133
|
+
* retried; each block is pushed to each peer once (see "What is pushed" in the module comment).
|
|
114
134
|
*/
|
|
115
135
|
export declare class PeerJoinBackfill {
|
|
116
136
|
private readonly deps;
|
|
@@ -119,10 +139,22 @@ export declare class PeerJoinBackfill {
|
|
|
119
139
|
private started;
|
|
120
140
|
private stopped;
|
|
121
141
|
/**
|
|
122
|
-
* Peers
|
|
123
|
-
* {@link forceCatchUpPeer}
|
|
142
|
+
* Peers caught up since their current connection opened. Cleared for a peer when its last
|
|
143
|
+
* connection closes, so a reconnect re-runs; {@link forceCatchUpPeer} runs past it.
|
|
124
144
|
*/
|
|
125
145
|
private readonly done;
|
|
146
|
+
/**
|
|
147
|
+
* Peers that disconnected while their run was in flight, so that run does not mark them
|
|
148
|
+
* {@link done} after the disconnect cleared it. Cleared when the run ends.
|
|
149
|
+
*/
|
|
150
|
+
private readonly disconnectedInFlight;
|
|
151
|
+
/** Per-peer, per-block verdicts from push replies; see {@link PeerMemo}. */
|
|
152
|
+
private readonly memos;
|
|
153
|
+
/**
|
|
154
|
+
* Peers a run has been started for. A peer not in it is run at once on its first schedule;
|
|
155
|
+
* later schedules wait out `debounceMs`.
|
|
156
|
+
*/
|
|
157
|
+
private readonly contacted;
|
|
126
158
|
/**
|
|
127
159
|
* Peers with a catch-up currently running, each with that run (suppresses concurrent
|
|
128
160
|
* duplicates; {@link forceCatchUpPeer} waits on the run).
|
|
@@ -130,9 +162,9 @@ export declare class PeerJoinBackfill {
|
|
|
130
162
|
private readonly inFlight;
|
|
131
163
|
/**
|
|
132
164
|
* Peers whose (re-)schedule arrived while their OWN run was in flight, replayed once
|
|
133
|
-
* that run finishes. Load-bearing for the gated path: the gate
|
|
134
|
-
* a
|
|
135
|
-
*
|
|
165
|
+
* that run finishes. Load-bearing for the gated path: the gate is judged once, at the start
|
|
166
|
+
* of a run, and the run's pushes take long enough for the very membership commit that would
|
|
167
|
+
* have authorized the peer to land after that check —
|
|
136
168
|
* dropping that schedule (rather than deferring it) leaves the denied peer waiting for a
|
|
137
169
|
* reconnect, which is exactly what the re-arm exists to avoid.
|
|
138
170
|
*/
|
|
@@ -150,17 +182,32 @@ export declare class PeerJoinBackfill {
|
|
|
150
182
|
/** Peers already reported on `console.warn`; reset when a run finally lands cleanly. */
|
|
151
183
|
private readonly warned;
|
|
152
184
|
private readonly onPeerIdentify;
|
|
185
|
+
private readonly onPeerDisconnect;
|
|
153
186
|
private loggedNoListBlockIds;
|
|
154
187
|
constructor(deps: PeerJoinBackfillDeps, config?: PeerJoinBackfillConfig);
|
|
155
188
|
/**
|
|
156
189
|
* Subscribe to `peer:identify` AND schedule a catch-up for already-connected peers whose
|
|
157
190
|
* stored protocols already name this network's block-transfer protocol — a peer that does
|
|
158
|
-
* not speak it (a bare circuit relay, a bootstrap node) is never scheduled at all.
|
|
159
|
-
*
|
|
191
|
+
* not speak it (a bare circuit relay, a bootstrap node) is never scheduled at all. Also
|
|
192
|
+
* subscribes to `peer:disconnect`, so a peer caught up before it went away is run again on
|
|
193
|
+
* its return. See {@link speaksBlockTransfer} and the module comment.
|
|
160
194
|
*/
|
|
161
195
|
start(): void;
|
|
162
196
|
/** Unsubscribe, clear timers; in-flight runs observe the stopped flag and bail. */
|
|
163
197
|
stop(): void;
|
|
198
|
+
/**
|
|
199
|
+
* A peer's last connection closed: it is no longer caught up, so its next `peer:identify`
|
|
200
|
+
* re-runs. Only `done` is cleared. The memo stays (it keeps the re-run to what moved),
|
|
201
|
+
* `contacted` stays (a link flapping inside one settle window costs one run), and the
|
|
202
|
+
* backoff state stays (clearing it re-dials an unreachable peer on every reconnect; see the
|
|
203
|
+
* module comment's retry paragraph).
|
|
204
|
+
*
|
|
205
|
+
* When the returning peer wrote while away with a cohort that named this node, its own
|
|
206
|
+
* re-run pushes those blocks here and reports them through `reportBlockHeld`, so its
|
|
207
|
+
* under-replication drain does not push them again. Revisit if a measurement shows reconnect
|
|
208
|
+
* re-runs dominating push traffic.
|
|
209
|
+
*/
|
|
210
|
+
private forgetCaughtUp;
|
|
164
211
|
/**
|
|
165
212
|
* (Re-)schedule a debounced catch-up for every currently-connected peer whose protocols, as
|
|
166
213
|
* already stored in the libp2p peer store, name this network's block-transfer protocol. A
|
|
@@ -177,7 +224,11 @@ export declare class PeerJoinBackfill {
|
|
|
177
224
|
scheduleConnectedPeers(): Promise<number>;
|
|
178
225
|
/** Schedules `peerId` only if the peer store already knows it speaks this network's protocol. */
|
|
179
226
|
private scheduleIfKnownToSpeak;
|
|
180
|
-
/**
|
|
227
|
+
/**
|
|
228
|
+
* Entry point for connection churn: one run per peer per settle window, except that a peer
|
|
229
|
+
* never run for is run at once (on a zero-delay timer, so a burst of identify events in one
|
|
230
|
+
* turn still collapses, and no work happens inside the libp2p event dispatch).
|
|
231
|
+
*/
|
|
181
232
|
private schedulePeer;
|
|
182
233
|
/**
|
|
183
234
|
* Run one peer's catch-up now, bypassing the debounce. Never rejects. Returns an
|
|
@@ -186,14 +237,16 @@ export declare class PeerJoinBackfill {
|
|
|
186
237
|
*/
|
|
187
238
|
catchUpPeer(peerId: PeerId): Promise<PeerJoinBackfillResult>;
|
|
188
239
|
/**
|
|
189
|
-
* Run one peer's catch-up now and wait for it,
|
|
190
|
-
*
|
|
191
|
-
*
|
|
240
|
+
* Run one peer's catch-up now and wait for it, even when the peer is memoized as caught up:
|
|
241
|
+
* wait out a run already in flight for it, then run again. The run still skips every block the
|
|
242
|
+
* peer is known to hold (it accepted or refused that revision, or signed it), so for a peer that
|
|
243
|
+
* holds the whole store it pushes nothing and returns `alreadyHeld` equal to the store size.
|
|
244
|
+
* Never rejects; an all-zero result only when stopped.
|
|
192
245
|
*
|
|
193
246
|
* For a caller that must know the peer holds this store before it proceeds, where
|
|
194
247
|
* {@link catchUpPeer}'s empty answer would hide a run that was denied (a `peer:identify`
|
|
195
|
-
* run can pass the gate a moment before the caller authorized the peer) or
|
|
196
|
-
*
|
|
248
|
+
* run can pass the gate a moment before the caller authorized the peer) or commits made
|
|
249
|
+
* since the peer was caught up.
|
|
197
250
|
*/
|
|
198
251
|
forceCatchUpPeer(peerId: PeerId): Promise<PeerJoinBackfillResult>;
|
|
199
252
|
/**
|
|
@@ -218,10 +271,26 @@ export declare class PeerJoinBackfill {
|
|
|
218
271
|
* timeout. Reset when a run finally lands cleanly, so a peer that recovers can report again.
|
|
219
272
|
*/
|
|
220
273
|
private warnPersistentFailure;
|
|
274
|
+
/** This peer's memo, created empty on first use. */
|
|
275
|
+
private memoFor;
|
|
276
|
+
/**
|
|
277
|
+
* Tell the node which blocks of one push reply the peer accepted, at the revision pushed.
|
|
278
|
+
* Best-effort: a failed report is logged and costs only the drain's duplicate push.
|
|
279
|
+
*/
|
|
280
|
+
private reportAccepted;
|
|
221
281
|
/**
|
|
222
|
-
* The actual copy. `clean` =
|
|
282
|
+
* The actual copy. `clean` = the gate admitted the peer, the store is listable and no push
|
|
283
|
+
* threw (a block the receiver refused is remembered per block instead, see {@link PeerMemo}).
|
|
223
284
|
* `pushFailed` = at least one push THREW, which is the only non-clean outcome a retry can
|
|
224
|
-
* change; the others are verdicts (denied, inert store
|
|
285
|
+
* change; the others are verdicts (denied, inert store).
|
|
225
286
|
*/
|
|
226
287
|
private runCatchUp;
|
|
288
|
+
/**
|
|
289
|
+
* Read one block for the push to `key`, or count why it is skipped in `result` and return
|
|
290
|
+
* nothing: not committed, already held by the peer (memo or its own commit signature), not
|
|
291
|
+
* materialized, or too large for one message. The proof is read for EXACTLY the revision the
|
|
292
|
+
* meta will name, from the same `latest`; absent is normal (nothing retained a proof for that
|
|
293
|
+
* revision), and the block still ships with its meta for the receiver to decide.
|
|
294
|
+
*/
|
|
295
|
+
private readOffer;
|
|
227
296
|
}
|