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