@serfab/cadre-core 0.11.0 → 0.12.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/announce-addrs.d.ts +49 -0
- package/dist/announce-addrs.js +78 -0
- package/dist/announce-addrs.js.map +1 -0
- package/dist/cadre-node.d.ts +281 -30
- package/dist/cadre-node.js +513 -103
- package/dist/cadre-node.js.map +1 -1
- package/dist/control-database.d.ts +155 -23
- package/dist/control-database.js +272 -104
- package/dist/control-database.js.map +1 -1
- package/dist/control-read-retry.d.ts +103 -0
- package/dist/control-read-retry.js +145 -0
- package/dist/control-read-retry.js.map +1 -0
- package/dist/control-retry.d.ts +101 -0
- package/dist/control-retry.js +108 -0
- package/dist/control-retry.js.map +1 -0
- package/dist/control-schema.d.ts +1 -1
- package/dist/control-schema.js +20 -4
- package/dist/control-schema.js.map +1 -1
- package/dist/control-write-retry.d.ts +59 -35
- package/dist/control-write-retry.js +21 -92
- package/dist/control-write-retry.js.map +1 -1
- package/dist/delegate-admission.d.ts +17 -15
- package/dist/delegate-admission.js +17 -15
- package/dist/delegate-admission.js.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.js +17 -8
- package/dist/index.js.map +1 -1
- package/dist/membership-connection-gater.d.ts +211 -25
- package/dist/membership-connection-gater.js +309 -29
- package/dist/membership-connection-gater.js.map +1 -1
- package/dist/peer-record.d.ts +26 -0
- package/dist/peer-record.js +32 -0
- package/dist/peer-record.js.map +1 -1
- package/dist/relay-addrs.d.ts +76 -26
- package/dist/relay-addrs.js +115 -27
- package/dist/relay-addrs.js.map +1 -1
- package/dist/relay-reservation.d.ts +20 -15
- package/dist/relay-reservation.js +18 -14
- package/dist/relay-reservation.js.map +1 -1
- package/dist/strand-addr-protocol.js +16 -0
- package/dist/strand-addr-protocol.js.map +1 -1
- package/dist/strand-backfill.js +13 -4
- package/dist/strand-backfill.js.map +1 -1
- package/dist/strand-formation-manager.d.ts +10 -9
- package/dist/strand-formation-manager.js +10 -9
- package/dist/strand-formation-manager.js.map +1 -1
- package/dist/strand-formation-protocol.d.ts +7 -7
- package/dist/strand-formation-protocol.js +8 -8
- package/dist/strand-formation-protocol.js.map +1 -1
- package/dist/strand-instance-manager.d.ts +4 -3
- package/dist/strand-instance-manager.js +31 -6
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-membership-writer.d.ts +106 -14
- package/dist/strand-membership-writer.js +180 -14
- package/dist/strand-membership-writer.js.map +1 -1
- package/dist/strand-solicitation.d.ts +3 -3
- package/dist/strand-solicitation.js +4 -5
- package/dist/strand-solicitation.js.map +1 -1
- package/dist/strand-wake-protocol.d.ts +47 -2
- package/dist/strand-wake-protocol.js +76 -6
- package/dist/strand-wake-protocol.js.map +1 -1
- package/dist/types.d.ts +74 -29
- package/dist/types.js.map +1 -1
- package/package.json +8 -8
- package/src/announce-addrs.ts +93 -0
- package/src/cadre-node.ts +5603 -5158
- package/src/control-database.ts +2584 -2406
- package/src/control-read-retry.ts +167 -0
- package/src/control-retry.ts +190 -0
- package/src/control-schema.ts +20 -4
- package/src/control-write-retry.ts +30 -130
- package/src/delegate-admission.ts +17 -15
- package/src/index.ts +435 -407
- package/src/membership-connection-gater.ts +533 -204
- package/src/peer-record.ts +33 -0
- package/src/relay-addrs.ts +218 -111
- package/src/relay-reservation.ts +828 -823
- package/src/strand-addr-protocol.ts +17 -0
- package/src/strand-backfill.ts +389 -366
- package/src/strand-formation-manager.ts +492 -491
- package/src/strand-formation-protocol.ts +8 -8
- package/src/strand-instance-manager.ts +636 -611
- package/src/strand-membership-writer.ts +209 -14
- package/src/strand-solicitation.ts +6 -7
- package/src/strand-wake-protocol.ts +94 -8
- package/src/types.ts +74 -29
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Translate `network.announceAddrs` / `network.appendAnnounceAddrs` — the operator-facing
|
|
3
|
+
* "advertise these addresses" settings — into the two `@optimystic/db-p2p` `NodeOptions`
|
|
4
|
+
* fields of the same names, which reach libp2p's `addresses.announce` /
|
|
5
|
+
* `addresses.appendAnnounce`.
|
|
6
|
+
*
|
|
7
|
+
* Two jobs, both of which the control node and every strand node need identically, hence
|
|
8
|
+
* one module rather than the same conditional spread written twice:
|
|
9
|
+
*
|
|
10
|
+
* - **Empty means unset.** libp2p treats `announce: []` as "no override", and forwarding
|
|
11
|
+
* `[]` would still be forwarding a field. An empty config array is dropped so it cannot
|
|
12
|
+
* land as an explicit empty announce set.
|
|
13
|
+
* - **Validate the multiaddrs here, at start.** libp2p does NOT validate announce addrs
|
|
14
|
+
* at construction: `AddressManager` stores them as raw strings and only parses them on
|
|
15
|
+
* the first `getAnnounceAddrs()`. A typo therefore produces a node that starts
|
|
16
|
+
* cleanly, then throws `InvalidMultiaddrError` out of every `getMultiaddrs()` call —
|
|
17
|
+
* including an UNHANDLED one from the debounced peer-store update libp2p runs on
|
|
18
|
+
* `transport:listening`. Verified against libp2p's `address-manager` (its constructor
|
|
19
|
+
* does `announce.map(ma => ma.toString())`; `getAnnounceAddrs()` does `multiaddr(a)`).
|
|
20
|
+
* Parsing each entry up front converts that into a loud failure at node start, which is
|
|
21
|
+
* what {@link relayCircuitAddrs} already does for `network.relayAddrs`.
|
|
22
|
+
*
|
|
23
|
+
* Parsing alone is not enough, though: `''` and `'/'` both parse into a component-less
|
|
24
|
+
* multiaddr, and a set holding only those is non-empty by the rule above — so it would
|
|
25
|
+
* replace every advertised address with nothing at all. An entry naming no address is
|
|
26
|
+
* therefore rejected alongside one that fails to parse.
|
|
27
|
+
*/
|
|
28
|
+
import type { NetworkConfig } from './types.js';
|
|
29
|
+
/**
|
|
30
|
+
* The announce fields to spread into `createLibp2pNode` options. A field is present
|
|
31
|
+
* only when the operator configured a non-empty list for it, so a node that configures
|
|
32
|
+
* neither passes neither.
|
|
33
|
+
*/
|
|
34
|
+
export interface ResolvedAnnounceAddrs {
|
|
35
|
+
announceAddrs?: string[];
|
|
36
|
+
appendAnnounceAddrs?: string[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Resolve both announce fields off a `NetworkConfig`. Throws — naming the offending
|
|
40
|
+
* config field and entry — when any entry is not a parsable multiaddr.
|
|
41
|
+
*/
|
|
42
|
+
export declare function resolveAnnounceAddrs(network: NetworkConfig | undefined): ResolvedAnnounceAddrs;
|
|
43
|
+
/**
|
|
44
|
+
* Whether this node's advertised set will be REPLACED rather than extended — i.e.
|
|
45
|
+
* whether {@link ResolvedAnnounceAddrs.announceAddrs} is in play at all. The single
|
|
46
|
+
* predicate behind `CadreNode.start()`'s operator warning, kept here so the warning
|
|
47
|
+
* and the forwarding agree on what "set" means (non-empty, not merely present).
|
|
48
|
+
*/
|
|
49
|
+
export declare function replacesAdvertisedAddrs(network: NetworkConfig | undefined): boolean;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Translate `network.announceAddrs` / `network.appendAnnounceAddrs` — the operator-facing
|
|
3
|
+
* "advertise these addresses" settings — into the two `@optimystic/db-p2p` `NodeOptions`
|
|
4
|
+
* fields of the same names, which reach libp2p's `addresses.announce` /
|
|
5
|
+
* `addresses.appendAnnounce`.
|
|
6
|
+
*
|
|
7
|
+
* Two jobs, both of which the control node and every strand node need identically, hence
|
|
8
|
+
* one module rather than the same conditional spread written twice:
|
|
9
|
+
*
|
|
10
|
+
* - **Empty means unset.** libp2p treats `announce: []` as "no override", and forwarding
|
|
11
|
+
* `[]` would still be forwarding a field. An empty config array is dropped so it cannot
|
|
12
|
+
* land as an explicit empty announce set.
|
|
13
|
+
* - **Validate the multiaddrs here, at start.** libp2p does NOT validate announce addrs
|
|
14
|
+
* at construction: `AddressManager` stores them as raw strings and only parses them on
|
|
15
|
+
* the first `getAnnounceAddrs()`. A typo therefore produces a node that starts
|
|
16
|
+
* cleanly, then throws `InvalidMultiaddrError` out of every `getMultiaddrs()` call —
|
|
17
|
+
* including an UNHANDLED one from the debounced peer-store update libp2p runs on
|
|
18
|
+
* `transport:listening`. Verified against libp2p's `address-manager` (its constructor
|
|
19
|
+
* does `announce.map(ma => ma.toString())`; `getAnnounceAddrs()` does `multiaddr(a)`).
|
|
20
|
+
* Parsing each entry up front converts that into a loud failure at node start, which is
|
|
21
|
+
* what {@link relayCircuitAddrs} already does for `network.relayAddrs`.
|
|
22
|
+
*
|
|
23
|
+
* Parsing alone is not enough, though: `''` and `'/'` both parse into a component-less
|
|
24
|
+
* multiaddr, and a set holding only those is non-empty by the rule above — so it would
|
|
25
|
+
* replace every advertised address with nothing at all. An entry naming no address is
|
|
26
|
+
* therefore rejected alongside one that fails to parse.
|
|
27
|
+
*/
|
|
28
|
+
import { multiaddr } from '@multiformats/multiaddr';
|
|
29
|
+
/**
|
|
30
|
+
* Resolve both announce fields off a `NetworkConfig`. Throws — naming the offending
|
|
31
|
+
* config field and entry — when any entry is not a parsable multiaddr.
|
|
32
|
+
*/
|
|
33
|
+
export function resolveAnnounceAddrs(network) {
|
|
34
|
+
const announceAddrs = configuredAddrs('network.announceAddrs', network?.announceAddrs);
|
|
35
|
+
const appendAnnounceAddrs = configuredAddrs('network.appendAnnounceAddrs', network?.appendAnnounceAddrs);
|
|
36
|
+
return {
|
|
37
|
+
...(announceAddrs && { announceAddrs }),
|
|
38
|
+
...(appendAnnounceAddrs && { appendAnnounceAddrs })
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Whether this node's advertised set will be REPLACED rather than extended — i.e.
|
|
43
|
+
* whether {@link ResolvedAnnounceAddrs.announceAddrs} is in play at all. The single
|
|
44
|
+
* predicate behind `CadreNode.start()`'s operator warning, kept here so the warning
|
|
45
|
+
* and the forwarding agree on what "set" means (non-empty, not merely present).
|
|
46
|
+
*/
|
|
47
|
+
export function replacesAdvertisedAddrs(network) {
|
|
48
|
+
return (network?.announceAddrs?.length ?? 0) > 0;
|
|
49
|
+
}
|
|
50
|
+
/** The entries to forward for one announce field, or `undefined` when it is unset or empty. */
|
|
51
|
+
function configuredAddrs(field, addrs) {
|
|
52
|
+
if (!addrs || addrs.length === 0) {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
return addrs.map((addr) => validated(field, addr));
|
|
56
|
+
}
|
|
57
|
+
/** `addr` unchanged, having proved it names a real address — config field named on failure. */
|
|
58
|
+
function validated(field, addr) {
|
|
59
|
+
if (parsed(field, addr).getComponents().length === 0) {
|
|
60
|
+
// `''` and `'/'` PARSE: both yield a component-less multiaddr that stringifies to
|
|
61
|
+
// `/`. Forwarded, they make an announce set that is non-empty but names nothing —
|
|
62
|
+
// which by the replacement rule above costs the node every address it would
|
|
63
|
+
// otherwise advertise, silently. A templated `cadre.yaml` whose address variable went
|
|
64
|
+
// unsubstituted is the realistic way in, so it is rejected rather than forwarded.
|
|
65
|
+
throw new Error(`${field} entry names no address: ${JSON.stringify(addr)}`);
|
|
66
|
+
}
|
|
67
|
+
return addr;
|
|
68
|
+
}
|
|
69
|
+
/** `addr` as a multiaddr, with the config field named on a parse failure. */
|
|
70
|
+
function parsed(field, addr) {
|
|
71
|
+
try {
|
|
72
|
+
return multiaddr(addr);
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
throw new Error(`${field} entry is not a valid multiaddr: ${addr}`, { cause: err });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=announce-addrs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"announce-addrs.js","sourceRoot":"","sources":["../src/announce-addrs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,SAAS,EAAkB,MAAM,yBAAyB,CAAC;AAapE;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAkC;IACrE,MAAM,aAAa,GAAG,eAAe,CAAC,uBAAuB,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;IACvF,MAAM,mBAAmB,GAAG,eAAe,CAAC,6BAA6B,EAAE,OAAO,EAAE,mBAAmB,CAAC,CAAC;IACzG,OAAO;QACL,GAAG,CAAC,aAAa,IAAI,EAAE,aAAa,EAAE,CAAC;QACvC,GAAG,CAAC,mBAAmB,IAAI,EAAE,mBAAmB,EAAE,CAAC;KACpD,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAkC;IACxE,OAAO,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;AACnD,CAAC;AAED,+FAA+F;AAC/F,SAAS,eAAe,CAAC,KAAa,EAAE,KAAoC;IAC1E,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,+FAA+F;AAC/F,SAAS,SAAS,CAAC,KAAa,EAAE,IAAY;IAC5C,IAAI,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrD,kFAAkF;QAClF,kFAAkF;QAClF,4EAA4E;QAC5E,sFAAsF;QACtF,kFAAkF;QAClF,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,4BAA4B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,6EAA6E;AAC7E,SAAS,MAAM,CAAC,KAAa,EAAE,IAAY;IACzC,IAAI,CAAC;QACH,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,oCAAoC,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IACtF,CAAC;AACH,CAAC"}
|
package/dist/cadre-node.d.ts
CHANGED
|
@@ -103,10 +103,11 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
103
103
|
private windowWaiters;
|
|
104
104
|
private eventHandlers;
|
|
105
105
|
/**
|
|
106
|
-
* Relay multiaddrs the caller asked {@link reserveRelays} to reserve through
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
106
|
+
* Relay multiaddrs the caller asked {@link reserveRelays} to reserve through —
|
|
107
|
+
* or, on a node that names `network.relayAddrs`, the ones
|
|
108
|
+
* {@link driveControlRelayReservation} asked for at the end of {@link start}.
|
|
109
|
+
* Empty (the default) means neither happened, so {@link getRelayReservationState}
|
|
110
|
+
* reports `none`.
|
|
110
111
|
*/
|
|
111
112
|
private relayReserveAddrs;
|
|
112
113
|
/**
|
|
@@ -121,6 +122,23 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
121
122
|
* supervisor to hold one — i.e. the pre-start `control node unavailable` case.
|
|
122
123
|
*/
|
|
123
124
|
private relayReserveError;
|
|
125
|
+
/**
|
|
126
|
+
* True from just before the control libp2p node is created until
|
|
127
|
+
* {@link ControlDatabase.initialize} has settled — the connection gate's
|
|
128
|
+
* BRING-UP QUIET PERIOD (`membership-connection-gater.ts`), during which this
|
|
129
|
+
* node refuses every control connection in both directions.
|
|
130
|
+
*
|
|
131
|
+
* The invariant: the control database is built while this node holds zero
|
|
132
|
+
* control connections. Every same-party sibling connected in that window joins
|
|
133
|
+
* the Optimystic cohort the bring-up's block probes consult, and a sibling that
|
|
134
|
+
* has not yet replicated this node's `CadrePeer` row refuses them all — which
|
|
135
|
+
* fails `start()` outright and cannot be retried into convergence (writing the
|
|
136
|
+
* row that would clear the refusal needs the database being built).
|
|
137
|
+
*
|
|
138
|
+
* Cleared on FAILURE as well as success ({@link cleanup} clears it), so
|
|
139
|
+
* teardown is never gated.
|
|
140
|
+
*/
|
|
141
|
+
private controlBringUpInFlight;
|
|
124
142
|
/** Map of strandId -> sAppConfig for sAppId filtering and management */
|
|
125
143
|
private sAppConfigs;
|
|
126
144
|
/**
|
|
@@ -181,12 +199,25 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
181
199
|
/**
|
|
182
200
|
* In-memory delegate admission grants (see `delegate-admission.ts`): the
|
|
183
201
|
* strand-node transport peerIds this party's members have announced over the
|
|
184
|
-
* strand-addr RPC, admitted at the CONNECTION
|
|
185
|
-
* strand node can hold a circuit-relay reservation on this
|
|
186
|
-
*
|
|
187
|
-
*
|
|
202
|
+
* strand-addr RPC, admitted at the CONNECTION and RESERVATION levels so a
|
|
203
|
+
* member's NAT'd strand node can hold a circuit-relay reservation on this
|
|
204
|
+
* node (without spending the unauthorized-reservation budget). Consulted
|
|
205
|
+
* ONLY by {@link admitInboundControlConnection} and
|
|
206
|
+
* {@link admitControlRelayReservation}; the fail-closed per-stream gate
|
|
207
|
+
* ({@link authorizeInboundControlStream}) never honors it.
|
|
188
208
|
*/
|
|
189
209
|
private readonly delegateAdmission;
|
|
210
|
+
/**
|
|
211
|
+
* Bounded budget of concurrent circuit-relay reservations granted to peers
|
|
212
|
+
* this node cannot (yet) place as members — the boot-ordering window where a
|
|
213
|
+
* genuine sibling reserves before its `CadrePeer` row has replicated here.
|
|
214
|
+
* Consulted only by {@link admitControlRelayReservation} (the gater's
|
|
215
|
+
* `denyInboundRelayReservation` policy); authorized members and announced
|
|
216
|
+
* delegates are admitted before it and never counted. Cap from
|
|
217
|
+
* `network.unauthorizedRelayReservationCap` (default
|
|
218
|
+
* `MAX_UNAUTHORIZED_RELAY_RESERVATIONS`).
|
|
219
|
+
*/
|
|
220
|
+
private readonly unauthorizedRelayReservations;
|
|
190
221
|
/**
|
|
191
222
|
* When this node last ANNOUNCED a delegate, keyed `<targetPeerId>\n<strandId>`
|
|
192
223
|
* (the peer announced TO, not the delegate). Throttles
|
|
@@ -522,6 +553,27 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
522
553
|
* operation count.
|
|
523
554
|
*/
|
|
524
555
|
private resolveControlStorage;
|
|
556
|
+
/**
|
|
557
|
+
* Warn the operator when `network.announceAddrs` will silently cost this node the
|
|
558
|
+
* relay reachability it also configured.
|
|
559
|
+
*
|
|
560
|
+
* A non-empty announce set REPLACES everything libp2p advertises, so the
|
|
561
|
+
* `/p2p-circuit` address earned by a relay reservation is dropped from the node's
|
|
562
|
+
* advertised addresses even though the reservation itself is still held — peers
|
|
563
|
+
* behind NAT stop being able to reach it through that relay. Not an error: an
|
|
564
|
+
* operator whose relay slot is decorative may genuinely want only the announced
|
|
565
|
+
* address, so this reports and proceeds.
|
|
566
|
+
*
|
|
567
|
+
* Keyed off the RESOLVED listen addrs rather than `relayAddrs` alone, so a
|
|
568
|
+
* hand-written `/p2p-circuit` entry in `listenAddrs` — the same reservation by the
|
|
569
|
+
* longer route — is caught too.
|
|
570
|
+
*
|
|
571
|
+
* NOTE: the only direct `console.*` in this library — a boot-time operator warning, not a
|
|
572
|
+
* diagnostic trace (those use `debug`, which an operator never sees without `DEBUG=`). If a
|
|
573
|
+
* second such warning ever appears here, route both through a `CadreNodeEvents` entry the
|
|
574
|
+
* embedder surfaces instead of growing a console surface inside a library.
|
|
575
|
+
*/
|
|
576
|
+
private warnIfAnnounceAddrsDiscardRelay;
|
|
525
577
|
/**
|
|
526
578
|
* Map this node's config onto the control network's libp2p node options.
|
|
527
579
|
*
|
|
@@ -531,6 +583,15 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
531
583
|
* only caller in production is `createControlNode`.
|
|
532
584
|
*/
|
|
533
585
|
private buildControlNodeOptions;
|
|
586
|
+
/**
|
|
587
|
+
* Does this node's CONTROL libp2p run the circuit-relay server? An explicit
|
|
588
|
+
* `network.enableRelay` wins; otherwise storage-profile nodes default to on
|
|
589
|
+
* (better connectivity/uptime). Shared by {@link buildControlNodeOptions}
|
|
590
|
+
* (which configures the server from it) and
|
|
591
|
+
* {@link admitInboundControlConnection} (whose deny/admit-for-relay branch
|
|
592
|
+
* must agree with whether a reservation is even servable here).
|
|
593
|
+
*/
|
|
594
|
+
private relayServerEnabled;
|
|
534
595
|
/**
|
|
535
596
|
* Decide whether an inbound CONTROL-network connection from `remotePeerId`
|
|
536
597
|
* should be admitted — the policy behind the connection gater wired in
|
|
@@ -540,7 +601,7 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
540
601
|
* `membership-connection-gater.ts` for the layer's rationale and the
|
|
541
602
|
* stranger-open protocol allowlist).
|
|
542
603
|
*
|
|
543
|
-
*
|
|
604
|
+
* Returns `'admit'` when ANY of:
|
|
544
605
|
* 1. a shared-baseline check admits ({@link admitControlPeerUnconditionally}
|
|
545
606
|
* — not running / DB torn down, absent-or-empty trusted-owner anchor, or
|
|
546
607
|
* configured bootstrap/relay infrastructure);
|
|
@@ -577,17 +638,69 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
577
638
|
* this node yet is denied even though the formation handler would have
|
|
578
639
|
* accepted it, exactly like the unreplicated-membership-row case below.
|
|
579
640
|
*
|
|
641
|
+
* When every check falls through, the verdict depends on whether this node
|
|
642
|
+
* runs the circuit-relay server ({@link relayServerEnabled}): without one,
|
|
643
|
+
* `'deny'`; with one, `'admit-for-relay'` — a circuit-relay reservation is
|
|
644
|
+
* established by the reserving peer DIALING the relay, so a connection deny
|
|
645
|
+
* here kills the reservation, and that deny is NOT self-healing: an outbound
|
|
646
|
+
* reconcile re-dial re-establishes a data link, but no outbound dial can
|
|
647
|
+
* grant the remote peer a reservation, and a relay-only peer has no address
|
|
648
|
+
* of its own to dial back — the reservation IS its address. The gater admits
|
|
649
|
+
* such a connection, decides the reservation via
|
|
650
|
+
* {@link admitControlRelayReservation}, and drops the connection if no
|
|
651
|
+
* reservation is admitted in time (see `membership-connection-gater.ts` →
|
|
652
|
+
* "The relay-reservation seam").
|
|
653
|
+
*
|
|
580
654
|
* NOTE: check 4/5 runs a control-DB read per inbound connection
|
|
581
655
|
* (`listAuthorizedMembers`); connections are rare and cadres small, and this
|
|
582
656
|
* layer is fail-open behind `ADMISSION_DECISION_TIMEOUT_MS`, so the live
|
|
583
657
|
* read is safe here — unlike the per-stream gate, which must consult the
|
|
584
658
|
* materialized {@link authorizedControlPeers} snapshot instead.
|
|
585
|
-
* NOTE: a sibling whose membership row has not yet
|
|
586
|
-
*
|
|
587
|
-
* either side's next outbound reconcile dial (outbound is never
|
|
588
|
-
* re-establishes the link — self-healing,
|
|
659
|
+
* NOTE: on a relay-DISABLED node, a sibling whose membership row has not yet
|
|
660
|
+
* replicated here is denied until the row converges (typically via the
|
|
661
|
+
* owner); either side's next outbound reconcile dial (outbound is never
|
|
662
|
+
* gated) re-establishes the DATA link — self-healing for data, visible as a
|
|
663
|
+
* transient deny. That self-healing story never covered a reservation, which
|
|
664
|
+
* is exactly why the relay-enabled path above exists.
|
|
589
665
|
*/
|
|
590
666
|
private admitInboundControlConnection;
|
|
667
|
+
/**
|
|
668
|
+
* Should `remotePeerId` be granted a circuit-relay reservation slot on this
|
|
669
|
+
* node's relay server? The policy behind the gater's
|
|
670
|
+
* `denyInboundRelayReservation` hook (see `membership-connection-gater.ts` →
|
|
671
|
+
* "The relay-reservation seam"); the circuit-relay server consults it per
|
|
672
|
+
* RESERVE request, so it is never called on a node whose relay server is off.
|
|
673
|
+
*
|
|
674
|
+
* Admits when ANY of:
|
|
675
|
+
* 1. a shared-baseline check admits ({@link admitControlPeerUnconditionally}
|
|
676
|
+
* — not running / DB torn down, absent-or-empty trusted-owner anchor, or
|
|
677
|
+
* configured bootstrap/relay infrastructure);
|
|
678
|
+
* 2. the peer holds a live delegate admission grant — a member's strand
|
|
679
|
+
* node reserving here (see `delegate-admission.ts`); never counted
|
|
680
|
+
* against the unauthorized budget;
|
|
681
|
+
* 3. the authorized-member set is empty (cold start) or the peer IS an
|
|
682
|
+
* authorized member — members are never counted against the budget; or
|
|
683
|
+
* 4. the peer takes (or already holds) a slot in the bounded
|
|
684
|
+
* unauthorized-reservation budget — the boot-ordering window where a
|
|
685
|
+
* genuine member reserves before its `CadrePeer` row replicates here.
|
|
686
|
+
* Cap via `network.unauthorizedRelayReservationCap` (0 = refuse every
|
|
687
|
+
* unauthorized reservation).
|
|
688
|
+
*
|
|
689
|
+
* Every uncounted admission also RELEASES the budget slot the peer may hold
|
|
690
|
+
* from an earlier reservation taken while it was still unplaceable — a member
|
|
691
|
+
* that boots, reserves, and only then has its row replicate here would
|
|
692
|
+
* otherwise keep that slot spent for the rest of the entry's TTL.
|
|
693
|
+
*
|
|
694
|
+
* The connection gate's stranger carve-outs (an open enrollment window, an
|
|
695
|
+
* outstanding formation invitation) deliberately do NOT extend here: they
|
|
696
|
+
* exist so a stranger's SEED or FORMATION stream can ride a connection, and
|
|
697
|
+
* neither needs relay capacity. A genuine invitee that does need a relay slot
|
|
698
|
+
* takes one from the budget like any other unplaced peer, so an open window
|
|
699
|
+
* never becomes an unbounded grant of this node's forwarding capacity.
|
|
700
|
+
*/
|
|
701
|
+
private admitControlRelayReservation;
|
|
702
|
+
/** Admit a reservation on the peer's own merits, giving back any budget slot it still holds. */
|
|
703
|
+
private admitReservationUncounted;
|
|
591
704
|
/**
|
|
592
705
|
* Hold the control-network inbound gate open for not-yet-authorized peers
|
|
593
706
|
* until `untilEpochMs` (extends, never shrinks, an already-open window).
|
|
@@ -599,7 +712,8 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
599
712
|
/**
|
|
600
713
|
* Record (or refresh) a delegate admission grant: `delegatePeerId` is the
|
|
601
714
|
* transport peerId of `announcerPeerId`'s strand-`strandId` node, admitted
|
|
602
|
-
* at the CONNECTION
|
|
715
|
+
* at the CONNECTION and RESERVATION levels (all a circuit-relay reservation
|
|
716
|
+
* needs, without spending the unauthorized-reservation budget) for
|
|
603
717
|
* `DELEGATE_GRANT_TTL_MS`. Called by the strand-addr responder after its
|
|
604
718
|
* authorized-membership gate has passed; public so tests can drive the
|
|
605
719
|
* admission policy without a full strand launch. A re-announce for the same
|
|
@@ -677,6 +791,12 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
677
791
|
*
|
|
678
792
|
* The SOLE caller is {@link drainMembershipGate}, which serializes refreshes —
|
|
679
793
|
* so two reads can no longer settle out of order.
|
|
794
|
+
*
|
|
795
|
+
* Reads WITHOUT the transient-failure retry, deliberately: `ControlDatabase` drives
|
|
796
|
+
* this listener with its write lock HELD (`notifyMembershipChanged`), so a retrying
|
|
797
|
+
* read here would sleep its backoff holding the lock and stall every other local
|
|
798
|
+
* writer. Nothing is lost — this refresh already keeps the previous snapshot on
|
|
799
|
+
* failure and is re-driven by the next membership write and by the timed reconcile.
|
|
680
800
|
*/
|
|
681
801
|
private refreshAuthorizedControlPeers;
|
|
682
802
|
/**
|
|
@@ -787,8 +907,44 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
787
907
|
* Survivors are returned signaling (`/p2p-circuit`) first, filtered to
|
|
788
908
|
* signaling-only when requested, as parsed `Multiaddr`s (unparsable addrs
|
|
789
909
|
* dropped). Any gate failure yields an empty array rather than throwing.
|
|
910
|
+
*
|
|
911
|
+
* Every returned address is normalized to terminate in `/p2p/<peerId>` — see
|
|
912
|
+
* {@link normalizeDialAddrs} for why that invariant, not each dial site's own
|
|
913
|
+
* handling, is what keeps a mixed list from taking a whole peer offline.
|
|
790
914
|
*/
|
|
791
915
|
resolvePeerAddrs(peerId: string, opts?: ResolveOpts): Promise<Multiaddr[]>;
|
|
916
|
+
/**
|
|
917
|
+
* Guarantee every address handed to a control-network dial terminates in
|
|
918
|
+
* `/p2p/<peerId>`, with no duplicates — the invariant every dial path
|
|
919
|
+
* downstream relies on.
|
|
920
|
+
*
|
|
921
|
+
* `libp2p.dial(addrs)` requires that the addresses in ONE dial either all name
|
|
922
|
+
* a peer id or none do; a list mixing a circuit address (which ends in
|
|
923
|
+
* `/p2p/<target>`) with a bare direct one (which ends in `/tcp/…`) makes that
|
|
924
|
+
* call throw, and the whole peer is then silently skipped rather than one bad
|
|
925
|
+
* address.
|
|
926
|
+
*
|
|
927
|
+
* Applied by ALL THREE sources of control-dial candidates, so no call site
|
|
928
|
+
* invents its own rule and none can produce a mixed list: the signed record
|
|
929
|
+
* ({@link resolvePeerAddrs}), the libp2p address book
|
|
930
|
+
* ({@link peerStoreAddrs}), and a seed's retained owner addresses
|
|
931
|
+
* ({@link bootstrapDialAddrs}).
|
|
932
|
+
*
|
|
933
|
+
* An address naming a DIFFERENT trailing peer id is dropped: it does not reach
|
|
934
|
+
* `peerId`, so it does not belong in this peer's candidate list (libp2p's own
|
|
935
|
+
* dial queue filters the same shape out one layer lower).
|
|
936
|
+
*/
|
|
937
|
+
private normalizeDialAddrs;
|
|
938
|
+
/**
|
|
939
|
+
* One address bound to `peerId`, or `null` when it cannot be — logged either
|
|
940
|
+
* way, never thrown, so every caller's list-shaping stays total.
|
|
941
|
+
*
|
|
942
|
+
* `withTrailingPeerId` encapsulates `/p2p/<peerId>`, which throws on a peer id
|
|
943
|
+
* that does not parse. Unreachable for a `CadrePeer` row (the binding gate
|
|
944
|
+
* above parsed it already), reachable for a seed-supplied one
|
|
945
|
+
* ({@link bootstrapDialAddrs}).
|
|
946
|
+
*/
|
|
947
|
+
private bindAddrToPeer;
|
|
792
948
|
/** Parse multiaddr strings, dropping (and logging) any that fail to parse. */
|
|
793
949
|
private parseMultiaddrs;
|
|
794
950
|
/**
|
|
@@ -875,6 +1031,16 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
875
1031
|
* Cold-start fallback: the libp2p peerStore multiaddrs for `peerId` (seeded by
|
|
876
1032
|
* {@link SeedBootstrapService.applySeed}). Returns `[]` on a missing entry or any
|
|
877
1033
|
* parse/lookup failure — never throws.
|
|
1034
|
+
*
|
|
1035
|
+
* Normalized through {@link normalizeDialAddrs} for the same reason
|
|
1036
|
+
* {@link resolvePeerAddrs} is, and with more cause: the address book hands back
|
|
1037
|
+
* a list that is inherently MIXED. `@libp2p/peer-store`'s
|
|
1038
|
+
* `dedupeFilterAndSortAddresses` strips a trailing `/p2p/<peerId>` only when
|
|
1039
|
+
* that id is the address's FIRST `/p2p/` component, so a direct address
|
|
1040
|
+
* round-trips bare while a relayed one — whose first `/p2p/` names the relay —
|
|
1041
|
+
* keeps its suffix (the same asymmetry `peer-addr-book.ts`'s `addrKey` exists
|
|
1042
|
+
* to absorb). Feeding both to one `dial()` is exactly the
|
|
1043
|
+
* `InvalidParametersError` that skipped the whole peer.
|
|
878
1044
|
*/
|
|
879
1045
|
private peerStoreAddrs;
|
|
880
1046
|
/**
|
|
@@ -927,11 +1093,12 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
927
1093
|
* Bind a bootstrap peer's seed addresses to its peer id, so the dial
|
|
928
1094
|
* authenticates the peer it is aiming at rather than trusting whoever answers.
|
|
929
1095
|
*
|
|
930
|
-
*
|
|
931
|
-
*
|
|
932
|
-
*
|
|
933
|
-
*
|
|
934
|
-
* bare
|
|
1096
|
+
* The same {@link normalizeDialAddrs} rule the resolved and address-book paths
|
|
1097
|
+
* use, on the third and last source of control-dial candidates: an address that
|
|
1098
|
+
* already terminates in `/p2p/<id>` must carry THIS peer's id or it is dropped
|
|
1099
|
+
* (a seed that disagrees with itself is not a dial target); one that does not —
|
|
1100
|
+
* a bare listen addr, or a relay hop with the destination missing — gets the id
|
|
1101
|
+
* encapsulated; an unencapsulatable one is dropped rather than dialed bare.
|
|
935
1102
|
*/
|
|
936
1103
|
private bootstrapDialAddrs;
|
|
937
1104
|
/** Dial one cold-start bootstrap peer, best-effort. Returns whether it connected. */
|
|
@@ -1180,6 +1347,12 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
1180
1347
|
expireDeviceToken(peerId: string): Promise<void>;
|
|
1181
1348
|
private handleStrandAdded;
|
|
1182
1349
|
private handleStrandRemoved;
|
|
1350
|
+
/**
|
|
1351
|
+
* Return this node to its pre-{@link start} state. The ONE teardown — `stop()` and
|
|
1352
|
+
* a failed `start()` both come here, so anything a stopped node must not still be
|
|
1353
|
+
* doing belongs in this method and not in `stop()`. `stop()` adds only the
|
|
1354
|
+
* `control:disconnected` emit, which a never-connected start has no edge for.
|
|
1355
|
+
*/
|
|
1183
1356
|
private cleanup;
|
|
1184
1357
|
private handleStrandIdle;
|
|
1185
1358
|
/**
|
|
@@ -1521,11 +1694,25 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
1521
1694
|
private connectedSiblingTargets;
|
|
1522
1695
|
/**
|
|
1523
1696
|
* The circuit relays this node's strand nodes would reserve through: the
|
|
1524
|
-
* union of
|
|
1525
|
-
* `network.listenAddrs` circuit entry
|
|
1526
|
-
*
|
|
1527
|
-
*
|
|
1528
|
-
*
|
|
1697
|
+
* union of CONFIGURED relays — `network.relayAddrs`, plus any hand-written
|
|
1698
|
+
* `network.listenAddrs` circuit entry, both of which a strand node inherits
|
|
1699
|
+
* verbatim — and the control node's own live `/p2p-circuit` multiaddrs (a
|
|
1700
|
+
* reservation this node discovered rather than configured).
|
|
1701
|
+
*
|
|
1702
|
+
* The CONFIGURED half reads `network.relayAddrs` and `network.listenAddrs`
|
|
1703
|
+
* directly rather than going through {@link resolveListenAddrs}: the control
|
|
1704
|
+
* node's resolution takes the `'search'` route, whose bare `/p2p-circuit` entry
|
|
1705
|
+
* names no relay, so a configured relay would be unannounceable here until this
|
|
1706
|
+
* node's own reservation landed — and the announce must be in place BEFORE a
|
|
1707
|
+
* strand node dials its reservation, since the relay's membership gate does not
|
|
1708
|
+
* know the strand's derived peerId (see delegate-admission.ts). Configuration is
|
|
1709
|
+
* authoritative; the live multiaddrs only ADD relays nobody configured.
|
|
1710
|
+
*
|
|
1711
|
+
* The `listenAddrs` half is now unreachable on a control node — `relay-addrs.ts`
|
|
1712
|
+
* rejects a hand-written `<relay>/p2p-circuit` listen entry outright, because the
|
|
1713
|
+
* bring-up quiet period denies the dial that listener makes from inside
|
|
1714
|
+
* `libp2p.start()`. Kept because it costs one spread and this is the one place
|
|
1715
|
+
* that would silently stop announcing if that rejection is ever relaxed.
|
|
1529
1716
|
*
|
|
1530
1717
|
* NOTE: a relay the STRAND node discovers on its own (autorelay — in neither
|
|
1531
1718
|
* source) gets no announcement, and a membership-gated one will deny it; fine
|
|
@@ -1719,16 +1906,48 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
1719
1906
|
* Get the control network node (for advanced use)
|
|
1720
1907
|
*/
|
|
1721
1908
|
getControlNode(): Libp2p | null;
|
|
1909
|
+
/**
|
|
1910
|
+
* The boot-path half of {@link reserveRelays}: reserve through every
|
|
1911
|
+
* `network.relayAddrs` entry, or fail `start()`.
|
|
1912
|
+
*
|
|
1913
|
+
* WHY IT RUNS HERE, AT THE END. `network.relayAddrs` used to resolve to a
|
|
1914
|
+
* CONFIGURED circuit listener, which libp2p dials from inside `libp2p.start()`
|
|
1915
|
+
* — so the relay was already a connected peer, and therefore already in this
|
|
1916
|
+
* node's Optimystic cohort, before `ControlDatabase.initialize()` ran. Building
|
|
1917
|
+
* that database is a long chain of cohort-consulting block probes (catalog
|
|
1918
|
+
* hydration, then one per table, then the indexes), and a sibling that has not
|
|
1919
|
+
* yet replicated this node's `CadrePeer` row correctly refuses every one of
|
|
1920
|
+
* them, so bring-up died on `BlockUnavailableError` — deterministically, on
|
|
1921
|
+
* every boot of a relay-only node. Retrying could not converge either: the
|
|
1922
|
+
* condition that clears the refusal is this node's own row reaching the
|
|
1923
|
+
* sibling, and writing that row needs the database the retry is building.
|
|
1924
|
+
*
|
|
1925
|
+
* So the invariant is ordering, not retrying: the control database is built
|
|
1926
|
+
* while this node holds ZERO control connections (a cohort of one, entirely
|
|
1927
|
+
* local), and only then does it reach out. Everything above in {@link start}
|
|
1928
|
+
* has completed by the time this runs.
|
|
1929
|
+
*
|
|
1930
|
+
* BUDGET: the supervisor's first attempt — `relay-reservation.ts`'s
|
|
1931
|
+
* `DEFAULT_RELAY_RESERVE_TIMEOUT_MS`, 10 s — is what `start()` waits on — deliberately the module default rather
|
|
1932
|
+
* than a boot-specific one. A healthy dial-plus-reserve is sub-second even over
|
|
1933
|
+
* a WAN, so 10 s is slack for a slow link; going much longer would make a dead
|
|
1934
|
+
* relay indistinguishable from a hung start, and much shorter would fail nodes
|
|
1935
|
+
* on links that were merely slow. The retries carry on in the background after
|
|
1936
|
+
* this resolves, exactly as they do for a {@link reserveRelays} caller.
|
|
1937
|
+
*/
|
|
1938
|
+
private driveControlRelayReservation;
|
|
1722
1939
|
/**
|
|
1723
1940
|
* Start keeping a relay reservation: dial the given relay(s) from the control
|
|
1724
1941
|
* node, ask the first one that answers for a reservation slot, wait until the
|
|
1725
1942
|
* resulting `/p2p-circuit` address makes this node dialable — and keep a
|
|
1726
1943
|
* supervisor running that re-drives whenever the reservation is later lost.
|
|
1727
1944
|
*
|
|
1728
|
-
*
|
|
1729
|
-
*
|
|
1730
|
-
*
|
|
1731
|
-
*
|
|
1945
|
+
* The FAIL-SOFT entry point, for a caller that discovers its relay at runtime
|
|
1946
|
+
* (a browser tab, a host UI). A node that names `network.relayAddrs` gets the
|
|
1947
|
+
* same drive from {@link driveControlRelayReservation} at the end of
|
|
1948
|
+
* {@link start}, which is fail-fast instead. Both fill the pending reservation
|
|
1949
|
+
* the bare `/p2p-circuit` search listener registered; calling this afterwards
|
|
1950
|
+
* simply replaces the supervisor with one over the new list.
|
|
1732
1951
|
*
|
|
1733
1952
|
* Resolves once the FIRST attempt has settled, exactly as it did when it drove
|
|
1734
1953
|
* once; the retries continue in the background until {@link stop} or the next
|
|
@@ -1790,13 +2009,40 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
1790
2009
|
* Push the multiaddrs that future invites should advertise. Pass `null` to
|
|
1791
2010
|
* revert to the libp2p-reported addresses (the default). The host calls this
|
|
1792
2011
|
* at spawn and on every NAT change.
|
|
2012
|
+
*
|
|
2013
|
+
* Entries need NOT carry a `/p2p/<peerId>` suffix — {@link resolveInviteAddresses}
|
|
2014
|
+
* appends this node's own before anything publishes or dials them (see
|
|
2015
|
+
* {@link normalizeSelfAddrs}). Passing them suffixed is equally fine.
|
|
1793
2016
|
*/
|
|
1794
2017
|
setInviteAddresses(addresses: string[] | null): void;
|
|
1795
2018
|
/**
|
|
1796
2019
|
* Resolve the addresses to embed in invites. Prefers pushed addresses, then
|
|
1797
|
-
* any config-supplied resolver, then the libp2p-observed multiaddrs.
|
|
2020
|
+
* any config-supplied resolver, then the libp2p-observed multiaddrs. The two
|
|
2021
|
+
* app-supplied sources are normalized onto `/p2p/<self>` (see
|
|
2022
|
+
* {@link normalizeSelfAddrs}) so neither hook has to remember the suffix;
|
|
2023
|
+
* libp2p's own addresses already carry it.
|
|
1798
2024
|
*/
|
|
1799
2025
|
private resolveInviteAddresses;
|
|
2026
|
+
/**
|
|
2027
|
+
* Normalize addresses an app handed us for THIS node onto `/p2p/<self>`, the
|
|
2028
|
+
* same invariant {@link normalizeDialAddrs} enforces on the way out.
|
|
2029
|
+
*
|
|
2030
|
+
* `setInviteAddresses` (the admin API `PUT /admin/invite-addresses`) and
|
|
2031
|
+
* `network.inviteAddressResolver` both take arbitrary strings, and whatever
|
|
2032
|
+
* they return ends up in this node's published `CadrePeer` record — so ONE
|
|
2033
|
+
* unsuffixed entry from either hook is enough to give every sibling in the
|
|
2034
|
+
* party a mixed candidate list for this peer. Establishing the suffix here,
|
|
2035
|
+
* where those strings enter the system, means neither hook has to know the
|
|
2036
|
+
* rule; `cadre-host`'s `buildInviteAddresses` already appends it, and
|
|
2037
|
+
* re-normalizing an already-suffixed address is a no-op.
|
|
2038
|
+
*
|
|
2039
|
+
* Unparsable and other-peer-addressed entries are passed through untouched
|
|
2040
|
+
* rather than dropped: publication is not the place to police an address's
|
|
2041
|
+
* validity, and {@link resolvePeerAddrs} already drops both on the read side.
|
|
2042
|
+
* Before `start()` resolves an identity there is no peer id to append, so the
|
|
2043
|
+
* list is returned as given.
|
|
2044
|
+
*/
|
|
2045
|
+
private normalizeSelfAddrs;
|
|
1800
2046
|
/**
|
|
1801
2047
|
* Enumerate the cadre's `CadrePeer` membership — the ADDRESSABLE surface (see
|
|
1802
2048
|
* {@link isMember}). Rows whose stamp is retired in `CadreControl.Revocation`
|
|
@@ -1853,8 +2099,13 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
1853
2099
|
* legit member goes un-authorized on readers that only pin the new key. Full
|
|
1854
2100
|
* rotation handling (re-vouch on rotate) is the
|
|
1855
2101
|
* `flip-strand-membership-rotation-known-gap` work, not this predicate's.
|
|
2102
|
+
*
|
|
2103
|
+
* @param retry - Whether the underlying membership read may retry a transient cluster
|
|
2104
|
+
* failure. Only {@link refreshAuthorizedControlPeers} passes `false`, because it runs
|
|
2105
|
+
* as the control database's membership listener with that database's write lock held;
|
|
2106
|
+
* see its comment.
|
|
1856
2107
|
*/
|
|
1857
|
-
listAuthorizedMembers(): Promise<Array<{
|
|
2108
|
+
listAuthorizedMembers(retry?: boolean): Promise<Array<{
|
|
1858
2109
|
peerId: string;
|
|
1859
2110
|
multiaddr: string | null;
|
|
1860
2111
|
}>>;
|