@serfab/cadre-core 1.5.0 → 1.7.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/dist/cadre-node.d.ts +206 -67
- package/dist/cadre-node.js +399 -98
- package/dist/cadre-node.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +17 -1
- package/dist/index.js.map +1 -1
- package/dist/joined-strand-store.d.ts +112 -0
- package/dist/joined-strand-store.js +263 -0
- package/dist/joined-strand-store.js.map +1 -0
- package/dist/key-store.d.ts +6 -0
- package/dist/key-store.js.map +1 -1
- package/dist/link-budget.d.ts +95 -53
- package/dist/link-budget.js +97 -53
- package/dist/link-budget.js.map +1 -1
- package/dist/node-local-snapshot.d.ts +5 -4
- package/dist/node-local-snapshot.js +6 -3
- package/dist/node-local-snapshot.js.map +1 -1
- package/dist/peer-dial.d.ts +3 -3
- package/dist/peer-dial.js +3 -3
- package/dist/peer-join-backfill.d.ts +35 -16
- package/dist/peer-join-backfill.js +117 -57
- package/dist/peer-join-backfill.js.map +1 -1
- package/dist/relay-reservation.d.ts +2 -2
- package/dist/relay-reservation.js +2 -2
- package/dist/seed-bootstrap.js +1 -1
- package/dist/strand-first-sync-gate.d.ts +88 -43
- package/dist/strand-first-sync-gate.js +92 -46
- package/dist/strand-first-sync-gate.js.map +1 -1
- package/dist/strand-instance-manager.d.ts +39 -0
- package/dist/strand-instance-manager.js +80 -3
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-peer-book-file.d.ts +12 -0
- package/dist/strand-peer-book-file.js +37 -0
- package/dist/strand-peer-book-file.js.map +1 -0
- package/dist/strand-peer-book-protocol.d.ts +159 -0
- package/dist/strand-peer-book-protocol.js +360 -0
- package/dist/strand-peer-book-protocol.js.map +1 -0
- package/dist/strand-peer-book-swap.d.ts +104 -0
- package/dist/strand-peer-book-swap.js +284 -0
- package/dist/strand-peer-book-swap.js.map +1 -0
- package/dist/strand-peer-book.d.ts +159 -0
- package/dist/strand-peer-book.js +354 -0
- package/dist/strand-peer-book.js.map +1 -0
- package/dist/strand-peer-observer.d.ts +88 -0
- package/dist/strand-peer-observer.js +180 -0
- package/dist/strand-peer-observer.js.map +1 -0
- package/dist/types.d.ts +84 -17
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -1
- package/package.json +11 -7
- package/src/cadre-node.ts +7776 -7445
- package/src/index.ts +68 -0
- package/src/joined-strand-store.ts +308 -0
- package/src/key-store.ts +6 -0
- package/src/link-budget.ts +100 -53
- package/src/node-local-snapshot.ts +293 -289
- package/src/peer-dial.ts +3 -3
- package/src/peer-join-backfill.ts +709 -647
- package/src/relay-reservation.ts +2 -2
- package/src/seed-bootstrap.ts +1 -1
- package/src/strand-first-sync-gate.ts +352 -306
- package/src/strand-instance-manager.ts +106 -3
- package/src/strand-peer-book-file.ts +39 -0
- package/src/strand-peer-book-protocol.ts +463 -0
- package/src/strand-peer-book-swap.ts +338 -0
- package/src/strand-peer-book.ts +468 -0
- package/src/strand-peer-observer.ts +235 -0
- package/src/types.ts +86 -17
package/dist/link-budget.d.ts
CHANGED
|
@@ -35,62 +35,78 @@
|
|
|
35
35
|
*
|
|
36
36
|
* | operation | link round trips | at the declared default |
|
|
37
37
|
* | ---------------------------------------------------- | ---------------- | ----------------------- |
|
|
38
|
-
* | open a relayed connection to another machine | 4 |
|
|
39
|
-
* | dial the relay itself | 1 |
|
|
40
|
-
* | request a reservation on an open relay connection | 1 |
|
|
41
|
-
* | negotiate a protocol over an established circuit | 1 |
|
|
42
|
-
*
|
|
43
|
-
* **Measured** 2026-09-26, one Windows machine, loopback dedicated relay
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* already thrown the half-built connection away — so the first stream over it died with
|
|
38
|
+
* | open a relayed connection to another machine | 4 | 14 000 ms |
|
|
39
|
+
* | dial the relay itself | 1 | 3 500 ms |
|
|
40
|
+
* | request a reservation on an open relay connection | 1 | 3 500 ms |
|
|
41
|
+
* | negotiate a protocol over an established circuit | 1 | 3 500 ms |
|
|
42
|
+
*
|
|
43
|
+
* **Measured** 2026-09-26, one Windows machine, loopback dedicated relay: a relayed dial took
|
|
44
|
+
* 20-25 ms at no delay, **7 255-7 279 ms at 900 ms one-way**, and **12 066-12 094 ms at 1 500 ms
|
|
45
|
+
* one-way**. Four link round trips of pure delay would be 7 200 and 12 000, so the real cost
|
|
46
|
+
* sits about 60-95 ms ABOVE the arithmetic — the handshakes, which no delay figure contains.
|
|
47
|
+
* That residue is why {@link DECLARED_LINK_ROUND_TRIP_MS} carries headroom over the link sereus
|
|
48
|
+
* supports rather than matching it exactly: a declaration equal to the supported round trip
|
|
49
|
+
* would derive a budget marginally BELOW the dial it has to contain.
|
|
50
|
+
*
|
|
51
|
+
* ── libp2p's own two limits ──
|
|
52
|
+
*
|
|
53
|
+
* Two limits inside libp2p bound the same relayed dial as cadre's budgets do, and both were
|
|
54
|
+
* 10 000 ms until `@optimystic/db-p2p` 1.7.0 let an embedder set them: the DIALER's
|
|
55
|
+
* `connectionManager.dialTimeout`, which bounds every dial that carries no abort signal of its
|
|
56
|
+
* own, and the LISTENER's `connectionManager.inboundUpgradeTimeout`, which is how long the
|
|
57
|
+
* machine being called lets a half-built connection finish its handshakes. At 10 000 ms each,
|
|
58
|
+
* no relayed connection could be opened above about 1 250 ms one-way (a 2.5-second link round
|
|
59
|
+
* trip) whatever cadre declared. The listener's limit is the one that makes that failure
|
|
60
|
+
* silent: at 1 500 ms one-way the dialer's own 12 094 ms dial RESOLVED while the listener had
|
|
61
|
+
* already thrown the connection away at 10 s, so the first stream over it died with
|
|
63
62
|
* `Unexpected EOF - stream closed while reading 0/1 bytes` and the listener reported no peer at
|
|
64
|
-
* all.
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
63
|
+
* all. cadre now declares both from this module ({@link connectionManagerTimeouts}) on the
|
|
64
|
+
* control node and every strand node.
|
|
65
|
+
*
|
|
66
|
+
* ── What still fails at the supported link ──
|
|
67
|
+
*
|
|
68
|
+
* - **Optimystic's own request dials.** `@optimystic/db-p2p`'s RPC clients dial with fixed
|
|
69
|
+
* 3 000 ms deadlines of their own (`DEFAULT_DIAL_TIMEOUT_MS`, the `pushDialTimeoutMs`
|
|
70
|
+
* defaults), which neither limit above reaches because a caller's signal replaces
|
|
71
|
+
* `dialTimeout`. So an Optimystic request that has to OPEN a relayed connection fails above
|
|
72
|
+
* 375 ms one-way. A request over a connection that is already open does not dial, and the
|
|
73
|
+
* connections cadre opens itself are budgeted here. Upstream:
|
|
74
|
+
* `debt-rpc-dial-deadlines-cannot-open-a-slow-relayed-connection` in optimystic.
|
|
75
|
+
* - **Cadre deadlines still typed as milliseconds.** The strand wake, strand-address and seed
|
|
76
|
+
* delivery deadlines, and the cohort read deadline, bound exchanges over the same link but do
|
|
77
|
+
* not derive from it: `tickets/backlog/debt-three-more-dial-deadlines-ignore-the-declared-link`.
|
|
78
|
+
* - **A machine that declares a faster link than its peers.** Every machine is the listener
|
|
79
|
+
* for the others, so its `inboundUpgradeTimeout` — derived from ITS declaration — bounds
|
|
80
|
+
* connections other machines open to it. A peer declaring 3 500 ms dialing a machine that
|
|
81
|
+
* declared 500 ms gets exactly the silent failure above. Declare the same link on every
|
|
82
|
+
* machine of a party.
|
|
75
83
|
*/
|
|
84
|
+
import type { Libp2pConnectionTimeouts } from '@optimystic/db-p2p';
|
|
76
85
|
/**
|
|
77
86
|
* The link round trip cadre assumes when a host declares none, in milliseconds. A deployment
|
|
78
87
|
* that knows its own link states it with `NetworkConfig.linkRoundTripMs` instead.
|
|
79
88
|
*
|
|
80
|
-
* **Why
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
89
|
+
* **Why 3 500.** Sereus supports two machines that reach each other only through a relay up to
|
|
90
|
+
* a **3-second link round trip** (1 500 ms each way — a congested mobile or satellite link;
|
|
91
|
+
* `docs/architecture.md` → "Relay Integration"). The worst relayed dial measured at that link
|
|
92
|
+
* was 12 094 ms, above the 12 000 ms a declaration of exactly 3 000 would derive, so the
|
|
93
|
+
* declaration rounds the supported link up to the next half second. 3 500 derives 14 000 ms
|
|
94
|
+
* and leaves about 1.9 s over that dial: room for a phone's Noise handshake, which the
|
|
95
|
+
* loopback measurement on a desktop does not contain. (The previous 2 000 followed the same
|
|
96
|
+
* convention for the 1.8 s band sereus supported before, with about 720 ms to spare.)
|
|
97
|
+
*
|
|
98
|
+
* Two budgets outside this module were sized against the 1.8 s band and do NOT move with it:
|
|
99
|
+
* `COHORT_READ_DEADLINE_MS` (`quereus-plugin-sereus/src/cluster-size.ts`, 5 000 ms) and
|
|
100
|
+
* `DEFAULT_STRAND_FIRST_SYNC_TIMEOUT_MS` (`strand-first-sync-gate.ts`). The module doc's
|
|
101
|
+
* "What still fails" list carries the first.
|
|
102
|
+
*
|
|
103
|
+
* What 3 500 costs, against 2 000: a peer that is genuinely gone holds each operation longer
|
|
104
|
+
* before it is abandoned and retried — a relayed dial or a reservation drive 14 s instead of
|
|
105
|
+
* 8 s, and a control-cohort dial of one peer across all its addresses 56 s instead of 32 s.
|
|
106
|
+
* Raise it further for a link slower still; lower it only on a deployment where EVERY machine
|
|
107
|
+
* of the party is that close, for the reason the "What still fails" list gives.
|
|
92
108
|
*/
|
|
93
|
-
export declare const DECLARED_LINK_ROUND_TRIP_MS =
|
|
109
|
+
export declare const DECLARED_LINK_ROUND_TRIP_MS = 3500;
|
|
94
110
|
/**
|
|
95
111
|
* Link round trips one relayed connection setup costs: transport, encryption and multiplexer
|
|
96
112
|
* handshakes to the relay, the circuit open, then both handshakes again end to end through it.
|
|
@@ -127,10 +143,10 @@ export declare const CIRCUIT_REQUEST_ROUND_TRIPS = 2;
|
|
|
127
143
|
*
|
|
128
144
|
* NOTE: 6 000 ms is not a measurement of any throughput — it is the residue of the 10 000 ms
|
|
129
145
|
* this deadline shipped as before it was split into a latency part and a transfer part, chosen
|
|
130
|
-
* so that at the
|
|
131
|
-
* slower. Nobody has measured how long 1 MiB takes to cross a relayed mobile
|
|
132
|
-
* ever time out with the transfer only part done, measure that and raise THIS,
|
|
133
|
-
* round trip.
|
|
146
|
+
* so that at the declaration then in force (2 000 ms) the derived value stayed 10 000 and no
|
|
147
|
+
* fast link got slower. Nobody has measured how long 1 MiB takes to cross a relayed mobile
|
|
148
|
+
* link. If pushes ever time out with the transfer only part done, measure that and raise THIS,
|
|
149
|
+
* not the declared round trip.
|
|
134
150
|
*/
|
|
135
151
|
export declare const PUSH_TRANSFER_ALLOWANCE_MS = 6000;
|
|
136
152
|
/**
|
|
@@ -155,6 +171,32 @@ export declare function resolveLinkRoundTripMs(linkRoundTripMs?: number): number
|
|
|
155
171
|
* relay: {@link RELAYED_DIAL_ROUND_TRIPS} at the declared link round trip.
|
|
156
172
|
*/
|
|
157
173
|
export declare function relayedDialBudgetMs(linkRoundTripMs?: number): number;
|
|
174
|
+
/**
|
|
175
|
+
* libp2p's two connection-manager limits for a node at the declared link, handed to
|
|
176
|
+
* `@optimystic/db-p2p`'s `NodeOptions.connectionManager` on the control node and every strand
|
|
177
|
+
* node.
|
|
178
|
+
*
|
|
179
|
+
* Both bound the same thing — opening a relayed connection, measured at 8 one-way link delays,
|
|
180
|
+
* which is {@link RELAYED_DIAL_ROUND_TRIPS} (4) link round trips — so both are
|
|
181
|
+
* {@link relayedDialBudgetMs}: 4 x 3 500 = 14 000 ms at the default declaration, covering the
|
|
182
|
+
* 12 094 ms measured at the supported 3-second link.
|
|
183
|
+
*
|
|
184
|
+
* The listener's limit is deliberately NOT smaller than the dialer's. The listener's clock
|
|
185
|
+
* starts only when the relay hands it the circuit, a few one-way delays after the dialer's
|
|
186
|
+
* started, and both sides finish the handshakes at about the same moment; so with equal limits
|
|
187
|
+
* the listener never discards a connection that the dialer's own dial would still accept. A
|
|
188
|
+
* listener limit below the dialer's is what produced the silent failure in the module doc.
|
|
189
|
+
*
|
|
190
|
+
* The cost of a longer `inboundUpgradeTimeout` is that a peer which opens a connection and then
|
|
191
|
+
* stalls its handshake holds that half-built connection 14 s instead of 10 s.
|
|
192
|
+
*
|
|
193
|
+
* NOTE: derived from the declaration alone, so a per-field override that raises a cadre dial
|
|
194
|
+
* budget above it (`controlCohort.perAddressDialTimeoutMs`, `strandBackfill.dialTimeoutMs`)
|
|
195
|
+
* does not raise these; a dial that outlasts the listener's limit gets the silent failure
|
|
196
|
+
* again. If such overrides start being used for slow links, raise the declaration instead or
|
|
197
|
+
* take the largest configured dial budget here.
|
|
198
|
+
*/
|
|
199
|
+
export declare function connectionManagerTimeouts(linkRoundTripMs?: number): Libp2pConnectionTimeouts;
|
|
158
200
|
/**
|
|
159
201
|
* Deadline for one whole relay reservation drive: {@link RELAY_RESERVATION_ROUND_TRIPS} at the
|
|
160
202
|
* declared link round trip.
|
package/dist/link-budget.js
CHANGED
|
@@ -35,62 +35,77 @@
|
|
|
35
35
|
*
|
|
36
36
|
* | operation | link round trips | at the declared default |
|
|
37
37
|
* | ---------------------------------------------------- | ---------------- | ----------------------- |
|
|
38
|
-
* | open a relayed connection to another machine | 4 |
|
|
39
|
-
* | dial the relay itself | 1 |
|
|
40
|
-
* | request a reservation on an open relay connection | 1 |
|
|
41
|
-
* | negotiate a protocol over an established circuit | 1 |
|
|
42
|
-
*
|
|
43
|
-
* **Measured** 2026-09-26, one Windows machine, loopback dedicated relay
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* already thrown the half-built connection away — so the first stream over it died with
|
|
38
|
+
* | open a relayed connection to another machine | 4 | 14 000 ms |
|
|
39
|
+
* | dial the relay itself | 1 | 3 500 ms |
|
|
40
|
+
* | request a reservation on an open relay connection | 1 | 3 500 ms |
|
|
41
|
+
* | negotiate a protocol over an established circuit | 1 | 3 500 ms |
|
|
42
|
+
*
|
|
43
|
+
* **Measured** 2026-09-26, one Windows machine, loopback dedicated relay: a relayed dial took
|
|
44
|
+
* 20-25 ms at no delay, **7 255-7 279 ms at 900 ms one-way**, and **12 066-12 094 ms at 1 500 ms
|
|
45
|
+
* one-way**. Four link round trips of pure delay would be 7 200 and 12 000, so the real cost
|
|
46
|
+
* sits about 60-95 ms ABOVE the arithmetic — the handshakes, which no delay figure contains.
|
|
47
|
+
* That residue is why {@link DECLARED_LINK_ROUND_TRIP_MS} carries headroom over the link sereus
|
|
48
|
+
* supports rather than matching it exactly: a declaration equal to the supported round trip
|
|
49
|
+
* would derive a budget marginally BELOW the dial it has to contain.
|
|
50
|
+
*
|
|
51
|
+
* ── libp2p's own two limits ──
|
|
52
|
+
*
|
|
53
|
+
* Two limits inside libp2p bound the same relayed dial as cadre's budgets do, and both were
|
|
54
|
+
* 10 000 ms until `@optimystic/db-p2p` 1.7.0 let an embedder set them: the DIALER's
|
|
55
|
+
* `connectionManager.dialTimeout`, which bounds every dial that carries no abort signal of its
|
|
56
|
+
* own, and the LISTENER's `connectionManager.inboundUpgradeTimeout`, which is how long the
|
|
57
|
+
* machine being called lets a half-built connection finish its handshakes. At 10 000 ms each,
|
|
58
|
+
* no relayed connection could be opened above about 1 250 ms one-way (a 2.5-second link round
|
|
59
|
+
* trip) whatever cadre declared. The listener's limit is the one that makes that failure
|
|
60
|
+
* silent: at 1 500 ms one-way the dialer's own 12 094 ms dial RESOLVED while the listener had
|
|
61
|
+
* already thrown the connection away at 10 s, so the first stream over it died with
|
|
63
62
|
* `Unexpected EOF - stream closed while reading 0/1 bytes` and the listener reported no peer at
|
|
64
|
-
* all.
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
63
|
+
* all. cadre now declares both from this module ({@link connectionManagerTimeouts}) on the
|
|
64
|
+
* control node and every strand node.
|
|
65
|
+
*
|
|
66
|
+
* ── What still fails at the supported link ──
|
|
67
|
+
*
|
|
68
|
+
* - **Optimystic's own request dials.** `@optimystic/db-p2p`'s RPC clients dial with fixed
|
|
69
|
+
* 3 000 ms deadlines of their own (`DEFAULT_DIAL_TIMEOUT_MS`, the `pushDialTimeoutMs`
|
|
70
|
+
* defaults), which neither limit above reaches because a caller's signal replaces
|
|
71
|
+
* `dialTimeout`. So an Optimystic request that has to OPEN a relayed connection fails above
|
|
72
|
+
* 375 ms one-way. A request over a connection that is already open does not dial, and the
|
|
73
|
+
* connections cadre opens itself are budgeted here. Upstream:
|
|
74
|
+
* `debt-rpc-dial-deadlines-cannot-open-a-slow-relayed-connection` in optimystic.
|
|
75
|
+
* - **Cadre deadlines still typed as milliseconds.** The strand wake, strand-address and seed
|
|
76
|
+
* delivery deadlines, and the cohort read deadline, bound exchanges over the same link but do
|
|
77
|
+
* not derive from it: `tickets/backlog/debt-three-more-dial-deadlines-ignore-the-declared-link`.
|
|
78
|
+
* - **A machine that declares a faster link than its peers.** Every machine is the listener
|
|
79
|
+
* for the others, so its `inboundUpgradeTimeout` — derived from ITS declaration — bounds
|
|
80
|
+
* connections other machines open to it. A peer declaring 3 500 ms dialing a machine that
|
|
81
|
+
* declared 500 ms gets exactly the silent failure above. Declare the same link on every
|
|
82
|
+
* machine of a party.
|
|
75
83
|
*/
|
|
76
84
|
/**
|
|
77
85
|
* The link round trip cadre assumes when a host declares none, in milliseconds. A deployment
|
|
78
86
|
* that knows its own link states it with `NetworkConfig.linkRoundTripMs` instead.
|
|
79
87
|
*
|
|
80
|
-
* **Why
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
88
|
+
* **Why 3 500.** Sereus supports two machines that reach each other only through a relay up to
|
|
89
|
+
* a **3-second link round trip** (1 500 ms each way — a congested mobile or satellite link;
|
|
90
|
+
* `docs/architecture.md` → "Relay Integration"). The worst relayed dial measured at that link
|
|
91
|
+
* was 12 094 ms, above the 12 000 ms a declaration of exactly 3 000 would derive, so the
|
|
92
|
+
* declaration rounds the supported link up to the next half second. 3 500 derives 14 000 ms
|
|
93
|
+
* and leaves about 1.9 s over that dial: room for a phone's Noise handshake, which the
|
|
94
|
+
* loopback measurement on a desktop does not contain. (The previous 2 000 followed the same
|
|
95
|
+
* convention for the 1.8 s band sereus supported before, with about 720 ms to spare.)
|
|
96
|
+
*
|
|
97
|
+
* Two budgets outside this module were sized against the 1.8 s band and do NOT move with it:
|
|
98
|
+
* `COHORT_READ_DEADLINE_MS` (`quereus-plugin-sereus/src/cluster-size.ts`, 5 000 ms) and
|
|
99
|
+
* `DEFAULT_STRAND_FIRST_SYNC_TIMEOUT_MS` (`strand-first-sync-gate.ts`). The module doc's
|
|
100
|
+
* "What still fails" list carries the first.
|
|
101
|
+
*
|
|
102
|
+
* What 3 500 costs, against 2 000: a peer that is genuinely gone holds each operation longer
|
|
103
|
+
* before it is abandoned and retried — a relayed dial or a reservation drive 14 s instead of
|
|
104
|
+
* 8 s, and a control-cohort dial of one peer across all its addresses 56 s instead of 32 s.
|
|
105
|
+
* Raise it further for a link slower still; lower it only on a deployment where EVERY machine
|
|
106
|
+
* of the party is that close, for the reason the "What still fails" list gives.
|
|
92
107
|
*/
|
|
93
|
-
export const DECLARED_LINK_ROUND_TRIP_MS =
|
|
108
|
+
export const DECLARED_LINK_ROUND_TRIP_MS = 3500;
|
|
94
109
|
/**
|
|
95
110
|
* Link round trips one relayed connection setup costs: transport, encryption and multiplexer
|
|
96
111
|
* handshakes to the relay, the circuit open, then both handshakes again end to end through it.
|
|
@@ -127,10 +142,10 @@ export const CIRCUIT_REQUEST_ROUND_TRIPS = 2;
|
|
|
127
142
|
*
|
|
128
143
|
* NOTE: 6 000 ms is not a measurement of any throughput — it is the residue of the 10 000 ms
|
|
129
144
|
* this deadline shipped as before it was split into a latency part and a transfer part, chosen
|
|
130
|
-
* so that at the
|
|
131
|
-
* slower. Nobody has measured how long 1 MiB takes to cross a relayed mobile
|
|
132
|
-
* ever time out with the transfer only part done, measure that and raise THIS,
|
|
133
|
-
* round trip.
|
|
145
|
+
* so that at the declaration then in force (2 000 ms) the derived value stayed 10 000 and no
|
|
146
|
+
* fast link got slower. Nobody has measured how long 1 MiB takes to cross a relayed mobile
|
|
147
|
+
* link. If pushes ever time out with the transfer only part done, measure that and raise THIS,
|
|
148
|
+
* not the declared round trip.
|
|
134
149
|
*/
|
|
135
150
|
export const PUSH_TRANSFER_ALLOWANCE_MS = 6000;
|
|
136
151
|
/**
|
|
@@ -165,6 +180,35 @@ export function resolveLinkRoundTripMs(linkRoundTripMs) {
|
|
|
165
180
|
export function relayedDialBudgetMs(linkRoundTripMs) {
|
|
166
181
|
return RELAYED_DIAL_ROUND_TRIPS * resolveLinkRoundTripMs(linkRoundTripMs);
|
|
167
182
|
}
|
|
183
|
+
/**
|
|
184
|
+
* libp2p's two connection-manager limits for a node at the declared link, handed to
|
|
185
|
+
* `@optimystic/db-p2p`'s `NodeOptions.connectionManager` on the control node and every strand
|
|
186
|
+
* node.
|
|
187
|
+
*
|
|
188
|
+
* Both bound the same thing — opening a relayed connection, measured at 8 one-way link delays,
|
|
189
|
+
* which is {@link RELAYED_DIAL_ROUND_TRIPS} (4) link round trips — so both are
|
|
190
|
+
* {@link relayedDialBudgetMs}: 4 x 3 500 = 14 000 ms at the default declaration, covering the
|
|
191
|
+
* 12 094 ms measured at the supported 3-second link.
|
|
192
|
+
*
|
|
193
|
+
* The listener's limit is deliberately NOT smaller than the dialer's. The listener's clock
|
|
194
|
+
* starts only when the relay hands it the circuit, a few one-way delays after the dialer's
|
|
195
|
+
* started, and both sides finish the handshakes at about the same moment; so with equal limits
|
|
196
|
+
* the listener never discards a connection that the dialer's own dial would still accept. A
|
|
197
|
+
* listener limit below the dialer's is what produced the silent failure in the module doc.
|
|
198
|
+
*
|
|
199
|
+
* The cost of a longer `inboundUpgradeTimeout` is that a peer which opens a connection and then
|
|
200
|
+
* stalls its handshake holds that half-built connection 14 s instead of 10 s.
|
|
201
|
+
*
|
|
202
|
+
* NOTE: derived from the declaration alone, so a per-field override that raises a cadre dial
|
|
203
|
+
* budget above it (`controlCohort.perAddressDialTimeoutMs`, `strandBackfill.dialTimeoutMs`)
|
|
204
|
+
* does not raise these; a dial that outlasts the listener's limit gets the silent failure
|
|
205
|
+
* again. If such overrides start being used for slow links, raise the declaration instead or
|
|
206
|
+
* take the largest configured dial budget here.
|
|
207
|
+
*/
|
|
208
|
+
export function connectionManagerTimeouts(linkRoundTripMs) {
|
|
209
|
+
const budgetMs = relayedDialBudgetMs(linkRoundTripMs);
|
|
210
|
+
return { dialTimeout: budgetMs, inboundUpgradeTimeout: budgetMs };
|
|
211
|
+
}
|
|
168
212
|
/**
|
|
169
213
|
* Deadline for one whole relay reservation drive: {@link RELAY_RESERVATION_ROUND_TRIPS} at the
|
|
170
214
|
* declared link round trip.
|
package/dist/link-budget.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link-budget.js","sourceRoot":"","sources":["../src/link-budget.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"link-budget.js","sourceRoot":"","sources":["../src/link-budget.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkFG;AAIH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,IAAI,CAAC;AAEhD;;;;GAIG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAE1C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC;AAE/C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,CAAC;AAE7C;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,IAAI,CAAC;AAE/C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,sBAAsB,CAAC,eAAwB;IAC9D,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;QACnC,OAAO,2BAA2B,CAAC;IACpC,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,eAAe,IAAI,CAAC,EAAE,CAAC;QAC/D,MAAM,IAAI,KAAK,CACd,mFAAmF,MAAM,CAAC,eAAe,CAAC,EAAE,CAC5G,CAAC;IACH,CAAC;IACD,OAAO,eAAe,CAAC;AACxB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,eAAwB;IAC3D,OAAO,wBAAwB,GAAG,sBAAsB,CAAC,eAAe,CAAC,CAAC;AAC3E,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,yBAAyB,CAAC,eAAwB;IACjE,MAAM,QAAQ,GAAG,mBAAmB,CAAC,eAAe,CAAC,CAAC;IACtD,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,qBAAqB,EAAE,QAAQ,EAAE,CAAC;AACnE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CAAC,eAAwB;IAChE,OAAO,6BAA6B,GAAG,sBAAsB,CAAC,eAAe,CAAC,CAAC;AAChF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CACrC,eAAwB,EACxB,mBAAmB,GAAG,0BAA0B;IAEhD,OAAO,2BAA2B,GAAG,sBAAsB,CAAC,eAAe,CAAC,GAAG,mBAAmB,CAAC;AACpG,CAAC;AAUD;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,eAAwB;IAC1D,OAAO;QACN,aAAa,EAAE,mBAAmB,CAAC,eAAe,CAAC;QACnD,iBAAiB,EAAE,sBAAsB,CAAC,eAAe,CAAC;KAC1D,CAAC;AACH,CAAC"}
|
|
@@ -28,15 +28,16 @@ export interface DurableSlot {
|
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
30
|
* What one unusable entry means for its siblings — the single intentional
|
|
31
|
-
* difference between the
|
|
31
|
+
* difference between the records:
|
|
32
32
|
*
|
|
33
33
|
* - `'discard-all'` (the trusted-owner anchor): a record that cannot be read
|
|
34
34
|
* in full is not an anchor. Trusting a *subset* of the keys a file claims is
|
|
35
35
|
* a silent, security-relevant downgrade, so the whole record is discarded
|
|
36
36
|
* and the node trusts no one until re-seeded out of band.
|
|
37
|
-
* - `'drop-entry'` (the bootstrap-peer store
|
|
38
|
-
*
|
|
39
|
-
* discard a stranded node's only remaining way back
|
|
37
|
+
* - `'drop-entry'` (the bootstrap-peer store and the strand peer book): the
|
|
38
|
+
* record is a best-effort dial list and nothing in it is trust-bearing, so one
|
|
39
|
+
* junk entry must not discard a stranded node's only remaining way back to
|
|
40
|
+
* its party or its strand's peers.
|
|
40
41
|
*/
|
|
41
42
|
export type UnusableEntryPolicy = 'discard-all' | 'drop-entry';
|
|
42
43
|
/** What a particular node-local record persists, and how it validates it. */
|
|
@@ -4,15 +4,18 @@
|
|
|
4
4
|
* from shared group state:
|
|
5
5
|
*
|
|
6
6
|
* - the trusted-owner anchor (`trusted-owner-store.ts`),
|
|
7
|
-
* - the cold-start bootstrap-peer store (`bootstrap-peer-store.ts`)
|
|
7
|
+
* - the cold-start bootstrap-peer store (`bootstrap-peer-store.ts`),
|
|
8
|
+
* - the strand peer book (`strand-peer-book.ts`), whose entries are one map per
|
|
9
|
+
* strand rather than one value per key — the validation hook below is what
|
|
10
|
+
* lets it drop a single junk peer without dropping the strand.
|
|
8
11
|
*
|
|
9
|
-
*
|
|
12
|
+
* ANOTHER node-local record — the enrolled-machine count
|
|
10
13
|
* (`enrolled-machine-store.ts`) — reuses {@link DurableSlot} but deliberately
|
|
11
14
|
* NOT this module's snapshot machinery: it is one scalar rather than an entry
|
|
12
15
|
* map, and it must cold-start rather than throw on an unreadable slot. Its
|
|
13
16
|
* module comment carries the reasoning; do not fold it in here.
|
|
14
17
|
*
|
|
15
|
-
*
|
|
18
|
+
* Every record here is the same mechanism with a different payload: a
|
|
16
19
|
* `{ version, partyId, <entries> }` envelope, snapshot-written whole on every
|
|
17
20
|
* change, loaded under one fail-safe-but-not-fail-silent policy. The only part
|
|
18
21
|
* that differs per platform is WHERE the bytes are kept — Node writes a file,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-local-snapshot.js","sourceRoot":"","sources":["../src/node-local-snapshot.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"node-local-snapshot.js","sourceRoot":"","sources":["../src/node-local-snapshot.ts"],"names":[],"mappings":"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"}
|
package/dist/peer-dial.d.ts
CHANGED
|
@@ -26,8 +26,8 @@ import type { Connection } from '@libp2p/interface';
|
|
|
26
26
|
import type { Multiaddr } from '@multiformats/multiaddr';
|
|
27
27
|
/**
|
|
28
28
|
* Default limit on ONE address's dial attempt, in ms, at the DEFAULT declared link round trip:
|
|
29
|
-
* `RELAYED_DIAL_ROUND_TRIPS` (4) x `DECLARED_LINK_ROUND_TRIP_MS` (
|
|
30
|
-
*
|
|
29
|
+
* `RELAYED_DIAL_ROUND_TRIPS` (4) x `DECLARED_LINK_ROUND_TRIP_MS` (3500 ms) = 14 000 ms. It was
|
|
30
|
+
* a fixed 8000 ms before it was derived.
|
|
31
31
|
*
|
|
32
32
|
* It has to cover the slowest address that should succeed, because an attempt
|
|
33
33
|
* that needs longer fails the same way on every retry. That is a relayed dial on
|
|
@@ -35,7 +35,7 @@ import type { Multiaddr } from '@multiformats/multiaddr';
|
|
|
35
35
|
* handshakes, when no relay connection is open yet), open the circuit, then run
|
|
36
36
|
* both handshakes again end to end through the relay. `link-budget.ts` is where that
|
|
37
37
|
* reasoning is now a measured count instead of an estimate — four link round trips, measured at
|
|
38
|
-
*
|
|
38
|
+
* 12 094 ms on a link whose round trip is 3 s — so the value MOVES with a host's
|
|
39
39
|
* `NetworkConfig.linkRoundTripMs` rather than pinning the band this node can reach to whatever
|
|
40
40
|
* number was typed here. A direct dial that works is far quicker — a phone's WebSocket dial to
|
|
41
41
|
* a node forwarded over `adb reverse` measured 1.6 s end to end.
|
package/dist/peer-dial.js
CHANGED
|
@@ -28,8 +28,8 @@ import { relayedDialBudgetMs } from './link-budget.js';
|
|
|
28
28
|
const log = debug('sereus:cadre:peer-dial');
|
|
29
29
|
/**
|
|
30
30
|
* Default limit on ONE address's dial attempt, in ms, at the DEFAULT declared link round trip:
|
|
31
|
-
* `RELAYED_DIAL_ROUND_TRIPS` (4) x `DECLARED_LINK_ROUND_TRIP_MS` (
|
|
32
|
-
*
|
|
31
|
+
* `RELAYED_DIAL_ROUND_TRIPS` (4) x `DECLARED_LINK_ROUND_TRIP_MS` (3500 ms) = 14 000 ms. It was
|
|
32
|
+
* a fixed 8000 ms before it was derived.
|
|
33
33
|
*
|
|
34
34
|
* It has to cover the slowest address that should succeed, because an attempt
|
|
35
35
|
* that needs longer fails the same way on every retry. That is a relayed dial on
|
|
@@ -37,7 +37,7 @@ const log = debug('sereus:cadre:peer-dial');
|
|
|
37
37
|
* handshakes, when no relay connection is open yet), open the circuit, then run
|
|
38
38
|
* both handshakes again end to end through the relay. `link-budget.ts` is where that
|
|
39
39
|
* reasoning is now a measured count instead of an estimate — four link round trips, measured at
|
|
40
|
-
*
|
|
40
|
+
* 12 094 ms on a link whose round trip is 3 s — so the value MOVES with a host's
|
|
41
41
|
* `NetworkConfig.linkRoundTripMs` rather than pinning the band this node can reach to whatever
|
|
42
42
|
* number was typed here. A direct dial that works is far quicker — a phone's WebSocket dial to
|
|
43
43
|
* a node forwarded over `adb reverse` measured 1.6 s end to end.
|
|
@@ -8,6 +8,15 @@ import { BlockTransferClient, type IRawStorage } from '@optimystic/db-p2p';
|
|
|
8
8
|
* changes it or starts exporting it.
|
|
9
9
|
*/
|
|
10
10
|
export declare const MAX_BLOCK_MESSAGE_BYTES: number;
|
|
11
|
+
/**
|
|
12
|
+
* Whether an identified peer's protocol list names this network's own block-transfer
|
|
13
|
+
* protocol — the one gate that decides whether {@link PeerJoinBackfill} schedules a peer at
|
|
14
|
+
* all. A peer that lacks it (a bare circuit relay, a bootstrap node, a stranger the control
|
|
15
|
+
* network's inbound gate admitted without membership) cannot receive a push no matter how
|
|
16
|
+
* long it is dialed, since the protocol id is namespaced per network. Exported because a
|
|
17
|
+
* later strand peer-address ticket's identify-driven observation needs the identical test.
|
|
18
|
+
*/
|
|
19
|
+
export declare function speaksBlockTransfer(protocols: readonly string[], protocolPrefix: string): boolean;
|
|
11
20
|
/**
|
|
12
21
|
* Consecutive failed catch-up runs against ONE peer before the module says so on
|
|
13
22
|
* `console.warn` rather than only in its DEBUG log. At the default backoff that is reached
|
|
@@ -29,7 +38,7 @@ export interface PeerJoinBackfillConfig {
|
|
|
29
38
|
maxChunkBlocks?: number;
|
|
30
39
|
/**
|
|
31
40
|
* Per-push dial deadline, ms. Default {@link peerJoinPushBudget}'s `dialTimeoutMs` — four link
|
|
32
|
-
* round trips at the declared link,
|
|
41
|
+
* round trips at the declared link, 14 000 ms as shipped. NOT a fixed number: a relayed dial
|
|
33
42
|
* costs a fixed number of exchanges, so a host on a slower link moves this (and every other
|
|
34
43
|
* cadre dial budget) by declaring `NetworkConfig.linkRoundTripMs`. Naming it here still wins
|
|
35
44
|
* over the derived value — `link-budget.ts` has the counts and the measurement.
|
|
@@ -38,7 +47,7 @@ export interface PeerJoinBackfillConfig {
|
|
|
38
47
|
/**
|
|
39
48
|
* Per-push response deadline, ms. Default {@link peerJoinPushBudget}'s `responseTimeoutMs` —
|
|
40
49
|
* two link round trips at the declared link plus a transfer allowance for the chunk's own
|
|
41
|
-
* bytes,
|
|
50
|
+
* bytes, 13 000 ms as shipped. Derived differently from {@link dialTimeoutMs} because it
|
|
42
51
|
* bounds a data transfer over a connection that is already open, not a dial.
|
|
43
52
|
*/
|
|
44
53
|
responseTimeoutMs?: number;
|
|
@@ -109,7 +118,7 @@ export interface PeerJoinBackfillResult {
|
|
|
109
118
|
* Best-effort throughout: nothing here throws into a libp2p event handler or into a
|
|
110
119
|
* runtime bring-up; a failed chunk is logged and the run continues. A peer is marked
|
|
111
120
|
* fully caught up ONLY after a run with no thrown chunk and an empty `missing` list, so
|
|
112
|
-
* the next `
|
|
121
|
+
* the next `peer:identify` from a peer whose catch-up failed retries it.
|
|
113
122
|
*/
|
|
114
123
|
export declare class PeerJoinBackfill {
|
|
115
124
|
private readonly deps;
|
|
@@ -136,30 +145,40 @@ export declare class PeerJoinBackfill {
|
|
|
136
145
|
private readonly failures;
|
|
137
146
|
/**
|
|
138
147
|
* Epoch ms before which a peer's catch-up must not be re-run, set alongside a backoff timer
|
|
139
|
-
* that will run it. Its presence is what makes `
|
|
148
|
+
* that will run it. Its presence is what makes `peer:identify` churn free: a schedule
|
|
140
149
|
* arriving inside the wait is dropped, rather than collapsing the backoff to the debounce.
|
|
141
150
|
*/
|
|
142
151
|
private readonly retryAfter;
|
|
143
152
|
/** Peers already reported on `console.warn`; reset when a run finally lands cleanly. */
|
|
144
153
|
private readonly warned;
|
|
145
|
-
private readonly
|
|
154
|
+
private readonly onPeerIdentify;
|
|
146
155
|
private loggedNoListBlockIds;
|
|
147
156
|
constructor(deps: PeerJoinBackfillDeps, config?: PeerJoinBackfillConfig);
|
|
148
|
-
/**
|
|
157
|
+
/**
|
|
158
|
+
* Subscribe to `peer:identify` AND schedule a catch-up for already-connected peers whose
|
|
159
|
+
* stored protocols already name this network's block-transfer protocol — a peer that does
|
|
160
|
+
* not speak it (a bare circuit relay, a bootstrap node) is never scheduled at all. See
|
|
161
|
+
* {@link speaksBlockTransfer} and the module comment.
|
|
162
|
+
*/
|
|
149
163
|
start(): void;
|
|
150
164
|
/** Unsubscribe, clear timers; in-flight runs observe the stopped flag and bail. */
|
|
151
165
|
stop(): void;
|
|
152
166
|
/**
|
|
153
|
-
* (Re-)schedule a debounced catch-up for every currently-connected peer
|
|
154
|
-
*
|
|
155
|
-
* peer
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
167
|
+
* (Re-)schedule a debounced catch-up for every currently-connected peer whose protocols, as
|
|
168
|
+
* already stored in the libp2p peer store, name this network's block-transfer protocol. A
|
|
169
|
+
* peer not yet in the peer store — its identify has not finished — is left to the
|
|
170
|
+
* `peer:identify` handler rather than dialed blind; one whose stored protocols are known
|
|
171
|
+
* and lack ours is skipped outright. Idempotent and cheap otherwise (caught-up peers are
|
|
172
|
+
* skipped before any timer is set, and a peer whose run is in flight is deferred to the end
|
|
173
|
+
* of that run rather than dropped). Driven by {@link start}, and — on a gated network — by
|
|
174
|
+
* the embedder whenever membership changes, so a peer whose first pass was denied (connected
|
|
175
|
+
* before it was authorized: the production join order) is retried without waiting for a
|
|
176
|
+
* reconnect. Returns how many distinct peers were considered (for the start() log) — a peer
|
|
177
|
+
* holding several connections is one peer, and is scheduled once.
|
|
161
178
|
*/
|
|
162
|
-
scheduleConnectedPeers(): number
|
|
179
|
+
scheduleConnectedPeers(): Promise<number>;
|
|
180
|
+
/** Schedules `peerId` only if the peer store already knows it speaks this network's protocol. */
|
|
181
|
+
private scheduleIfKnownToSpeak;
|
|
163
182
|
/** Debounced entry point for connection churn: one run per peer per settle window. */
|
|
164
183
|
private schedulePeer;
|
|
165
184
|
/**
|
|
@@ -173,7 +192,7 @@ export declare class PeerJoinBackfill {
|
|
|
173
192
|
/**
|
|
174
193
|
* Re-arm one peer's catch-up after a run whose push failed, on a wait that doubles
|
|
175
194
|
* per consecutive failure up to `maxRetryBackoffMs`. Sets {@link retryAfter} alongside the
|
|
176
|
-
* timer, which is what makes `
|
|
195
|
+
* timer, which is what makes `peer:identify` churn inside the wait free.
|
|
177
196
|
*/
|
|
178
197
|
private scheduleRetryWithBackoff;
|
|
179
198
|
/**
|