@serfab/cadre-core 0.10.0 → 0.11.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 +255 -255
- package/dist/cadre-node.d.ts +203 -28
- package/dist/cadre-node.js +445 -84
- package/dist/cadre-node.js.map +1 -1
- package/dist/control-cohort.d.ts +26 -0
- package/dist/control-cohort.js +26 -0
- package/dist/control-cohort.js.map +1 -1
- package/dist/control-database.d.ts +82 -117
- package/dist/control-database.js +217 -295
- package/dist/control-database.js.map +1 -1
- package/dist/control-formation-recorder.d.ts +8 -7
- package/dist/control-formation-recorder.js +8 -7
- package/dist/control-formation-recorder.js.map +1 -1
- package/dist/control-schema.d.ts +1 -1
- package/dist/control-schema.js +789 -774
- package/dist/control-schema.js.map +1 -1
- package/dist/control-write-retry.d.ts +15 -5
- package/dist/control-write-retry.js +19 -18
- package/dist/control-write-retry.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/peer-addr-book.d.ts +92 -0
- package/dist/peer-addr-book.js +220 -0
- package/dist/peer-addr-book.js.map +1 -0
- package/dist/seed-bootstrap.d.ts +7 -0
- package/dist/seed-bootstrap.js +15 -13
- package/dist/seed-bootstrap.js.map +1 -1
- package/dist/strand-cohort.d.ts +4 -37
- package/dist/strand-cohort.js +4 -15
- package/dist/strand-cohort.js.map +1 -1
- package/dist/strand-database.d.ts +11 -16
- package/dist/strand-database.js +19 -7
- package/dist/strand-database.js.map +1 -1
- package/dist/strand-formation-manager.d.ts +8 -8
- package/dist/strand-formation-manager.js +15 -18
- package/dist/strand-formation-manager.js.map +1 -1
- package/dist/strand-instance-manager.d.ts +52 -21
- package/dist/strand-instance-manager.js +100 -34
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-membership-writer.d.ts +6 -4
- package/dist/strand-membership-writer.js +38 -36
- package/dist/strand-membership-writer.js.map +1 -1
- package/dist/types.d.ts +39 -31
- package/dist/types.js.map +1 -1
- package/package.json +8 -7
- package/src/arachnode-stub.ts +159 -159
- package/src/bootstrap-peer-store-file.ts +44 -44
- package/src/bootstrap-peer-store.ts +172 -172
- package/src/cadre-node.ts +5158 -4771
- package/src/canonical-json.ts +30 -30
- package/src/control-authorization.ts +114 -114
- package/src/control-cohort.ts +130 -103
- package/src/control-database.ts +2406 -2506
- package/src/control-formation-recorder.ts +305 -304
- package/src/control-schema.ts +801 -786
- package/src/control-stream.ts +205 -205
- package/src/control-write-retry.ts +483 -473
- package/src/delegate-admission.ts +302 -302
- package/src/device-token.ts +94 -94
- package/src/diagnostics/connection-path.ts +277 -277
- package/src/diagnostics/webrtc-turn-tracker.ts +222 -222
- package/src/ed25519-key.ts +134 -134
- package/src/enrollment.ts +199 -199
- package/src/file-durable-slot.ts +61 -61
- package/src/formation-approval.ts +604 -604
- package/src/fs-atomic.ts +107 -107
- package/src/hibernation-manager.ts +437 -437
- package/src/identity-key.ts +109 -109
- package/src/index.ts +1 -0
- package/src/key-store-file.ts +132 -132
- package/src/key-store.ts +99 -99
- package/src/membership-connection-gater.ts +204 -204
- package/src/node-local-snapshot.ts +260 -260
- package/src/peer-addr-book.ts +250 -0
- package/src/peer-authorization.ts +259 -259
- package/src/peer-record.ts +164 -164
- package/src/push-credentials.ts +84 -84
- package/src/push-node.ts +64 -64
- package/src/push-notifier-apns.ts +247 -247
- package/src/push-notifier-fcm.ts +220 -220
- package/src/push-notifier-shared.ts +28 -28
- package/src/push-notifier.ts +52 -52
- package/src/relay-addrs.ts +111 -111
- package/src/relay-reservation.ts +823 -823
- package/src/seed-bootstrap.ts +15 -15
- package/src/seed-trust-policy.ts +140 -140
- package/src/strand-addr-protocol.ts +441 -441
- package/src/strand-backfill.ts +366 -366
- package/src/strand-cohort.ts +38 -77
- package/src/strand-database.ts +202 -204
- package/src/strand-formation-manager.ts +491 -494
- package/src/strand-formation-protocol.ts +692 -692
- package/src/strand-instance-manager.ts +108 -50
- package/src/strand-member-key.ts +39 -39
- package/src/strand-member-registry.ts +182 -182
- package/src/strand-membership-writer.ts +1432 -1430
- package/src/strand-solicitation.ts +472 -472
- package/src/strand-transport-key.ts +58 -58
- package/src/strand-wake-payload.ts +32 -32
- package/src/strand-wake-protocol.ts +314 -314
- package/src/strand-watcher.ts +314 -314
- package/src/trusted-owner-store-file.ts +41 -41
- package/src/trusted-owner-store.ts +171 -171
- package/src/types.ts +1309 -1303
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-schema.js","sourceRoot":"","sources":["../src/control-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG
|
|
1
|
+
{"version":3,"file":"control-schema.js","sourceRoot":"","sources":["../src/control-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAqxBH,CAAC"}
|
|
@@ -67,8 +67,7 @@ export declare const CONTROL_WRITE_RETRY_BUDGET_MS = 10000;
|
|
|
67
67
|
* re-presenting the SAME signed write a moment later the right response?
|
|
68
68
|
*
|
|
69
69
|
* Classifies by MESSAGE, walking the `cause` chain with Quereus' own {@link unwrapError} —
|
|
70
|
-
* the
|
|
71
|
-
* recognisable by type. The transactor and the coordinator both throw bare `Error`s, and by
|
|
70
|
+
* the failure surface is not recognisable by type. The transactor and the coordinator both throw bare `Error`s, and by
|
|
72
71
|
* the time one reaches `ControlDatabase` it is wrapped in a `QuereusError` (the real chain
|
|
73
72
|
* is `QuereusError` → `Error` → `Error`), so the match must work at any depth. Anything
|
|
74
73
|
* that is not an `Error` is never retried.
|
|
@@ -78,10 +77,12 @@ export declare const CONTROL_WRITE_RETRY_BUDGET_MS = 10000;
|
|
|
78
77
|
* other level looking transient.
|
|
79
78
|
*
|
|
80
79
|
* NOTE: this depends on engine/transactor error TEXT. The messages producible without a
|
|
81
|
-
* network are driven from the REAL engine in `control-formation-
|
|
80
|
+
* network are driven from the REAL engine in `control-formation-seat-budget.spec.ts`, so
|
|
82
81
|
* a rewording reddens a spec rather than silently disabling the retry. The two RETRIABLE
|
|
83
|
-
* messages need a real multi-node cluster to produce
|
|
84
|
-
* `control-write-
|
|
82
|
+
* messages need a real multi-node cluster to produce; the degraded-cohort scenario
|
|
83
|
+
* (`control-write-degraded-cohort-member.integration.ts`) asserts this classifier against
|
|
84
|
+
* both LIVE — the super-majority shortfall from a real silent member, and the transactor
|
|
85
|
+
* aggregate from a real stream reset, which the retry there absorbs end to end.
|
|
85
86
|
*/
|
|
86
87
|
export declare function isRetriableControlWriteFailure(error: unknown): boolean;
|
|
87
88
|
/**
|
|
@@ -114,6 +115,15 @@ export interface ControlWriteRetryOptions {
|
|
|
114
115
|
* {@link isRetriableSchemaInitFailure}, via {@link SCHEMA_INIT_RETRY_POLICY}.
|
|
115
116
|
*/
|
|
116
117
|
isRetriable?: (error: unknown) => boolean;
|
|
118
|
+
/**
|
|
119
|
+
* Operation label stamped into every log line this loop emits (rendered as
|
|
120
|
+
* `Control write [<label>] …`), and NOTHING else — no behavioural effect. The debug
|
|
121
|
+
* log is the only surface where the loop's decisions are observable (the rethrown
|
|
122
|
+
* error is unchanged and no attempt counter is exposed), and several writes retry
|
|
123
|
+
* CONCURRENTLY in a real party, so an unlabelled line cannot be attributed to a
|
|
124
|
+
* write. The degraded-cohort scenario asserts on these lines per-operation.
|
|
125
|
+
*/
|
|
126
|
+
label?: string;
|
|
117
127
|
/** The sleep primitive. Default: `setTimeout`. */
|
|
118
128
|
sleep?: (ms: number) => Promise<void>;
|
|
119
129
|
/** Clock for the elapsed-budget check. Default: `Date.now`. */
|
|
@@ -146,9 +146,10 @@ const SUPER_MAJORITY_SHORTFALL_UNANSWERED = /Failed to get super-majority: \d+\/
|
|
|
146
146
|
* NOTE: the discriminator is a formatting detail of another repo. If Optimystic ever reformats
|
|
147
147
|
* those per-batch details, this fails CLOSED — the aggregate stops matching and control writes
|
|
148
148
|
* simply stop being retried, silently losing the absorption rather than doing anything unsafe.
|
|
149
|
-
* The guard against that is
|
|
150
|
-
*
|
|
151
|
-
* reformat is the first thing to
|
|
149
|
+
* The guard against that is live: `control-write-degraded-cohort-member.integration.ts` asserts
|
|
150
|
+
* this classifier against the real degraded-cohort failure object and asserts the `[block:`
|
|
151
|
+
* token on the live aggregate; if it reddens there, an upstream reformat is the first thing to
|
|
152
|
+
* check.
|
|
152
153
|
*
|
|
153
154
|
* An aggregate whose details came out EMPTY (possible when `formatBatchStatuses` has no
|
|
154
155
|
* batches to format) carries neither token, matches nothing here, and is not retried — an
|
|
@@ -226,9 +227,8 @@ function chainMessages(error) {
|
|
|
226
227
|
*
|
|
227
228
|
* Deliberately NOT matched: every constraint / authorization failure
|
|
228
229
|
* (`CHECK constraint failed:`, `UNIQUE constraint failed:`) — those reach the same funnel
|
|
229
|
-
* and must be retried zero times
|
|
230
|
-
*
|
|
231
|
-
* classifier and that one are DISJOINT and the two retry loops can never multiply.
|
|
230
|
+
* and must be retried zero times: the cohort REFUSED the write, so re-presenting it
|
|
231
|
+
* re-presents a spent signature and can never commit.
|
|
232
232
|
*/
|
|
233
233
|
const RETRIABLE_CONTROL_WRITE_MATCHERS = [
|
|
234
234
|
isUncommittedTransactorAggregate,
|
|
@@ -261,8 +261,7 @@ const RETRIABLE_SCHEMA_INIT_MATCHERS = [
|
|
|
261
261
|
* re-presenting the SAME signed write a moment later the right response?
|
|
262
262
|
*
|
|
263
263
|
* Classifies by MESSAGE, walking the `cause` chain with Quereus' own {@link unwrapError} —
|
|
264
|
-
* the
|
|
265
|
-
* recognisable by type. The transactor and the coordinator both throw bare `Error`s, and by
|
|
264
|
+
* the failure surface is not recognisable by type. The transactor and the coordinator both throw bare `Error`s, and by
|
|
266
265
|
* the time one reaches `ControlDatabase` it is wrapped in a `QuereusError` (the real chain
|
|
267
266
|
* is `QuereusError` → `Error` → `Error`), so the match must work at any depth. Anything
|
|
268
267
|
* that is not an `Error` is never retried.
|
|
@@ -272,10 +271,12 @@ const RETRIABLE_SCHEMA_INIT_MATCHERS = [
|
|
|
272
271
|
* other level looking transient.
|
|
273
272
|
*
|
|
274
273
|
* NOTE: this depends on engine/transactor error TEXT. The messages producible without a
|
|
275
|
-
* network are driven from the REAL engine in `control-formation-
|
|
274
|
+
* network are driven from the REAL engine in `control-formation-seat-budget.spec.ts`, so
|
|
276
275
|
* a rewording reddens a spec rather than silently disabling the retry. The two RETRIABLE
|
|
277
|
-
* messages need a real multi-node cluster to produce
|
|
278
|
-
* `control-write-
|
|
276
|
+
* messages need a real multi-node cluster to produce; the degraded-cohort scenario
|
|
277
|
+
* (`control-write-degraded-cohort-member.integration.ts`) asserts this classifier against
|
|
278
|
+
* both LIVE — the super-majority shortfall from a real silent member, and the transactor
|
|
279
|
+
* aggregate from a real stream reset, which the retry there absorbs end to end.
|
|
279
280
|
*/
|
|
280
281
|
export function isRetriableControlWriteFailure(error) {
|
|
281
282
|
return matchesRetriableMessage(error, RETRIABLE_CONTROL_WRITE_MATCHERS);
|
|
@@ -345,6 +346,9 @@ export async function retryControlWrite(attempt, options = {}) {
|
|
|
345
346
|
const isRetriable = options.isRetriable ?? isRetriableControlWriteFailure;
|
|
346
347
|
const sleep = options.sleep ?? defaultSleep;
|
|
347
348
|
const now = options.now ?? Date.now;
|
|
349
|
+
// Empty when unlabelled, so an unlabelled line is byte-identical to what this loop
|
|
350
|
+
// logged before labels existed.
|
|
351
|
+
const tag = options.label ? ` [${options.label}]` : '';
|
|
348
352
|
const start = now();
|
|
349
353
|
let lastError;
|
|
350
354
|
let attemptsMade = 0;
|
|
@@ -353,7 +357,7 @@ export async function retryControlWrite(attempt, options = {}) {
|
|
|
353
357
|
try {
|
|
354
358
|
const result = await attempt();
|
|
355
359
|
if (attemptNumber > 1) {
|
|
356
|
-
log('Control write committed on attempt %d/%d', attemptNumber, attempts);
|
|
360
|
+
log('Control write%s committed on attempt %d/%d', tag, attemptNumber, attempts);
|
|
357
361
|
}
|
|
358
362
|
return result;
|
|
359
363
|
}
|
|
@@ -362,10 +366,7 @@ export async function retryControlWrite(attempt, options = {}) {
|
|
|
362
366
|
// The ONLY trace that this funnel saw a failure and declined it. Without it the
|
|
363
367
|
// log is silent either way, so "the classifier vetoed this one" is
|
|
364
368
|
// indistinguishable from "the retry is not wired into this path at all".
|
|
365
|
-
|
|
366
|
-
// of them — the lost-use-number constraint failures — ARE retried by the OUTER
|
|
367
|
-
// loop (`ControlDatabase.withUseNumberRetry`) that this one nests inside.
|
|
368
|
-
log('Control write failed non-transiently on attempt %d/%d, not retried here: %s', attemptNumber, attempts, error);
|
|
369
|
+
log('Control write%s failed non-transiently on attempt %d/%d, not retried here: %s', tag, attemptNumber, attempts, error);
|
|
369
370
|
throw error;
|
|
370
371
|
}
|
|
371
372
|
lastError = error;
|
|
@@ -377,11 +378,11 @@ export async function retryControlWrite(attempt, options = {}) {
|
|
|
377
378
|
break;
|
|
378
379
|
}
|
|
379
380
|
const delay = jitteredDelay(delays, attemptNumber);
|
|
380
|
-
log('Control write failed transiently (attempt %d/%d), retrying in %d ms: %s', attemptNumber, attempts, delay, error);
|
|
381
|
+
log('Control write%s failed transiently (attempt %d/%d), retrying in %d ms: %s', tag, attemptNumber, attempts, delay, error);
|
|
381
382
|
await sleep(delay);
|
|
382
383
|
}
|
|
383
384
|
}
|
|
384
|
-
log('Control write failed after %d/%d attempt(s): %s', attemptsMade, attempts, lastError);
|
|
385
|
+
log('Control write%s failed after %d/%d attempt(s): %s', tag, attemptsMade, attempts, lastError);
|
|
385
386
|
throw lastError;
|
|
386
387
|
}
|
|
387
388
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-write-retry.js","sourceRoot":"","sources":["../src/control-write-retry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,MAAM,GAAG,GAAG,KAAK,CAAC,yBAAyB,CAAC,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAExC;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAEtC;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,KAAM,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,6BAA6B,GAAsB,CAAC,GAAG,EAAE,IAAK,CAAC,CAAC;AAEtE;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,2BAA2B,GAAsB,CAAC,GAAG,EAAE,GAAG,EAAE,IAAK,EAAE,IAAK,CAAC,CAAC;AAEhF,+FAA+F;AAC/F,MAAM,oBAAoB,GAAG,8BAA8B,CAAC;AAE5D;;;GAGG;AACH,MAAM,wBAAwB,GAAG,SAAS,CAAC;AAE3C;;;GAGG;AACH,MAAM,kBAAkB,GAAG,UAAU,CAAC;AAEtC;;;;;;;;GAQG;AACH,MAAM,mCAAmC,GACxC,+EAA+E,CAAC;AAEjF
|
|
1
|
+
{"version":3,"file":"control-write-retry.js","sourceRoot":"","sources":["../src/control-write-retry.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export { STRAND_WAKE_TYPE, type StrandWakePayload } from './strand-wake-payload.
|
|
|
34
34
|
export type { PushNotifier, PushMessage, PushSendResult } from './push-notifier.js';
|
|
35
35
|
export { validatePushCredentials, redactPushCredentials, REDACTED } from './push-credentials.js';
|
|
36
36
|
export { PushFanoutService, DEFAULT_PUSH_COOLDOWN_MS, DEFAULT_PUSH_DEBOUNCE_MS, type PushFanoutOptions, type FanoutMember } from './push-fanout.js';
|
|
37
|
-
export { selectControlCohortDials, DEFAULT_CONTROL_COHORT_RECONCILE_MS, DEFAULT_CONTROL_COHORT_TARGET_DEGREE, type ControlCohortSelection } from './control-cohort.js';
|
|
37
|
+
export { selectControlCohortDials, DEFAULT_CONTROL_COHORT_DIAL_TIMEOUT_MS, DEFAULT_CONTROL_COHORT_RECONCILE_MS, DEFAULT_CONTROL_COHORT_TARGET_DEGREE, type ControlCohortSelection } from './control-cohort.js';
|
|
38
38
|
export { anchoredTrustPolicy, pinnedKeyTrustPolicy, tofuTrustPolicy, type SeedTrustPolicy, type SeedTrustContext, type SeedTrustDecision } from './seed-trust-policy.js';
|
|
39
39
|
export { signSchema, verifySchema, assertSchemaSignature, SchemaVerificationError } from './schema-verification.js';
|
|
40
40
|
export { FormationListener, dialFormation, isValidResponderCreatesResult, FORMATION_PROTOCOL, type FormationParty, type FormationContactMessage, type FormationResultMessage, type FormationProvisionResult, type FormationStrandInfo, type FormationDbConnectionInfo, type FormationListenerOptions, type FormationDialOptions, type ResponderProvisionOutcome } from './strand-formation-protocol.js';
|
package/dist/index.js
CHANGED
|
@@ -96,7 +96,7 @@ export { validatePushCredentials, redactPushCredentials, REDACTED } from './push
|
|
|
96
96
|
export { PushFanoutService, DEFAULT_PUSH_COOLDOWN_MS, DEFAULT_PUSH_DEBOUNCE_MS } from './push-fanout.js';
|
|
97
97
|
// Control-cohort dial selection (backbone-preferential, bounded out-degree) +
|
|
98
98
|
// the cadence/degree defaults the proactive reconcile routine reads.
|
|
99
|
-
export { selectControlCohortDials, DEFAULT_CONTROL_COHORT_RECONCILE_MS, DEFAULT_CONTROL_COHORT_TARGET_DEGREE } from './control-cohort.js';
|
|
99
|
+
export { selectControlCohortDials, DEFAULT_CONTROL_COHORT_DIAL_TIMEOUT_MS, DEFAULT_CONTROL_COHORT_RECONCILE_MS, DEFAULT_CONTROL_COHORT_TARGET_DEGREE } from './control-cohort.js';
|
|
100
100
|
// Seed trust policy (trust anchor for incoming seeds)
|
|
101
101
|
export { anchoredTrustPolicy, pinnedKeyTrustPolicy, tofuTrustPolicy } from './seed-trust-policy.js';
|
|
102
102
|
// Schema Verification
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,cAAc,YAAY,CAAC;AAE3B,+DAA+D;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,uBAAuB;AACvB,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,mBAAmB;AACnB,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,eAAe,EAAoM,MAAM,uBAAuB,CAAC;AAE9W,+EAA+E;AAC/E,qFAAqF;AACrF,yCAAyC;AACzC,OAAO,EACL,sBAAsB,EACtB,6BAA6B,EAC7B,oBAAoB,EACpB,wBAAwB,EACxB,8BAA8B,EAC9B,4BAA4B,EAC5B,iBAAiB,EAElB,MAAM,0BAA0B,CAAC;AAElC,2FAA2F;AAC3F,OAAO,EAAE,0BAA0B,EAA0C,MAAM,4BAA4B,CAAC;AAEhH,2DAA2D;AAC3D,OAAO,EAAE,wBAAwB,EAAE,2BAA2B,EAAE,0BAA0B,EAAuB,MAAM,kBAAkB,CAAC;AAE1I,2EAA2E;AAC3E,gFAAgF;AAChF,8EAA8E;AAC9E,+EAA+E;AAC/E,2BAA2B;AAC3B,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,uBAAuB,EAGxB,MAAM,gBAAgB,CAAC;AAExB,8EAA8E;AAC9E,8EAA8E;AAC9E,gFAAgF;AAChF,OAAO,EACL,uBAAuB,EACvB,aAAa,EAEd,MAAM,mBAAmB,CAAC;AAE3B,2EAA2E;AAC3E,+EAA+E;AAC/E,2EAA2E;AAC3E,6CAA6C;AAC7C,mEAAmE;AACnE,wDAAwD;AACxD,OAAO,EACL,uBAAuB,EACvB,2BAA2B,EAG5B,MAAM,0BAA0B,CAAC;AAQlC,gFAAgF;AAChF,gFAAgF;AAChF,iFAAiF;AACjF,8EAA8E;AAC9E,kDAAkD;AAClD,OAAO,EACL,wBAAwB,EACxB,4BAA4B,EAG7B,MAAM,2BAA2B,CAAC;AAEnC,kBAAkB;AAClB,OAAO,EAAE,cAAc,EAA6B,MAAM,sBAAsB,CAAC;AAEjF,oBAAoB;AACpB,OAAO,EACL,aAAa,EAKd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,qBAAqB,EAGrB,oBAAoB,EACrB,MAAM,8BAA8B,CAAC;AAEtC,+EAA+E;AAC/E,6EAA6E;AAC7E,OAAO,EACL,cAAc,EACd,uBAAuB,EACvB,uBAAuB,EAKxB,MAAM,sBAAsB,CAAC;AAE9B,cAAc;AACd,OAAO,EACL,kBAAkB,EAEnB,MAAM,0BAA0B,CAAC;AAElC,mBAAmB;AACnB,OAAO,EACL,aAAa,EACb,mBAAmB,EAEpB,MAAM,qBAAqB,CAAC;AAE7B,aAAa;AACb,OAAO,EACL,iBAAiB,EAGlB,MAAM,iBAAiB,CAAC;AAEzB,sBAAsB;AACtB,OAAO,EACL,yBAAyB,EACzB,uCAAuC,EAOxC,MAAM,0BAA0B,CAAC;AAElC,wFAAwF;AACxF,yFAAyF;AACzF,OAAO,EACL,2BAA2B,EAC3B,qBAAqB,EACrB,uBAAuB,EACvB,sBAAsB,EAMvB,MAAM,yBAAyB,CAAC;AAEjC,+EAA+E;AAC/E,OAAO,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAC;AAEhF,uEAAuE;AACvE,2EAA2E;AAC3E,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAEtF,4EAA4E;AAC5E,8EAA8E;AAC9E,uCAAuC;AACvC,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EACrB,0BAA0B,EAC1B,WAAW,EACX,aAAa,EACb,YAAY,EACZ,sBAAsB,EACtB,kBAAkB,EAClB,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,aAAa,EACb,aAAa,EACb,qBAAqB,EAiBtB,MAAM,+BAA+B,CAAC;AAEvC,kFAAkF;AAClF,kFAAkF;AAClF,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,wEAAwE;AACxE,sEAAsE;AACtE,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,yBAAyB,EAE1B,MAAM,6BAA6B,CAAC;AAErC,iBAAiB;AACjB,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,6BAA6B,EAG9B,MAAM,qBAAqB,CAAC;AAE7B,wEAAwE;AACxE,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,EAEvB,MAAM,yBAAyB,CAAC;AAEjC,mDAAmD;AACnD,OAAO,EACL,iBAAiB,EACjB,QAAQ,EACR,aAAa,EAGd,MAAM,2BAA2B,CAAC;AAEnC,4EAA4E;AAC5E,yEAAyE;AACzE,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EAIrB,MAAM,2BAA2B,CAAC;AAEnC,gFAAgF;AAChF,OAAO,EACL,uBAAuB,EACvB,cAAc,EACd,yBAAyB,EACzB,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,wBAAwB,EACxB,8BAA8B,EAC9B,gCAAgC,EACjC,MAAM,kBAAkB,CAAC;AAE1B,uFAAuF;AACvF,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,0BAA0B,EAC1B,cAAc,EACf,MAAM,mBAAmB,CAAC;AAE3B,sFAAsF;AACtF,OAAO,EAAE,gBAAgB,EAA0B,MAAM,0BAA0B,CAAC;AAWpF,mFAAmF;AACnF,iFAAiF;AACjF,iFAAiF;AACjF,OAAO,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjG,oFAAoF;AACpF,gFAAgF;AAChF,wEAAwE;AACxE,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,wBAAwB,EAGzB,MAAM,kBAAkB,CAAC;AAE1B,8EAA8E;AAC9E,qEAAqE;AACrE,OAAO,EACL,wBAAwB,EACxB,mCAAmC,EACnC,oCAAoC,EAErC,MAAM,qBAAqB,CAAC;AAE7B,sDAAsD;AACtD,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,eAAe,EAIhB,MAAM,wBAAwB,CAAC;AAEhC,sBAAsB;AACtB,OAAO,EACL,UAAU,EACV,YAAY,EACZ,qBAAqB,EACrB,uBAAuB,EACxB,MAAM,0BAA0B,CAAC;AAElC,0DAA0D;AAC1D,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,6BAA6B,EAC7B,kBAAkB,EAUnB,MAAM,gCAAgC,CAAC;AAExC,yDAAyD;AACzD,OAAO,EACL,sBAAsB,EACtB,4BAA4B,EAG7B,MAAM,+BAA+B,CAAC;AAEvC,wEAAwE;AACxE,OAAO,EACL,+BAA+B,EAC/B,uBAAuB,EACvB,4BAA4B,EAC5B,6BAA6B,EAE9B,MAAM,kCAAkC,CAAC;AAE1C,4EAA4E;AAC5E,+EAA+E;AAC/E,OAAO,EACL,iBAAiB,EACjB,yBAAyB,EACzB,gCAAgC,EAChC,6BAA6B,EAC7B,sBAAsB,EACtB,4BAA4B,EAC5B,4BAA4B,EAM7B,MAAM,wBAAwB,CAAC;AAEhC,2EAA2E;AAC3E,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,wBAAwB,EACxB,0BAA0B,EAC1B,wBAAwB,EAMzB,MAAM,kCAAkC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merging verified cadre addresses into a libp2p node's **address book** (its
|
|
3
|
+
* peerStore), so that every layer below cadre-core which dials by bare peer id
|
|
4
|
+
* — Optimystic's cluster client, repo client, FRET ping/announce, all funnelling
|
|
5
|
+
* into `libp2p.dialProtocol(peerId, …)` — has an address to use for a sibling
|
|
6
|
+
* whose connection has dropped, instead of failing with `NoValidAddressesError`
|
|
7
|
+
* until the next reconcile pass happens to re-dial it.
|
|
8
|
+
*
|
|
9
|
+
* Shared by the control-cohort reconcile pass and the strand one (both in
|
|
10
|
+
* `CadreNode`): each resolves a peer's addresses its own way and then needs
|
|
11
|
+
* exactly this write, with exactly this workaround.
|
|
12
|
+
*
|
|
13
|
+
* Two exports, in the order a caller uses them: {@link groupAddrsByPeerId} turns
|
|
14
|
+
* a flat address list into per-peer groups (the strand path starts from the
|
|
15
|
+
* peer-agnostic union the strand-addr RPC returns), and {@link mergePeerAddrs}
|
|
16
|
+
* writes one peer's group.
|
|
17
|
+
*/
|
|
18
|
+
import type { PeerId, PeerStore } from '@libp2p/interface';
|
|
19
|
+
import { type Multiaddr } from '@multiformats/multiaddr';
|
|
20
|
+
/** Outcome of one address-book merge, for logging and tests. */
|
|
21
|
+
export type MergeAddrsResult = 'merged' | 'restamped' | 'skipped' | 'failed';
|
|
22
|
+
/**
|
|
23
|
+
* The slice of a libp2p node {@link mergePeerAddrs} touches. Structurally
|
|
24
|
+
* satisfied by `Libp2p`; narrow so a caller (or a test) can pass a bare
|
|
25
|
+
* peerStore holder.
|
|
26
|
+
*/
|
|
27
|
+
export interface PeerAddrBookHost {
|
|
28
|
+
peerStore: PeerStore;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Write `addrs` into `host`'s address book for `peerId`, best-effort. `peerId`
|
|
32
|
+
* may be the string form callers hold (a `CadrePeer.PeerId` column, a strand-addr
|
|
33
|
+
* RPC result); parsing it is part of the best-effort contract below, so no caller
|
|
34
|
+
* has to wrap this in a second try/catch of its own.
|
|
35
|
+
*
|
|
36
|
+
* - **Empty `addrs` writes nothing** and reports `'skipped'`. That is how a
|
|
37
|
+
* revoked / stale / untrusted peer's existing entry is allowed to age out on
|
|
38
|
+
* its own: the caller resolves `[]` for it, and nothing here refreshes it.
|
|
39
|
+
* - Otherwise the addresses are merged, and — see the timestamp trap below —
|
|
40
|
+
* re-saved when the merge alone leaves them invisible (`'restamped'`).
|
|
41
|
+
* - Any throw (unparsable peer id, datastore failure, a peerStore double without
|
|
42
|
+
* `merge`) is logged and folded to `'failed'`. Callers are best-effort loops:
|
|
43
|
+
* an address-book failure must never abort a reconcile pass.
|
|
44
|
+
*
|
|
45
|
+
* NOTE: `peerStore.merge` cannot refresh an address's `observed` timestamp in
|
|
46
|
+
* `@libp2p/peer-store` 12.0.10 — `to-peer-pb.js` shadows its own loop variable
|
|
47
|
+
* (`…addresses?.find(addr => uint8ArrayEquals(addr.multiaddr, addr.multiaddr))`,
|
|
48
|
+
* always true, so it returns the FIRST stored address's timestamp), and every
|
|
49
|
+
* read filters out addresses older than `MAX_ADDRESS_AGE` (1 hour). So an entry
|
|
50
|
+
* silently dies at the one-hour mark and no amount of re-merging revives it —
|
|
51
|
+
* not even merging a brand-new address. The `save` below is the workaround:
|
|
52
|
+
* `save` is the one write path that omits `existingPeer` and therefore stamps
|
|
53
|
+
* `Date.now()`. Drop it once upstream stamps `Date.now()` on merge.
|
|
54
|
+
*
|
|
55
|
+
* NOTE: raising the store's own `maxAddressAge` (libp2p forwards `init.peerStore`
|
|
56
|
+
* straight into `persistentPeerStore`) would sidestep the bug in one line, and is
|
|
57
|
+
* deliberately NOT done: expiry is load-bearing here. Only *verified* addresses
|
|
58
|
+
* come through this helper, and the design relies on everything else — the
|
|
59
|
+
* cold-start seed entries, identify-learned addresses — still ageing out on the
|
|
60
|
+
* stock schedule. A global age bump would keep those alive too.
|
|
61
|
+
*
|
|
62
|
+
* NOTE: if the store ever REJECTS an address we hand it, the restamp repeats
|
|
63
|
+
* every pass forever — `allVisible` stays false, and `save` re-submits the same
|
|
64
|
+
* rejected address. libp2p wires the store's `addressFilter` to
|
|
65
|
+
* `connectionGater.filterMultiaddrForPeer`, which nothing in this repo implements
|
|
66
|
+
* today (`createMembershipConnectionGater` gates dials, not addresses), so the
|
|
67
|
+
* loop is unreachable. If an app ever supplies that gater hook via
|
|
68
|
+
* `NetworkConfig.connectionGater`, bound the retry — the cost is one redundant
|
|
69
|
+
* datastore write per gated sibling per reconcile pass.
|
|
70
|
+
*/
|
|
71
|
+
export declare function mergePeerAddrs(host: PeerAddrBookHost, peerId: PeerId | string, addrs: Multiaddr[]): Promise<MergeAddrsResult>;
|
|
72
|
+
/**
|
|
73
|
+
* Group multiaddr strings by the peer id in their final `/p2p/` component — the
|
|
74
|
+
* attribution step between a flat, peer-agnostic address list and the per-peer
|
|
75
|
+
* writes {@link mergePeerAddrs} takes.
|
|
76
|
+
*
|
|
77
|
+
* The **last** `/p2p/` component is the addressed peer, not the first: a relayed
|
|
78
|
+
* address (`…/p2p/<relay>/p2p-circuit/p2p/<dst>`) names the relay first and the
|
|
79
|
+
* destination last, while a direct address (`…/tcp/…/p2p/<dst>`) names only the
|
|
80
|
+
* destination. Taking the last therefore attributes both shapes to the peer the
|
|
81
|
+
* address actually reaches.
|
|
82
|
+
*
|
|
83
|
+
* Three shapes are dropped rather than attributed, because none of them names a
|
|
84
|
+
* peer the address reaches: one that does not parse, one carrying no `/p2p/`
|
|
85
|
+
* component at all (a peer advertising a bare listen addr), and one whose
|
|
86
|
+
* `p2p-circuit` comes AFTER its last `/p2p/` (`…/p2p/<relay>/p2p-circuit`) — that
|
|
87
|
+
* last one is a relay hop with the destination missing, so its trailing peer id
|
|
88
|
+
* is the RELAY's and filing it under the relay would claim the relay is reachable
|
|
89
|
+
* at a circuit leading nowhere. Duplicates collapse within a group. Insertion
|
|
90
|
+
* order is preserved, both between groups and inside one.
|
|
91
|
+
*/
|
|
92
|
+
export declare function groupAddrsByPeerId(addrs: string[]): Map<string, Multiaddr[]>;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merging verified cadre addresses into a libp2p node's **address book** (its
|
|
3
|
+
* peerStore), so that every layer below cadre-core which dials by bare peer id
|
|
4
|
+
* — Optimystic's cluster client, repo client, FRET ping/announce, all funnelling
|
|
5
|
+
* into `libp2p.dialProtocol(peerId, …)` — has an address to use for a sibling
|
|
6
|
+
* whose connection has dropped, instead of failing with `NoValidAddressesError`
|
|
7
|
+
* until the next reconcile pass happens to re-dial it.
|
|
8
|
+
*
|
|
9
|
+
* Shared by the control-cohort reconcile pass and the strand one (both in
|
|
10
|
+
* `CadreNode`): each resolves a peer's addresses its own way and then needs
|
|
11
|
+
* exactly this write, with exactly this workaround.
|
|
12
|
+
*
|
|
13
|
+
* Two exports, in the order a caller uses them: {@link groupAddrsByPeerId} turns
|
|
14
|
+
* a flat address list into per-peer groups (the strand path starts from the
|
|
15
|
+
* peer-agnostic union the strand-addr RPC returns), and {@link mergePeerAddrs}
|
|
16
|
+
* writes one peer's group.
|
|
17
|
+
*/
|
|
18
|
+
import debug from 'debug';
|
|
19
|
+
import { peerIdFromString } from '@libp2p/peer-id';
|
|
20
|
+
import { multiaddr, CODE_P2P, CODE_P2P_CIRCUIT } from '@multiformats/multiaddr';
|
|
21
|
+
const log = debug('sereus:cadre:peer-addr-book');
|
|
22
|
+
/**
|
|
23
|
+
* Write `addrs` into `host`'s address book for `peerId`, best-effort. `peerId`
|
|
24
|
+
* may be the string form callers hold (a `CadrePeer.PeerId` column, a strand-addr
|
|
25
|
+
* RPC result); parsing it is part of the best-effort contract below, so no caller
|
|
26
|
+
* has to wrap this in a second try/catch of its own.
|
|
27
|
+
*
|
|
28
|
+
* - **Empty `addrs` writes nothing** and reports `'skipped'`. That is how a
|
|
29
|
+
* revoked / stale / untrusted peer's existing entry is allowed to age out on
|
|
30
|
+
* its own: the caller resolves `[]` for it, and nothing here refreshes it.
|
|
31
|
+
* - Otherwise the addresses are merged, and — see the timestamp trap below —
|
|
32
|
+
* re-saved when the merge alone leaves them invisible (`'restamped'`).
|
|
33
|
+
* - Any throw (unparsable peer id, datastore failure, a peerStore double without
|
|
34
|
+
* `merge`) is logged and folded to `'failed'`. Callers are best-effort loops:
|
|
35
|
+
* an address-book failure must never abort a reconcile pass.
|
|
36
|
+
*
|
|
37
|
+
* NOTE: `peerStore.merge` cannot refresh an address's `observed` timestamp in
|
|
38
|
+
* `@libp2p/peer-store` 12.0.10 — `to-peer-pb.js` shadows its own loop variable
|
|
39
|
+
* (`…addresses?.find(addr => uint8ArrayEquals(addr.multiaddr, addr.multiaddr))`,
|
|
40
|
+
* always true, so it returns the FIRST stored address's timestamp), and every
|
|
41
|
+
* read filters out addresses older than `MAX_ADDRESS_AGE` (1 hour). So an entry
|
|
42
|
+
* silently dies at the one-hour mark and no amount of re-merging revives it —
|
|
43
|
+
* not even merging a brand-new address. The `save` below is the workaround:
|
|
44
|
+
* `save` is the one write path that omits `existingPeer` and therefore stamps
|
|
45
|
+
* `Date.now()`. Drop it once upstream stamps `Date.now()` on merge.
|
|
46
|
+
*
|
|
47
|
+
* NOTE: raising the store's own `maxAddressAge` (libp2p forwards `init.peerStore`
|
|
48
|
+
* straight into `persistentPeerStore`) would sidestep the bug in one line, and is
|
|
49
|
+
* deliberately NOT done: expiry is load-bearing here. Only *verified* addresses
|
|
50
|
+
* come through this helper, and the design relies on everything else — the
|
|
51
|
+
* cold-start seed entries, identify-learned addresses — still ageing out on the
|
|
52
|
+
* stock schedule. A global age bump would keep those alive too.
|
|
53
|
+
*
|
|
54
|
+
* NOTE: if the store ever REJECTS an address we hand it, the restamp repeats
|
|
55
|
+
* every pass forever — `allVisible` stays false, and `save` re-submits the same
|
|
56
|
+
* rejected address. libp2p wires the store's `addressFilter` to
|
|
57
|
+
* `connectionGater.filterMultiaddrForPeer`, which nothing in this repo implements
|
|
58
|
+
* today (`createMembershipConnectionGater` gates dials, not addresses), so the
|
|
59
|
+
* loop is unreachable. If an app ever supplies that gater hook via
|
|
60
|
+
* `NetworkConfig.connectionGater`, bound the retry — the cost is one redundant
|
|
61
|
+
* datastore write per gated sibling per reconcile pass.
|
|
62
|
+
*/
|
|
63
|
+
export async function mergePeerAddrs(host, peerId, addrs) {
|
|
64
|
+
if (addrs.length === 0) {
|
|
65
|
+
return 'skipped';
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
const id = typeof peerId === 'string' ? peerIdFromString(peerId) : peerId;
|
|
69
|
+
const peer = await host.peerStore.merge(id, { multiaddrs: addrs });
|
|
70
|
+
// The returned Peer is already expiry-filtered, so it says whether the merge
|
|
71
|
+
// is actually VISIBLE — which is the only question that matters downstream.
|
|
72
|
+
if (allVisible(peer.addresses, addrs, id)) {
|
|
73
|
+
return 'merged';
|
|
74
|
+
}
|
|
75
|
+
await host.peerStore.save(id, restampData(peer, addrs, id));
|
|
76
|
+
return 'restamped';
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
log('mergePeerAddrs: address-book write for %s failed: %o', peerId.toString(), error);
|
|
80
|
+
return 'failed';
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Group multiaddr strings by the peer id in their final `/p2p/` component — the
|
|
85
|
+
* attribution step between a flat, peer-agnostic address list and the per-peer
|
|
86
|
+
* writes {@link mergePeerAddrs} takes.
|
|
87
|
+
*
|
|
88
|
+
* The **last** `/p2p/` component is the addressed peer, not the first: a relayed
|
|
89
|
+
* address (`…/p2p/<relay>/p2p-circuit/p2p/<dst>`) names the relay first and the
|
|
90
|
+
* destination last, while a direct address (`…/tcp/…/p2p/<dst>`) names only the
|
|
91
|
+
* destination. Taking the last therefore attributes both shapes to the peer the
|
|
92
|
+
* address actually reaches.
|
|
93
|
+
*
|
|
94
|
+
* Three shapes are dropped rather than attributed, because none of them names a
|
|
95
|
+
* peer the address reaches: one that does not parse, one carrying no `/p2p/`
|
|
96
|
+
* component at all (a peer advertising a bare listen addr), and one whose
|
|
97
|
+
* `p2p-circuit` comes AFTER its last `/p2p/` (`…/p2p/<relay>/p2p-circuit`) — that
|
|
98
|
+
* last one is a relay hop with the destination missing, so its trailing peer id
|
|
99
|
+
* is the RELAY's and filing it under the relay would claim the relay is reachable
|
|
100
|
+
* at a circuit leading nowhere. Duplicates collapse within a group. Insertion
|
|
101
|
+
* order is preserved, both between groups and inside one.
|
|
102
|
+
*/
|
|
103
|
+
export function groupAddrsByPeerId(addrs) {
|
|
104
|
+
const groups = new Map();
|
|
105
|
+
const seen = new Set();
|
|
106
|
+
for (const addr of addrs) {
|
|
107
|
+
const attributed = attributeAddr(addr);
|
|
108
|
+
if (!attributed) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const key = `${attributed.peerId}\n${addr}`;
|
|
112
|
+
if (seen.has(key)) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
seen.add(key);
|
|
116
|
+
const group = groups.get(attributed.peerId);
|
|
117
|
+
if (group) {
|
|
118
|
+
group.push(attributed.multiaddr);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
groups.set(attributed.peerId, [attributed.multiaddr]);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return groups;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Parse one address and pull out the peer id it addresses (its last `/p2p/`
|
|
128
|
+
* value); null when the address is unparsable or names no destination. Every case
|
|
129
|
+
* is logged at the same level — an unattributable address is a sibling telling us
|
|
130
|
+
* something we cannot use, which is worth seeing but never worth throwing over.
|
|
131
|
+
*/
|
|
132
|
+
function attributeAddr(addr) {
|
|
133
|
+
let parsed;
|
|
134
|
+
try {
|
|
135
|
+
parsed = multiaddr(addr);
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
log('groupAddrsByPeerId: skipping unparsable addr %s: %o', addr, error);
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
const peerId = lastAddressedPeerId(parsed);
|
|
142
|
+
if (peerId === null) {
|
|
143
|
+
log('groupAddrsByPeerId: skipping addr naming no destination peer: %s', addr);
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
return { peerId, multiaddr: parsed };
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* The peer id a parsed address reaches: its last `/p2p/` value, or null when it
|
|
150
|
+
* has none — or when a `p2p-circuit` sits after it, which makes that value the
|
|
151
|
+
* relay's rather than a destination's (see {@link groupAddrsByPeerId}). Walking
|
|
152
|
+
* backwards, meeting the circuit first is exactly that case.
|
|
153
|
+
*/
|
|
154
|
+
function lastAddressedPeerId(parsed) {
|
|
155
|
+
const components = parsed.getComponents();
|
|
156
|
+
for (let i = components.length - 1; i >= 0; i--) {
|
|
157
|
+
const component = components[i];
|
|
158
|
+
if (component.code === CODE_P2P_CIRCUIT) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
if (component.code === CODE_P2P && component.value) {
|
|
162
|
+
return component.value;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* The peerStore strips a trailing `/p2p/<peerId>` from an address it stores when
|
|
169
|
+
* that id is the address's FIRST `/p2p/` component (`dedupe-addresses.js`), so a
|
|
170
|
+
* plain address round-trips without its suffix while a relayed one — whose first
|
|
171
|
+
* `/p2p/` names the relay — keeps it. Comparing and de-duplicating on this
|
|
172
|
+
* suffix-stripped form matches either shape.
|
|
173
|
+
*/
|
|
174
|
+
function addrKey(addr, peerId) {
|
|
175
|
+
const suffix = `/p2p/${peerId.toString()}`;
|
|
176
|
+
return addr.endsWith(suffix) ? addr.slice(0, -suffix.length) : addr;
|
|
177
|
+
}
|
|
178
|
+
/** Is every address in `addrs` readable back from the stored, expiry-filtered set? */
|
|
179
|
+
function allVisible(stored, addrs, peerId) {
|
|
180
|
+
const keys = new Set(stored.map((a) => addrKey(a.multiaddr.toString(), peerId)));
|
|
181
|
+
return addrs.every((addr) => keys.has(addrKey(addr.toString(), peerId)));
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* The full `save` payload for a restamp: `save` re-uses the `patch` strategy with
|
|
185
|
+
* no existing peer, so every field it is not handed is DROPPED — and Optimystic
|
|
186
|
+
* classifies peers by their peerStore protocol list (`libp2p-key-network.ts`
|
|
187
|
+
* `membershipOf`), so losing protocols here would break cluster/repo routing.
|
|
188
|
+
* Everything therefore carries forward from the just-merged `peer`.
|
|
189
|
+
*
|
|
190
|
+
* The read-modify-write is NOT atomic against a concurrent `identify` write to
|
|
191
|
+
* the same entry. The loss window is milliseconds and costs at most one identify
|
|
192
|
+
* update, recovered by the next identify push — not worth a lock.
|
|
193
|
+
*
|
|
194
|
+
* A tag's remaining TTL is not carried: the public `Tag` type exposes only
|
|
195
|
+
* `value`, so the stored expiry is unreadable from here and the tag comes back
|
|
196
|
+
* non-expiring. `publicKey` is likewise not passed, which is lossless for the
|
|
197
|
+
* Ed25519 peer ids a cadre uses (the key is embedded in the id).
|
|
198
|
+
*/
|
|
199
|
+
function restampData(peer, addrs, peerId) {
|
|
200
|
+
const addresses = new Map();
|
|
201
|
+
for (const address of peer.addresses) {
|
|
202
|
+
addresses.set(addrKey(address.multiaddr.toString(), peerId), address);
|
|
203
|
+
}
|
|
204
|
+
for (const addr of addrs) {
|
|
205
|
+
const key = addrKey(addr.toString(), peerId);
|
|
206
|
+
if (!addresses.has(key)) {
|
|
207
|
+
// Uncertified, matching what `merge`'s own `multiaddrs` path would have
|
|
208
|
+
// stored; an address already present keeps whatever flag it carried.
|
|
209
|
+
addresses.set(key, { multiaddr: addr, isCertified: false });
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return {
|
|
213
|
+
addresses: [...addresses.values()],
|
|
214
|
+
protocols: peer.protocols,
|
|
215
|
+
metadata: new Map(peer.metadata),
|
|
216
|
+
tags: new Map([...peer.tags].map(([name, tag]) => [name, { value: tag.value }])),
|
|
217
|
+
peerRecordEnvelope: peer.peerRecordEnvelope
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=peer-addr-book.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peer-addr-book.js","sourceRoot":"","sources":["../src/peer-addr-book.ts"],"names":[],"mappings":"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"}
|
package/dist/seed-bootstrap.d.ts
CHANGED
|
@@ -454,6 +454,13 @@ export declare class SeedBootstrapService {
|
|
|
454
454
|
* This makes any owner node markable — not just the local one — and ties
|
|
455
455
|
* `isOwner` to the control table rather than to `peerId === self`.
|
|
456
456
|
*
|
|
457
|
+
* Read through {@link ControlDatabase.queryCadrePeers}, not a raw `CadrePeer`
|
|
458
|
+
* select: that reader drops any row whose `StampId` is retired in
|
|
459
|
+
* `CadreControl.Revocation`, so a removed member's addresses are never packed
|
|
460
|
+
* into a seed and pushed into a joiner's peerstore (`applySeed` adds every
|
|
461
|
+
* seed peer's addrs and dials the owner-flagged ones). A revoked peer is off
|
|
462
|
+
* the addressable surface everywhere, and this is one of its exits.
|
|
463
|
+
*
|
|
457
464
|
* NOTE: this is the one owner lookup deliberately left on the REPLICATED
|
|
458
465
|
* table rather than the node-local anchor. `SeedPeer.isOwner` is a dial hint
|
|
459
466
|
* — the receiver dials owner-flagged peers first — not a trust decision, and
|
package/dist/seed-bootstrap.js
CHANGED
|
@@ -251,7 +251,7 @@ export class SeedBootstrapService {
|
|
|
251
251
|
insert into CadreControl.DeviceToken (PeerId, Platform, Token, UpdatedAt, Sig, StampId)
|
|
252
252
|
with context OwnerKey = ?, Signature = ?
|
|
253
253
|
values (?, ?, ?, ?, ?, ?)
|
|
254
|
-
`, [this.ownerPublicKey, signature, record.peerId, record.platform, record.token, record.updatedAt, record.sig, stampId]);
|
|
254
|
+
`, [this.ownerPublicKey, signature, record.peerId, record.platform, record.token, record.updatedAt, record.sig, stampId], 'device-token-insert');
|
|
255
255
|
log('Device token inserted (owner-signed): %s', record.peerId);
|
|
256
256
|
}
|
|
257
257
|
/**
|
|
@@ -546,8 +546,8 @@ export class SeedBootstrapService {
|
|
|
546
546
|
// `ApplySeedResult.ownerDialsFailed`). Recovery is not this loop's job —
|
|
547
547
|
// `CadreNode.dialColdStartBootstrap` retries these same addresses on every
|
|
548
548
|
// control-cohort reconcile pass until the control database has siblings.
|
|
549
|
-
// `createSeed` projects
|
|
550
|
-
// minted after it joined finds ITSELF in the owner list. Dialing self always
|
|
549
|
+
// `createSeed` projects every non-revoked CadrePeer row, so an owner applying
|
|
550
|
+
// a seed minted after it joined finds ITSELF in the owner list. Dialing self always
|
|
551
551
|
// throws, which would report a healthy owner as "seeded but stranded".
|
|
552
552
|
// Optional-chained: partial libp2p handles (unit-test doubles) omit `peerId`,
|
|
553
553
|
// and an undefined self simply matches nothing.
|
|
@@ -720,6 +720,13 @@ export class SeedBootstrapService {
|
|
|
720
720
|
* This makes any owner node markable — not just the local one — and ties
|
|
721
721
|
* `isOwner` to the control table rather than to `peerId === self`.
|
|
722
722
|
*
|
|
723
|
+
* Read through {@link ControlDatabase.queryCadrePeers}, not a raw `CadrePeer`
|
|
724
|
+
* select: that reader drops any row whose `StampId` is retired in
|
|
725
|
+
* `CadreControl.Revocation`, so a removed member's addresses are never packed
|
|
726
|
+
* into a seed and pushed into a joiner's peerstore (`applySeed` adds every
|
|
727
|
+
* seed peer's addrs and dials the owner-flagged ones). A revoked peer is off
|
|
728
|
+
* the addressable surface everywhere, and this is one of its exits.
|
|
729
|
+
*
|
|
723
730
|
* NOTE: this is the one owner lookup deliberately left on the REPLICATED
|
|
724
731
|
* table rather than the node-local anchor. `SeedPeer.isOwner` is a dial hint
|
|
725
732
|
* — the receiver dials owner-flagged peers first — not a trust decision, and
|
|
@@ -733,25 +740,20 @@ export class SeedBootstrapService {
|
|
|
733
740
|
return [];
|
|
734
741
|
}
|
|
735
742
|
const ownerKeys = await this.controlDatabase.getOwnerKeys();
|
|
736
|
-
const
|
|
737
|
-
|
|
738
|
-
// Query CadrePeer table
|
|
739
|
-
for await (const row of db.eval('select PeerId, Multiaddr from CadreControl.CadrePeer')) {
|
|
740
|
-
const peerId = row.PeerId;
|
|
741
|
-
const multiaddr = row.Multiaddr;
|
|
743
|
+
const rows = await this.controlDatabase.queryCadrePeers();
|
|
744
|
+
return rows.map(({ peerId, multiaddr }) => {
|
|
742
745
|
// Derive the peer's ed25519 key from its PeerId; a non-Ed25519 peer or an
|
|
743
746
|
// unparsable id yields null and is treated as a non-owner rather than
|
|
744
747
|
// failing the whole seed creation.
|
|
745
748
|
const pubKeyB64 = ed25519PublicKeyB64FromPeerId(peerId);
|
|
746
749
|
const isOwner = pubKeyB64 !== null && ownerKeys.has(pubKeyB64);
|
|
747
|
-
|
|
750
|
+
return {
|
|
748
751
|
peerId,
|
|
749
752
|
multiaddrs: multiaddr ? multiaddr.split(',') : [],
|
|
750
753
|
isOwner,
|
|
751
754
|
...(isOwner ? { publicKey: pubKeyB64 } : {}),
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
return peers;
|
|
755
|
+
};
|
|
756
|
+
});
|
|
755
757
|
}
|
|
756
758
|
/**
|
|
757
759
|
* Register the seed protocol handler. The inbound closure just delegates to
|