@serfab/cadre-core 1.13.0 → 1.15.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 +293 -274
- package/dist/cadre-invite-protocol.d.ts +383 -0
- package/dist/cadre-invite-protocol.js +774 -0
- package/dist/cadre-invite-protocol.js.map +1 -0
- package/dist/cadre-join-request.d.ts +42 -0
- package/dist/cadre-join-request.js +144 -0
- package/dist/cadre-join-request.js.map +1 -0
- package/dist/cadre-node.d.ts +849 -210
- package/dist/cadre-node.js +1574 -374
- package/dist/cadre-node.js.map +1 -1
- package/dist/claim-proof.d.ts +45 -0
- package/dist/claim-proof.js +132 -0
- package/dist/claim-proof.js.map +1 -0
- package/dist/control-authorization.d.ts +80 -19
- package/dist/control-authorization.js +55 -13
- package/dist/control-authorization.js.map +1 -1
- package/dist/control-cohort.js +1 -1
- package/dist/control-cohort.js.map +1 -1
- package/dist/control-database.d.ts +605 -108
- package/dist/control-database.js +1299 -280
- package/dist/control-database.js.map +1 -1
- package/dist/control-protocol-guard.d.ts +142 -0
- package/dist/control-protocol-guard.js +293 -0
- package/dist/control-protocol-guard.js.map +1 -0
- package/dist/control-schema.d.ts +1 -1
- package/dist/control-schema.js +817 -1067
- package/dist/control-schema.js.map +1 -1
- package/dist/control-stream.d.ts +4 -0
- package/dist/control-stream.js +22 -7
- package/dist/control-stream.js.map +1 -1
- package/dist/delegate-admission.d.ts +1 -1
- package/dist/delegate-admission.js +1 -1
- package/dist/device-token.d.ts +11 -9
- package/dist/device-token.js +14 -12
- package/dist/device-token.js.map +1 -1
- package/dist/ed25519-key.d.ts +22 -9
- package/dist/ed25519-key.js +47 -10
- package/dist/ed25519-key.js.map +1 -1
- package/dist/fetch-impl.d.ts +12 -0
- package/dist/fetch-impl.js +23 -0
- package/dist/fetch-impl.js.map +1 -0
- package/dist/file-durable-slot.js +2 -1
- package/dist/file-durable-slot.js.map +1 -1
- package/dist/file-safe-name.d.ts +25 -0
- package/dist/file-safe-name.js +29 -0
- package/dist/file-safe-name.js.map +1 -0
- package/dist/formation-approval.js +5 -11
- package/dist/formation-approval.js.map +1 -1
- package/dist/fs-atomic.d.ts +0 -19
- package/dist/fs-atomic.js +3 -24
- package/dist/fs-atomic.js.map +1 -1
- package/dist/index.d.ts +22 -10
- package/dist/index.js +54 -11
- package/dist/index.js.map +1 -1
- package/dist/invitation-bootstrap.d.ts +50 -12
- package/dist/invitation-bootstrap.js +76 -13
- package/dist/invitation-bootstrap.js.map +1 -1
- package/dist/joined-strand-store.d.ts +7 -0
- package/dist/joined-strand-store.js +9 -0
- package/dist/joined-strand-store.js.map +1 -1
- package/dist/key-store-file.js +2 -1
- package/dist/key-store-file.js.map +1 -1
- package/dist/link-budget.d.ts +25 -33
- package/dist/link-budget.js +25 -35
- package/dist/link-budget.js.map +1 -1
- package/dist/machine-removal.d.ts +78 -0
- package/dist/machine-removal.js +166 -0
- package/dist/machine-removal.js.map +1 -0
- package/dist/membership-connection-gater.d.ts +191 -151
- package/dist/membership-connection-gater.js +236 -173
- package/dist/membership-connection-gater.js.map +1 -1
- package/dist/node-claim-payload.d.ts +74 -0
- package/dist/node-claim-payload.js +224 -0
- package/dist/node-claim-payload.js.map +1 -0
- package/dist/node-default-transports.d.ts +27 -0
- package/dist/node-default-transports.js +35 -0
- package/dist/node-default-transports.js.map +1 -0
- package/dist/node-transports.d.ts +30 -0
- package/dist/node-transports.js +40 -0
- package/dist/node-transports.js.map +1 -0
- package/dist/owner-anchor-sync.d.ts +22 -0
- package/dist/owner-anchor-sync.js +143 -0
- package/dist/owner-anchor-sync.js.map +1 -0
- package/dist/peer-authorization.d.ts +113 -18
- package/dist/peer-authorization.js +225 -29
- package/dist/peer-authorization.js.map +1 -1
- package/dist/peer-dial.d.ts +143 -27
- package/dist/peer-dial.js +276 -31
- package/dist/peer-dial.js.map +1 -1
- package/dist/peer-join-backfill.d.ts +26 -2
- package/dist/peer-join-backfill.js +60 -12
- package/dist/peer-join-backfill.js.map +1 -1
- package/dist/peer-record.d.ts +17 -52
- package/dist/peer-record.js +20 -58
- package/dist/peer-record.js.map +1 -1
- package/dist/pending-join-runner.d.ts +66 -58
- package/dist/pending-join-runner.js +136 -145
- package/dist/pending-join-runner.js.map +1 -1
- package/dist/primary-lan-address.d.ts +8 -0
- package/dist/primary-lan-address.js +46 -0
- package/dist/primary-lan-address.js.map +1 -0
- package/dist/provider/client.d.ts +131 -0
- package/dist/provider/client.js +226 -0
- package/dist/provider/client.js.map +1 -0
- package/dist/provider/descriptor.d.ts +41 -0
- package/dist/provider/descriptor.js +103 -0
- package/dist/provider/descriptor.js.map +1 -0
- package/dist/provider/index.d.ts +9 -0
- package/dist/provider/index.js +10 -0
- package/dist/provider/index.js.map +1 -0
- package/dist/provider/oauth.d.ts +125 -0
- package/dist/provider/oauth.js +199 -0
- package/dist/provider/oauth.js.map +1 -0
- package/dist/provider/rent-node.d.ts +101 -0
- package/dist/provider/rent-node.js +220 -0
- package/dist/provider/rent-node.js.map +1 -0
- package/dist/push-fanout.d.ts +8 -2
- package/dist/push-fanout.js +8 -2
- package/dist/push-fanout.js.map +1 -1
- package/dist/relay-addrs.d.ts +9 -4
- package/dist/relay-addrs.js +9 -4
- package/dist/relay-addrs.js.map +1 -1
- package/dist/relay-reservation.d.ts +51 -16
- package/dist/relay-reservation.js +107 -24
- package/dist/relay-reservation.js.map +1 -1
- package/dist/seed-bootstrap.d.ts +165 -123
- package/dist/seed-bootstrap.js +313 -275
- package/dist/seed-bootstrap.js.map +1 -1
- package/dist/seed-trust-policy.d.ts +98 -37
- package/dist/seed-trust-policy.js +188 -2
- package/dist/seed-trust-policy.js.map +1 -1
- package/dist/strand-addr-protocol.d.ts +24 -26
- package/dist/strand-addr-protocol.js +19 -26
- package/dist/strand-addr-protocol.js.map +1 -1
- package/dist/strand-commit-durability.d.ts +54 -0
- package/dist/strand-commit-durability.js +74 -0
- package/dist/strand-commit-durability.js.map +1 -0
- package/dist/strand-database.d.ts +23 -8
- package/dist/strand-database.js +41 -13
- package/dist/strand-database.js.map +1 -1
- package/dist/strand-first-sync-gate.d.ts +7 -1
- package/dist/strand-first-sync-gate.js +7 -1
- package/dist/strand-first-sync-gate.js.map +1 -1
- package/dist/strand-formation-protocol.js +5 -2
- package/dist/strand-formation-protocol.js.map +1 -1
- package/dist/strand-fret-addrs.d.ts +19 -1
- package/dist/strand-fret-addrs.js +27 -9
- package/dist/strand-fret-addrs.js.map +1 -1
- package/dist/strand-instance-manager.d.ts +81 -19
- package/dist/strand-instance-manager.js +216 -105
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-move.d.ts +124 -0
- package/dist/strand-move.js +438 -0
- package/dist/strand-move.js.map +1 -0
- package/dist/strand-network-config.js +7 -6
- package/dist/strand-network-config.js.map +1 -1
- package/dist/strand-peer-redial.d.ts +113 -0
- package/dist/strand-peer-redial.js +236 -0
- package/dist/strand-peer-redial.js.map +1 -0
- package/dist/strand-revocation-enforcer.d.ts +11 -11
- package/dist/strand-revocation-enforcer.js +11 -11
- package/dist/strand-wake-protocol.d.ts +13 -16
- package/dist/strand-wake-protocol.js +23 -27
- package/dist/strand-wake-protocol.js.map +1 -1
- package/dist/trusted-owner-store.d.ts +35 -5
- package/dist/trusted-owner-store.js +50 -8
- package/dist/trusted-owner-store.js.map +1 -1
- package/dist/types.d.ts +512 -89
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -1
- package/package.json +19 -10
- package/src/cadre-invite-protocol.ts +1052 -0
- package/src/cadre-join-request.ts +167 -0
- package/src/cadre-node.ts +1703 -386
- package/src/claim-proof.ts +147 -0
- package/src/control-authorization.ts +203 -117
- package/src/control-cohort.ts +1 -1
- package/src/control-database.ts +4663 -3453
- package/src/control-protocol-guard.ts +348 -0
- package/src/control-schema.ts +828 -1078
- package/src/control-stream.ts +26 -7
- package/src/delegate-admission.ts +1 -1
- package/src/device-token.ts +14 -10
- package/src/ed25519-key.ts +47 -10
- package/src/fetch-impl.ts +23 -0
- package/src/file-durable-slot.ts +64 -63
- package/src/file-safe-name.ts +32 -0
- package/src/formation-approval.ts +604 -610
- package/src/fs-atomic.ts +92 -117
- package/src/index.ts +789 -648
- package/src/invitation-bootstrap.ts +91 -13
- package/src/joined-strand-store.ts +508 -498
- package/src/key-store-file.ts +142 -141
- package/src/link-budget.ts +25 -36
- package/src/machine-removal.ts +216 -0
- package/src/membership-connection-gater.ts +259 -191
- package/src/node-claim-payload.ts +259 -0
- package/src/node-default-transports.ts +38 -0
- package/src/node-transports.ts +49 -0
- package/src/owner-anchor-sync.ts +171 -0
- package/src/peer-authorization.ts +258 -29
- package/src/peer-dial.ts +604 -315
- package/src/peer-join-backfill.ts +62 -11
- package/src/peer-record.ts +159 -197
- package/src/pending-join-runner.ts +729 -735
- package/src/primary-lan-address.ts +47 -0
- package/src/provider/client.ts +326 -0
- package/src/provider/descriptor.ts +129 -0
- package/src/provider/index.ts +59 -0
- package/src/provider/oauth.ts +285 -0
- package/src/provider/rent-node.ts +275 -0
- package/src/push-fanout.ts +8 -2
- package/src/relay-addrs.ts +9 -4
- package/src/relay-reservation.ts +1211 -1121
- package/src/seed-bootstrap.ts +1502 -1448
- package/src/seed-trust-policy.ts +353 -140
- package/src/strand-addr-protocol.ts +26 -35
- package/src/strand-commit-durability.ts +116 -0
- package/src/strand-database.ts +46 -14
- package/src/strand-first-sync-gate.ts +7 -1
- package/src/strand-formation-protocol.ts +1039 -1036
- package/src/strand-fret-addrs.ts +179 -145
- package/src/strand-instance-manager.ts +2026 -1883
- package/src/strand-move.ts +585 -0
- package/src/strand-network-config.ts +7 -6
- package/src/strand-peer-redial.ts +307 -0
- package/src/strand-revocation-enforcer.ts +11 -11
- package/src/strand-wake-protocol.ts +23 -30
- package/src/trusted-owner-store.ts +242 -171
- package/src/types.ts +2687 -2242
|
@@ -1,121 +1,160 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Control-network inbound admission gates
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
2
|
+
* Control-network inbound admission gates: the encrypted-connection checkpoint
|
|
3
|
+
* and the circuit-relay reservation checkpoint.
|
|
4
|
+
*
|
|
5
|
+
* The fail-closed layer of the membership enforcement chain is per-stream: the
|
|
6
|
+
* control node's protocol guard (`control-protocol-guard.ts`) refuses a peer that
|
|
7
|
+
* is not an authorized member on every protocol not declared open to strangers,
|
|
8
|
+
* before its handler runs, and the replicated rows an outsider *can* still write
|
|
9
|
+
* are disbelieved at read time. This module is NOT a stranger boundary on an
|
|
10
|
+
* enrolled node — outside the bring-up quiet period it admits every inbound
|
|
11
|
+
* connection. Its jobs are:
|
|
12
|
+
*
|
|
13
|
+
* - the bring-up quiet period (below), the one state in which it denies;
|
|
14
|
+
* - deciding which admitted peers carry a deadline: a peer the policy cannot
|
|
15
|
+
* place is admitted PROVISIONALLY, and its connection is closed at the
|
|
16
|
+
* deadline unless the policy admits it by then (see "Provisional admission");
|
|
17
|
+
* - handing circuit-relay reservations to the reservation policy (see "The
|
|
18
|
+
* relay-reservation seam").
|
|
19
|
+
*
|
|
20
|
+
* Why a stranger's connection is admitted at all: the gate sees only a peer id,
|
|
21
|
+
* after the encrypted handshake and before any protocol, so it cannot tell an
|
|
22
|
+
* outsider from a device carrying a cadre invitation this node has not received
|
|
23
|
+
* yet, or from a sibling whose membership row is still replicating. Refusing
|
|
24
|
+
* would fail those at the connection; admitting costs a mute connection for a
|
|
25
|
+
* bounded time, because the protocol guard refuses it every members-only protocol.
|
|
26
|
+
*
|
|
27
|
+
* ## Admitted outright
|
|
28
|
+
*
|
|
29
|
+
* A peer the policy CAN place gets no deadline. Besides members, configured
|
|
30
|
+
* infrastructure and an un-enrolled node's whole world (empty anchor or empty
|
|
31
|
+
* authorized set), that covers the stranger windows: states in which this node
|
|
32
|
+
* expects a stranger on one of the `stranger-open` protocols declared in
|
|
33
|
+
* `controlProtocolClasses` (`control-protocol-guard.ts`):
|
|
34
|
+
*
|
|
35
|
+
* - `/sereus/seed/1.0.0` — enrollment seed delivery.
|
|
27
36
|
* An owner dials a brand-new node to seed it (the new node has no members
|
|
28
|
-
* yet, so
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
37
|
+
* yet, so it admits everyone outright). The handler's own trust decision is the
|
|
38
|
+
* anchored seed-trust policy — or, on a node started with a claim secret
|
|
39
|
+
* (`CadreNodeConfig.claim`), the claim-secret policy. Such a node is the one
|
|
40
|
+
* stranger-facing state that is NOT "admit the connection and let the
|
|
41
|
+
* per-stream gates sort it out": while it waits to be claimed
|
|
42
|
+
* (`CadreNode.isAwaitingClaim`) its connection is admitted, because the claim
|
|
43
|
+
* seed has to ride one, but its control-DB streams and relay reservations are
|
|
44
|
+
* refused ahead of every admission below, the empty-anchor one included. An
|
|
45
|
+
* unclaimed node has no siblings to replicate from, and one on a public
|
|
46
|
+
* address must not relay for anyone. The claim anchors the owner, after which
|
|
47
|
+
* the ordinary rules apply.
|
|
48
|
+
* - `/sereus/formation/1.0.0` — cross-party
|
|
32
49
|
* strand formation via open invitations. Stranger-facing BY DESIGN: the
|
|
33
50
|
* initiator is another party, and its token is only checkable inside the
|
|
34
|
-
* protocol. The
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
51
|
+
* protocol. The window is keyed on EXPECTATION of a stranger, not capability
|
|
52
|
+
* to serve one: it is open only while this node has at least one UNEXPIRED,
|
|
53
|
+
* NOT-FULLY-CONSUMED open invitation outstanding
|
|
54
|
+
* (`StrandSolicitationService.hasOutstandingInvitation` — the tokens this
|
|
55
|
+
* process minted or published, plus any still-redeemable `FormationInvite`
|
|
56
|
+
* row the usage recorder can see). Registering the responder does NOT open
|
|
57
|
+
* it, so on every node — each registers one at `CadreNode.start` — a stranger
|
|
58
|
+
* with no invitation in play stays on the provisional deadline. The
|
|
42
59
|
* handler's own trust decision remains the per-token check, which is
|
|
43
60
|
* strictly finer than this one: a peer admitted here can still be rejected
|
|
44
61
|
* in-protocol for a bogus or spent token.
|
|
62
|
+
* - `/sereus/cadre-invite/1.0.0` — redemption
|
|
63
|
+
* of a cadre invitation at any member machine. Stranger-facing BY DESIGN:
|
|
64
|
+
* the device is not a member until the redemption writes its row, and its
|
|
65
|
+
* proof of possession (a signature with the invitation's private key) is
|
|
66
|
+
* only checkable inside the protocol. Keyed on expectation, as formation's
|
|
67
|
+
* is: open only while this node holds at least one LIVE `CadreInvite` row
|
|
68
|
+
* (`ControlDatabase.hasLiveCadreInvite`: not withdrawn, unexpired, uses left,
|
|
69
|
+
* issuer still an owner). A member that has not yet received the device's
|
|
70
|
+
* row by replication admits the device provisionally instead, seats the row
|
|
71
|
+
* from the invitation bundle during the redemption, and so admits it at the
|
|
72
|
+
* deadline's re-check.
|
|
45
73
|
*
|
|
46
74
|
* There is one further connection-level carve-out, which is NOT a protocol
|
|
47
|
-
*
|
|
75
|
+
* window:
|
|
48
76
|
*
|
|
49
77
|
* - **Announced delegate peers** (`delegate-admission.ts`). A member's strand
|
|
50
78
|
* node runs as a separate libp2p identity whose peerId no sibling can
|
|
51
79
|
* recompute. Before starting a strand node, a member's control node
|
|
52
80
|
* announces that peerId over the already-authenticated strand-addr RPC, and
|
|
53
81
|
* the receiver holds a short-lived grant for it
|
|
54
|
-
* (`CadreNode.grantDelegateAdmission`). The grant admits the CONNECTION
|
|
55
|
-
* admits the peer's RESERVATION at the seam below (without
|
|
56
|
-
* unauthorized budget), and nothing else — it is deliberately
|
|
57
|
-
* the
|
|
82
|
+
* (`CadreNode.grantDelegateAdmission`). The grant admits the CONNECTION
|
|
83
|
+
* outright, admits the peer's RESERVATION at the seam below (without
|
|
84
|
+
* spending the unauthorized budget), and nothing else — it is deliberately
|
|
85
|
+
* invisible to the protocol guard, so a delegate still gets refused on every
|
|
58
86
|
* members-only protocol.
|
|
59
87
|
*
|
|
88
|
+
* ## Provisional admission
|
|
89
|
+
*
|
|
90
|
+
* A peer the policy cannot place (`'admit-provisionally'`) gets its connection
|
|
91
|
+
* and a deadline — {@link PROVISIONAL_ADMISSION_DEADLINE_MS} at the default
|
|
92
|
+
* declaration; `CadreNode` passes the one derived from its OWN declared link,
|
|
93
|
+
* because the member is the machine that decides. At the deadline the gate asks
|
|
94
|
+
* the policy again:
|
|
95
|
+
*
|
|
96
|
+
* - `'admit'` — the peer has since become a member, holds a delegate grant, or
|
|
97
|
+
* this node now holds a live invitation (a redeeming device's row was
|
|
98
|
+
* seated): the connection stays, and nothing is re-armed;
|
|
99
|
+
* - `'admit-provisionally'` — the connection is closed (a bounded graceful
|
|
100
|
+
* close, with an abort only as the escalation);
|
|
101
|
+
* - the question throws or outlasts the decision deadline — the connection
|
|
102
|
+
* stays (see "Fail-open, deliberately").
|
|
103
|
+
*
|
|
104
|
+
* A connection that is already gone by then costs no question. One peer may hold
|
|
105
|
+
* several provisional connections; each deadline re-asks on its own.
|
|
106
|
+
*
|
|
107
|
+
* The gate does not decide which peers this node sends control writes to. A
|
|
108
|
+
* provisionally admitted stranger can open or advertise the party's protocols;
|
|
109
|
+
* what keeps it out of the control-database cohort is the control node's
|
|
110
|
+
* membership predicate (`CadreNode.isControlNetworkMember`, wired as Optimystic's
|
|
111
|
+
* `isNetworkMember`). FRET's ring still counts it: `docs/architecture.md` →
|
|
112
|
+
* "Per-stream protocol guard" → "What it does not cover".
|
|
113
|
+
*
|
|
60
114
|
* ## The relay-reservation seam
|
|
61
115
|
*
|
|
62
116
|
* A circuit-relay reservation is established by the reserving peer DIALING the
|
|
63
|
-
* relay, so at the relay it
|
|
117
|
+
* relay, so at the relay it rides an inbound connection — and closing that
|
|
64
118
|
* connection kills the reservation. For a genuine member whose `CadrePeer` row
|
|
65
|
-
* has not yet replicated to this node
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* relay
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* flight always finds a slot under any sane cap, while outsiders cannot
|
|
88
|
-
* annex the party's relay capacity. COUNT and lifetime are the only bounds
|
|
89
|
-
* on such a peer: a party-run relay forwards without libp2p's per-connection
|
|
90
|
-
* data and duration limit by default (`relay-server.ts`), so what a granted
|
|
91
|
-
* slot carries is not capped.
|
|
92
|
-
* - An `'admit-for-relay'` connection that is NOT reserving is dropped: it has
|
|
93
|
-
* {@link RELAY_ADMISSION_RESERVE_DEADLINE_MS} to get a reservation ADMITTED
|
|
94
|
-
* at that hook, after which the gate CLOSES the underlying connection so
|
|
95
|
-
* both ends let go of the socket. The guarantee above thus weakens on
|
|
96
|
-
* relay-enabled nodes from "never in the conversation" to "in it briefly,
|
|
97
|
-
* and can speak nothing".
|
|
119
|
+
* has not yet replicated to this node that would NOT be self-healing the way a
|
|
120
|
+
* data connection's close is: an outbound reconcile dial re-establishes a data
|
|
121
|
+
* link, but no outbound dial can grant the REMOTE peer a reservation, and a
|
|
122
|
+
* relay-only peer has no address of its own to dial back — the reservation IS
|
|
123
|
+
* its address. Boot ordering makes the window ordinary (a node reserves at the
|
|
124
|
+
* end of its own `start()`, before its row could have replicated anywhere), and
|
|
125
|
+
* a stalled replication makes it unbounded. So the reservation is decided on its
|
|
126
|
+
* own terms, not by the connection's:
|
|
127
|
+
*
|
|
128
|
+
* - It is decided at libp2p's `denyInboundRelayReservation` hook (the
|
|
129
|
+
* circuit-relay server consults it per RESERVE request): the policy admits
|
|
130
|
+
* members, delegates and configured infra outright, and admits peers it
|
|
131
|
+
* cannot place only within a bounded budget
|
|
132
|
+
* ({@link UnauthorizedReservationBudget}) — a member whose row is in flight
|
|
133
|
+
* always finds a slot under any sane cap, while outsiders cannot annex the
|
|
134
|
+
* party's relay capacity. COUNT and lifetime are the only bounds on such a
|
|
135
|
+
* peer: a party-run relay forwards without libp2p's per-connection data and
|
|
136
|
+
* duration limit by default (`relay-server.ts`), so what a granted slot
|
|
137
|
+
* carries is not capped.
|
|
138
|
+
* - An ADMITTED reservation disarms every provisional deadline the peer holds
|
|
139
|
+
* here, so its connection outlives the deadline even while the peer is still
|
|
140
|
+
* unplaced. A refused one disarms nothing.
|
|
98
141
|
*
|
|
99
142
|
* The deadline clears on reservation ADMISSION, not on the reservation's own
|
|
100
143
|
* success: this gate cannot observe the server-side `reserve()` outcome, so a
|
|
101
144
|
* peer whose admitted reservation is then refused for server capacity keeps its
|
|
102
145
|
* connection until either side closes it — bounded and mute, so harmless.
|
|
103
146
|
*
|
|
104
|
-
* Everything else a control node
|
|
105
|
-
* (
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
* gate is fail-open over a live DB read (deny only on positive proof of an
|
|
116
|
-
* outsider), the stream gate is fail-closed over the snapshot and has NO
|
|
117
|
-
* stranger carve-outs — an enrollment window admits a stranger's connection
|
|
118
|
-
* for seed delivery, yet its repo streams are still refused.
|
|
147
|
+
* Everything else a control node serves is either libp2p plumbing open to any
|
|
148
|
+
* connection (identify, ping, hole punching, AutoNAT, the relay protocols) or
|
|
149
|
+
* members-only — wake, strand-addr, the Optimystic control-DB protocols and FRET —
|
|
150
|
+
* and the fail-closed layer for all of it is the protocol guard
|
|
151
|
+
* (`control-protocol-guard.ts`), one seam that wraps every handler at dispatch,
|
|
152
|
+
* with a protocol nobody classed treated as members-only. The two layers
|
|
153
|
+
* complement, not duplicate: this connection gate is fail-open over a live DB
|
|
154
|
+
* read and decides only how long a connection lasts, the protocol guard is
|
|
155
|
+
* fail-closed and has NO stranger carve-outs — a live invitation admits a
|
|
156
|
+
* stranger's connection outright for redemption, yet its repo and FRET streams
|
|
157
|
+
* are still refused.
|
|
119
158
|
*
|
|
120
159
|
* ## The bring-up quiet period
|
|
121
160
|
*
|
|
@@ -151,62 +190,54 @@
|
|
|
151
190
|
*
|
|
152
191
|
* ## Fail-open, deliberately
|
|
153
192
|
*
|
|
154
|
-
* Outside that window this layer
|
|
155
|
-
*
|
|
156
|
-
* dependency, or ambiguous state admits the connection
|
|
157
|
-
*
|
|
158
|
-
*
|
|
193
|
+
* Outside that window this layer never denies, and it closes a provisional
|
|
194
|
+
* connection only on a positive answer that the peer is still unplaced. Any
|
|
195
|
+
* error, missing dependency, timeout or ambiguous state admits the connection
|
|
196
|
+
* outright (and the reservation), or keeps a provisional connection at its
|
|
197
|
+
* deadline, and defers to the fail-closed stream gates — a DB hiccup must not
|
|
198
|
+
* partition a legitimate cadre.
|
|
159
199
|
*/
|
|
160
200
|
import debug from 'debug';
|
|
161
|
-
import { SEED_PROTOCOL } from './seed-bootstrap.js';
|
|
162
|
-
import { FORMATION_PROTOCOL } from './strand-formation-protocol.js';
|
|
163
201
|
import { withDeadline } from './control-stream.js';
|
|
164
202
|
import { PARTY_RELAY_RESERVATION_TTL_MS } from './relay-server.js';
|
|
165
|
-
import { ADMISSION_DECISION_TIMEOUT_MS,
|
|
203
|
+
import { ADMISSION_DECISION_TIMEOUT_MS, relayedRequestBudgetMs } from './link-budget.js';
|
|
166
204
|
const log = debug('sereus:cadre:connection-gater');
|
|
167
205
|
/**
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
* does the same from inside its own `listen()`), so a connection idle past this
|
|
189
|
-
* deadline is not reserving.
|
|
190
|
-
*
|
|
191
|
-
* Derived from the link ({@link relayAdmissionReserveDeadlineMs}): one link round trip for the
|
|
192
|
-
* request to arrive plus one admission decision on it. This is the value at the default
|
|
193
|
-
* declaration; `CadreNode` passes the one derived from the relay's OWN declaration, because the
|
|
194
|
-
* relay is the machine that decides.
|
|
206
|
+
* How long a provisionally admitted connection lasts before the gate re-asks the
|
|
207
|
+
* policy and closes it unless the peer is admissible by then (see the module
|
|
208
|
+
* doc's "Provisional admission").
|
|
209
|
+
*
|
|
210
|
+
* {@link relayedRequestBudgetMs}: 28 500 ms at the default declaration. The
|
|
211
|
+
* longest exchange a stranger legitimately starts on a fresh connection is a
|
|
212
|
+
* cadre invitation redemption, and the device abandons each member address after
|
|
213
|
+
* that same budget of its own declared link (`redeemAtMembers`): it covers the
|
|
214
|
+
* dial, the request, the member's catch-up push, the seat and the redemption. So
|
|
215
|
+
* a member never cuts an exchange the device is still waiting on, and a
|
|
216
|
+
* reservation request lands well inside it. This is the value at the default
|
|
217
|
+
* declaration; `CadreNode` passes the one derived from its OWN declaration.
|
|
218
|
+
*
|
|
219
|
+
* NOTE: accepted tradeoff — any stranger can hold a mute connection to any
|
|
220
|
+
* enrolled member for this long, weighed against letting a device redeem an
|
|
221
|
+
* invitation at a member that has not yet received its row (maintainer,
|
|
222
|
+
* 2026-10-07, plan `cadre-invite-redeemable-before-the-row-replicates`). It can
|
|
223
|
+
* open only stranger-open and transport streams (the protocol guard), and
|
|
224
|
+
* libp2p's connection-manager limits bound how many it holds. Revisit if stranger
|
|
225
|
+
* connections show up as load on a member.
|
|
195
226
|
*/
|
|
196
|
-
export const
|
|
227
|
+
export const PROVISIONAL_ADMISSION_DEADLINE_MS = relayedRequestBudgetMs();
|
|
197
228
|
/**
|
|
198
|
-
* Bound on the graceful close of an expired
|
|
229
|
+
* Bound on the graceful close of an expired provisional connection. It exists
|
|
199
230
|
* because `AbstractMultiaddrConnection.close()` awaits an `idle`/`drain` event
|
|
200
231
|
* when the connection still has unsent bytes, and that wait has no timeout of
|
|
201
232
|
* its own — an unsignalled one never ends. This gate writes nothing to a
|
|
202
|
-
* stranger, so the wait is not reachable
|
|
233
|
+
* stranger, so the wait is not reachable from here; the bound is here so a timer
|
|
203
234
|
* callback can never hold an unending await.
|
|
204
235
|
*
|
|
205
236
|
* Applied through {@link withDeadline}, not `AbortSignal.timeout`: the latter is
|
|
206
237
|
* not reliably present on React Native/Hermes, which loads this same module.
|
|
207
238
|
*/
|
|
208
239
|
// eslint-disable-next-line no-restricted-syntax -- link-independent: bounds a local connection close inside a timer callback, and expiry aborts the connection instead
|
|
209
|
-
export const
|
|
240
|
+
export const PROVISIONAL_ADMISSION_CLOSE_TIMEOUT_MS = 2000;
|
|
210
241
|
/**
|
|
211
242
|
* Default cap on concurrent relay reservations held by peers the membership
|
|
212
243
|
* check could not place (see {@link UnauthorizedReservationBudget}). Small on
|
|
@@ -293,27 +324,30 @@ export class UnauthorizedReservationBudget {
|
|
|
293
324
|
* membership — this node decides for itself who to talk to.
|
|
294
325
|
*
|
|
295
326
|
* Composition semantics: every hook of `base` is preserved as-is; on the three
|
|
296
|
-
* composed hooks a deny from
|
|
297
|
-
* denies. A policy error — or a
|
|
298
|
-
* takes the fail-open outcome
|
|
299
|
-
*
|
|
327
|
+
* composed hooks a deny from the base gater denies, and so does the quiet
|
|
328
|
+
* period. The admission policy never denies a connection. A policy error — or a
|
|
329
|
+
* decision slower than `decisionTimeoutMs` — takes the fail-open outcome
|
|
330
|
+
* (connection admitted outright / reservation admitted, see module doc); the
|
|
331
|
+
* base gater's verdict is still honored first.
|
|
300
332
|
*
|
|
301
|
-
* An `'admit-
|
|
302
|
-
* `
|
|
303
|
-
*
|
|
304
|
-
*
|
|
333
|
+
* An `'admit-provisionally'` verdict admits the connection and arms a
|
|
334
|
+
* `provisionalDeadlineMs` timer against it. When the timer fires the policy is
|
|
335
|
+
* asked again, and the underlying `MultiaddrConnection` is closed unless it now
|
|
336
|
+
* answers `'admit'`; a reservation for that peer ADMITTED at the reservation
|
|
337
|
+
* hook disarms the timer first.
|
|
305
338
|
*
|
|
306
339
|
* NOTE: `base` is spread, so a gater passed as a CLASS INSTANCE would lose its
|
|
307
340
|
* prototype methods; every caller in this repo (and libp2p's own default)
|
|
308
341
|
* supplies a plain object. If a class-based gater ever shows up, delegate
|
|
309
342
|
* per-hook instead of spreading.
|
|
310
343
|
*
|
|
311
|
-
* Deny timing, as observed by the denied dialer
|
|
312
|
-
* the security handshake's early data, so
|
|
313
|
-
* (its `dial()` resolves) before this
|
|
314
|
-
* aborts the receiver's upgrade — the
|
|
315
|
-
* and never creates its muxer, so no
|
|
316
|
-
* dialer sees its "open" connection
|
|
344
|
+
* Deny timing, as observed by the denied dialer (a quiet-period or base-gater
|
|
345
|
+
* deny): noise negotiates the muxer in the security handshake's early data, so
|
|
346
|
+
* the DIALER's upgrade may complete (its `dial()` resolves) before this
|
|
347
|
+
* receiver-side hook runs. The deny then aborts the receiver's upgrade — the
|
|
348
|
+
* receiver never registers the connection and never creates its muxer, so no
|
|
349
|
+
* protocol can ever be negotiated — and the dialer sees its "open" connection
|
|
350
|
+
* close moments later.
|
|
317
351
|
*
|
|
318
352
|
* Control node only: strand cohort nodes legitimately connect cross-party
|
|
319
353
|
* peers, so cadre membership never gates them. An OPEN strand's node receives
|
|
@@ -322,8 +356,9 @@ export class UnauthorizedReservationBudget {
|
|
|
322
356
|
* evidence, not this module's membership admission — see
|
|
323
357
|
* `strand-revocation-enforcer.ts`.
|
|
324
358
|
*/
|
|
325
|
-
export function createMembershipConnectionGater(policy, base, decisionTimeoutMs = ADMISSION_DECISION_TIMEOUT_MS,
|
|
326
|
-
const
|
|
359
|
+
export function createMembershipConnectionGater(policy, base, decisionTimeoutMs = ADMISSION_DECISION_TIMEOUT_MS, provisionalDeadlineMs = PROVISIONAL_ADMISSION_DEADLINE_MS) {
|
|
360
|
+
const decideInbound = (remotePeerId) => decideWithinDeadline(() => policy.admitInbound(remotePeerId), 'admit', decisionTimeoutMs, `admitInbound(${remotePeerId})`);
|
|
361
|
+
const provisional = new ProvisionalAdmissions(provisionalDeadlineMs, decideInbound);
|
|
327
362
|
const quiet = () => policy.bringUpInFlight?.() ?? false;
|
|
328
363
|
return {
|
|
329
364
|
...base,
|
|
@@ -348,17 +383,16 @@ export function createMembershipConnectionGater(policy, base, decisionTimeoutMs
|
|
|
348
383
|
const remotePeerId = peerId.toString();
|
|
349
384
|
let verdict;
|
|
350
385
|
try {
|
|
351
|
-
verdict = await
|
|
386
|
+
verdict = await decideInbound(remotePeerId);
|
|
352
387
|
}
|
|
353
388
|
catch (error) {
|
|
354
389
|
log('admitInbound threw for %s — admitting (fail-open; stream gates decide): %o', remotePeerId, error);
|
|
355
390
|
return false;
|
|
356
391
|
}
|
|
357
|
-
if (verdict === 'admit-
|
|
358
|
-
|
|
359
|
-
return false;
|
|
392
|
+
if (verdict === 'admit-provisionally') {
|
|
393
|
+
provisional.arm(remotePeerId, maConn);
|
|
360
394
|
}
|
|
361
|
-
return
|
|
395
|
+
return false;
|
|
362
396
|
},
|
|
363
397
|
denyInboundRelayReservation: async (peerId) => {
|
|
364
398
|
if (await base?.denyInboundRelayReservation?.(peerId)) {
|
|
@@ -374,7 +408,7 @@ export function createMembershipConnectionGater(policy, base, decisionTimeoutMs
|
|
|
374
408
|
admitted = true;
|
|
375
409
|
}
|
|
376
410
|
if (admitted) {
|
|
377
|
-
|
|
411
|
+
provisional.disarm(remotePeerId);
|
|
378
412
|
}
|
|
379
413
|
return !admitted;
|
|
380
414
|
}
|
|
@@ -407,13 +441,12 @@ export async function decideWithinDeadline(decide, fallback, timeoutMs, what) {
|
|
|
407
441
|
}
|
|
408
442
|
}
|
|
409
443
|
/**
|
|
410
|
-
* The
|
|
411
|
-
*
|
|
412
|
-
*
|
|
413
|
-
* (called when a reservation for that peer is admitted) cancels
|
|
414
|
-
*
|
|
415
|
-
*
|
|
416
|
-
* a no-op (`close()` returns at once on any status but `open`).
|
|
444
|
+
* The deadlines of `'admit-provisionally'` connections, keyed by remote peerId
|
|
445
|
+
* (a Set per peer — one peer can hold several in-flight connections). `arm`
|
|
446
|
+
* starts a timer that re-asks the policy and closes the connection unless it now
|
|
447
|
+
* admits; `disarm` (called when a reservation for that peer is admitted) cancels
|
|
448
|
+
* every pending deadline for the peer, one whose question is already out
|
|
449
|
+
* included. Timers are unref'd so an armed deadline never holds a process open.
|
|
417
450
|
*
|
|
418
451
|
* Disarming is final for the connections it cancelled: a peer that reserved
|
|
419
452
|
* once and then lets its reservation lapse keeps a mute connection (the
|
|
@@ -421,15 +454,16 @@ export async function decideWithinDeadline(decide, fallback, timeoutMs, what) {
|
|
|
421
454
|
* side closes it. Bounded — only a peer the reservation policy already admitted
|
|
422
455
|
* can reach that state, so unplaceable peers are bounded by the budget cap.
|
|
423
456
|
*/
|
|
424
|
-
class
|
|
425
|
-
constructor(deadlineMs) {
|
|
457
|
+
class ProvisionalAdmissions {
|
|
458
|
+
constructor(deadlineMs, decide) {
|
|
426
459
|
this.deadlineMs = deadlineMs;
|
|
460
|
+
this.decide = decide;
|
|
427
461
|
this.byPeer = new Map();
|
|
428
462
|
}
|
|
429
463
|
arm(remotePeerId, maConn) {
|
|
430
464
|
const entry = {
|
|
431
465
|
maConn,
|
|
432
|
-
timer: setTimeout(() => this.expire(remotePeerId, entry), this.deadlineMs)
|
|
466
|
+
timer: setTimeout(() => void this.expire(remotePeerId, entry), this.deadlineMs)
|
|
433
467
|
};
|
|
434
468
|
entry.timer.unref?.();
|
|
435
469
|
let entries = this.byPeer.get(remotePeerId);
|
|
@@ -438,7 +472,7 @@ class PendingReserveDeadlines {
|
|
|
438
472
|
this.byPeer.set(remotePeerId, entries);
|
|
439
473
|
}
|
|
440
474
|
entries.add(entry);
|
|
441
|
-
log('Admitted %s
|
|
475
|
+
log('Admitted %s provisionally — closing the connection in %dms unless it is admissible by then', remotePeerId, this.deadlineMs);
|
|
442
476
|
}
|
|
443
477
|
disarm(remotePeerId) {
|
|
444
478
|
const entries = this.byPeer.get(remotePeerId);
|
|
@@ -450,17 +484,46 @@ class PendingReserveDeadlines {
|
|
|
450
484
|
clearTimeout(entry.timer);
|
|
451
485
|
}
|
|
452
486
|
}
|
|
453
|
-
expire(remotePeerId, entry) {
|
|
487
|
+
async expire(remotePeerId, entry) {
|
|
488
|
+
if (entry.maConn.status !== 'open') {
|
|
489
|
+
this.release(remotePeerId, entry);
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
const verdict = await this.recheck(remotePeerId);
|
|
493
|
+
// False when a reservation admitted while the question was out disarmed this deadline.
|
|
494
|
+
if (!this.release(remotePeerId, entry)) {
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
if (verdict === 'admit') {
|
|
498
|
+
log('%s is admissible at its provisional deadline — keeping the connection', remotePeerId);
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
log('Provisional admission expired for %s — still unplaced after %dms, closing the connection', remotePeerId, this.deadlineMs);
|
|
502
|
+
await this.drop(remotePeerId, entry.maConn);
|
|
503
|
+
}
|
|
504
|
+
/** The policy's answer at the deadline; a throw keeps the connection (fail-open). */
|
|
505
|
+
async recheck(remotePeerId) {
|
|
506
|
+
try {
|
|
507
|
+
return await this.decide(remotePeerId);
|
|
508
|
+
}
|
|
509
|
+
catch (error) {
|
|
510
|
+
log('admitInbound threw for %s at its provisional deadline — keeping the connection (fail-open): %o', remotePeerId, error);
|
|
511
|
+
return 'admit';
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
/** Forget `entry`; false when a `disarm` already took it. */
|
|
515
|
+
release(remotePeerId, entry) {
|
|
454
516
|
const entries = this.byPeer.get(remotePeerId);
|
|
455
|
-
entries?.delete(entry)
|
|
456
|
-
|
|
517
|
+
if (!entries?.delete(entry)) {
|
|
518
|
+
return false;
|
|
519
|
+
}
|
|
520
|
+
if (entries.size === 0) {
|
|
457
521
|
this.byPeer.delete(remotePeerId);
|
|
458
522
|
}
|
|
459
|
-
|
|
460
|
-
void this.drop(remotePeerId, entry.maConn);
|
|
523
|
+
return true;
|
|
461
524
|
}
|
|
462
525
|
/**
|
|
463
|
-
* End an expired
|
|
526
|
+
* End an expired provisional connection: a bounded graceful close, with
|
|
464
527
|
* `abort()` only as the escalation. The order cannot be reversed — `abort()`
|
|
465
528
|
* marks the connection `aborted`, and `close()` returns immediately on any
|
|
466
529
|
* status that is not `open`, so aborting first would make the close a silent
|
|
@@ -469,11 +532,11 @@ class PendingReserveDeadlines {
|
|
|
469
532
|
*/
|
|
470
533
|
async drop(remotePeerId, maConn) {
|
|
471
534
|
try {
|
|
472
|
-
await withDeadline(
|
|
535
|
+
await withDeadline(PROVISIONAL_ADMISSION_CLOSE_TIMEOUT_MS, `provisional close for ${remotePeerId}`, (signal) => maConn.close({ signal }));
|
|
473
536
|
return;
|
|
474
537
|
}
|
|
475
538
|
catch (error) {
|
|
476
|
-
log('Closing the expired
|
|
539
|
+
log('Closing the expired provisional connection from %s failed — aborting: %o', remotePeerId, error);
|
|
477
540
|
}
|
|
478
541
|
// NOTE: this fallback cannot actually free a WebSocket. `@libp2p/websockets`'
|
|
479
542
|
// `sendReset()` calls `websocket.close(1006)`, and 1006 is a reserved code
|
|
@@ -485,10 +548,10 @@ class PendingReserveDeadlines {
|
|
|
485
548
|
// far as this layer can go. Revisit — drop the fallback, or go back to a
|
|
486
549
|
// plain `abort()` — once that transport sends a legal reset code.
|
|
487
550
|
try {
|
|
488
|
-
maConn.abort(new Error(`
|
|
551
|
+
maConn.abort(new Error(`provisional admission expired: still unplaced after ${this.deadlineMs}ms`));
|
|
489
552
|
}
|
|
490
553
|
catch (error) {
|
|
491
|
-
log('Aborting the expired
|
|
554
|
+
log('Aborting the expired provisional connection from %s threw: %o', remotePeerId, error);
|
|
492
555
|
}
|
|
493
556
|
}
|
|
494
557
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"membership-connection-gater.js","sourceRoot":"","sources":["../src/membership-connection-gater.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"membership-connection-gater.js","sourceRoot":"","sources":["../src/membership-connection-gater.ts"],"names":[],"mappings":"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"}
|