@optimystic/db-p2p 0.16.3 → 0.18.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/src/cluster/block-transfer-service.d.ts +14 -1
- package/dist/src/cluster/block-transfer-service.d.ts.map +1 -1
- package/dist/src/cluster/block-transfer-service.js +12 -3
- package/dist/src/cluster/block-transfer-service.js.map +1 -1
- package/dist/src/cluster/cluster-policy.d.ts +112 -0
- package/dist/src/cluster/cluster-policy.d.ts.map +1 -0
- package/dist/src/cluster/cluster-policy.js +88 -0
- package/dist/src/cluster/cluster-policy.js.map +1 -0
- package/dist/src/cluster/cluster-repo.d.ts +41 -13
- package/dist/src/cluster/cluster-repo.d.ts.map +1 -1
- package/dist/src/cluster/cluster-repo.js +116 -23
- package/dist/src/cluster/cluster-repo.js.map +1 -1
- package/dist/src/cluster/quorum-restore.d.ts +64 -14
- package/dist/src/cluster/quorum-restore.d.ts.map +1 -1
- package/dist/src/cluster/quorum-restore.js +0 -0
- package/dist/src/cluster/quorum-restore.js.map +1 -1
- package/dist/src/cluster/reconcile-block.d.ts +60 -0
- package/dist/src/cluster/reconcile-block.d.ts.map +1 -0
- package/dist/src/cluster/reconcile-block.js +133 -0
- package/dist/src/cluster/reconcile-block.js.map +1 -0
- package/dist/src/cluster/service.d.ts +4 -1
- package/dist/src/cluster/service.d.ts.map +1 -1
- package/dist/src/cluster/service.js +9 -1
- package/dist/src/cluster/service.js.map +1 -1
- package/dist/src/cluster/spread-on-churn.d.ts.map +1 -1
- package/dist/src/cluster/spread-on-churn.js +8 -0
- package/dist/src/cluster/spread-on-churn.js.map +1 -1
- package/dist/src/inbound-authorization.d.ts +117 -0
- package/dist/src/inbound-authorization.d.ts.map +1 -0
- package/dist/src/inbound-authorization.js +149 -0
- package/dist/src/inbound-authorization.js.map +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/libp2p-key-network.d.ts +14 -0
- package/dist/src/libp2p-key-network.d.ts.map +1 -1
- package/dist/src/libp2p-key-network.js +54 -4
- package/dist/src/libp2p-key-network.js.map +1 -1
- package/dist/src/libp2p-node-base.d.ts +48 -7
- package/dist/src/libp2p-node-base.d.ts.map +1 -1
- package/dist/src/libp2p-node-base.js +61 -83
- package/dist/src/libp2p-node-base.js.map +1 -1
- package/dist/src/repo/cluster-coordinator.d.ts +21 -3
- package/dist/src/repo/cluster-coordinator.d.ts.map +1 -1
- package/dist/src/repo/cluster-coordinator.js +27 -5
- package/dist/src/repo/cluster-coordinator.js.map +1 -1
- package/dist/src/repo/coordinator-repo.d.ts +123 -16
- package/dist/src/repo/coordinator-repo.d.ts.map +1 -1
- package/dist/src/repo/coordinator-repo.js +354 -49
- package/dist/src/repo/coordinator-repo.js.map +1 -1
- package/dist/src/repo/service.d.ts +4 -1
- package/dist/src/repo/service.d.ts.map +1 -1
- package/dist/src/repo/service.js +9 -1
- package/dist/src/repo/service.js.map +1 -1
- package/dist/src/storage/block-storage.d.ts.map +1 -1
- package/dist/src/storage/block-storage.js +11 -0
- package/dist/src/storage/block-storage.js.map +1 -1
- package/dist/src/storage/storage-repo.d.ts +56 -0
- package/dist/src/storage/storage-repo.d.ts.map +1 -1
- package/dist/src/storage/storage-repo.js +155 -13
- package/dist/src/storage/storage-repo.js.map +1 -1
- package/dist/src/sync/service.d.ts +4 -7
- package/dist/src/sync/service.d.ts.map +1 -1
- package/dist/src/sync/service.js +13 -10
- package/dist/src/sync/service.js.map +1 -1
- package/dist/src/testing/mesh-harness.d.ts +10 -0
- package/dist/src/testing/mesh-harness.d.ts.map +1 -1
- package/dist/src/testing/mesh-harness.js +55 -49
- package/dist/src/testing/mesh-harness.js.map +1 -1
- package/package.json +2 -2
- package/{README.md → readme.md} +37 -0
- package/src/cluster/block-transfer-service.ts +20 -5
- package/src/cluster/cluster-policy.ts +152 -0
- package/src/cluster/cluster-repo.ts +121 -26
- package/src/cluster/quorum-restore.ts +0 -0
- package/src/cluster/reconcile-block.ts +191 -0
- package/src/cluster/service.ts +10 -3
- package/src/cluster/spread-on-churn.ts +8 -0
- package/src/inbound-authorization.ts +190 -0
- package/src/index.ts +1 -0
- package/src/libp2p-key-network.ts +54 -4
- package/src/libp2p-node-base.ts +111 -94
- package/src/repo/cluster-coordinator.ts +30 -6
- package/src/repo/coordinator-repo.ts +419 -58
- package/src/repo/service.ts +10 -3
- package/src/storage/block-storage.ts +11 -0
- package/src/storage/storage-repo.ts +172 -15
- package/src/sync/service.ts +14 -12
- package/src/testing/mesh-harness.ts +55 -49
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Startable } from '@libp2p/interface';
|
|
2
2
|
import type { IRepo, PeerId, IPeerNetwork, ActionId, ActionRev, IBlock, BlockId } from '@optimystic/db-core';
|
|
3
3
|
import { ProtocolClient } from '../protocol-client.js';
|
|
4
|
+
import { type InboundStreamAuthorizationInit } from '../inbound-authorization.js';
|
|
4
5
|
export declare const buildBlockTransferProtocol: (protocolPrefix?: string) => string;
|
|
5
6
|
/** Request to transfer blocks */
|
|
6
7
|
export interface BlockTransferRequest {
|
|
@@ -44,7 +45,7 @@ export interface IBlockReplicaStore extends IRepo {
|
|
|
44
45
|
*/
|
|
45
46
|
saveReplicatedBlock(blockId: BlockId, block: IBlock, source?: ActionRev): Promise<void>;
|
|
46
47
|
}
|
|
47
|
-
export interface BlockTransferServiceInit {
|
|
48
|
+
export interface BlockTransferServiceInit extends InboundStreamAuthorizationInit {
|
|
48
49
|
protocolPrefix?: string;
|
|
49
50
|
}
|
|
50
51
|
export interface BlockTransferServiceComponents {
|
|
@@ -53,6 +54,16 @@ export interface BlockTransferServiceComponents {
|
|
|
53
54
|
unhandle: (...args: any[]) => Promise<void>;
|
|
54
55
|
};
|
|
55
56
|
repo: IBlockReplicaStore;
|
|
57
|
+
/**
|
|
58
|
+
* Optional libp2p component logger. Supplied by the node factory so authorization denials
|
|
59
|
+
* land on the same `logger.forComponent(...).error` sink as the repo/cluster/sync services;
|
|
60
|
+
* without it they fall back to this module's `debug` logger.
|
|
61
|
+
*/
|
|
62
|
+
logger?: {
|
|
63
|
+
forComponent: (name: string) => {
|
|
64
|
+
error: (message: string, ...args: unknown[]) => void;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
56
67
|
}
|
|
57
68
|
/**
|
|
58
69
|
* Libp2p service that handles incoming block transfer requests.
|
|
@@ -65,6 +76,8 @@ export declare class BlockTransferService implements Startable {
|
|
|
65
76
|
private readonly protocol;
|
|
66
77
|
private readonly repo;
|
|
67
78
|
private readonly registrar;
|
|
79
|
+
/** Optional embedder authorization gate; `undefined` (the default) means no check runs. */
|
|
80
|
+
private readonly authorization;
|
|
68
81
|
constructor(components: BlockTransferServiceComponents, init?: BlockTransferServiceInit);
|
|
69
82
|
start(): Promise<void>;
|
|
70
83
|
stop(): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-transfer-service.d.ts","sourceRoot":"","sources":["../../../src/cluster/block-transfer-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"block-transfer-service.d.ts","sourceRoot":"","sources":["../../../src/cluster/block-transfer-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,7 @@ import { toString as u8ToString } from 'uint8arrays/to-string';
|
|
|
5
5
|
import { ProtocolClient } from '../protocol-client.js';
|
|
6
6
|
import { MAX_BLOCK_MESSAGE_BYTES } from '../protocol-limits.js';
|
|
7
7
|
import { createLogger } from '../logger.js';
|
|
8
|
+
import { createInboundStreamAuthorization } from '../inbound-authorization.js';
|
|
8
9
|
const log = createLogger('block-transfer-service');
|
|
9
10
|
/** Protocol path */
|
|
10
11
|
const BLOCK_TRANSFER_PREFIX = '/db-p2p/block-transfer/';
|
|
@@ -21,15 +22,19 @@ export class BlockTransferService {
|
|
|
21
22
|
protocol;
|
|
22
23
|
repo;
|
|
23
24
|
registrar;
|
|
25
|
+
/** Optional embedder authorization gate; `undefined` (the default) means no check runs. */
|
|
26
|
+
authorization;
|
|
24
27
|
constructor(components, init = {}) {
|
|
25
28
|
this.protocol = buildBlockTransferProtocol(init.protocolPrefix ?? '');
|
|
26
29
|
this.repo = components.repo;
|
|
27
30
|
this.registrar = components.registrar;
|
|
31
|
+
const componentLog = components.logger?.forComponent('db-p2p:block-transfer');
|
|
32
|
+
this.authorization = createInboundStreamAuthorization(init, this.protocol, componentLog ? (msg, ...args) => componentLog.error(msg, ...args) : (msg, ...args) => log(msg, ...args));
|
|
28
33
|
}
|
|
29
34
|
async start() {
|
|
30
35
|
if (this.running)
|
|
31
36
|
return;
|
|
32
|
-
await this.registrar.handle(this.protocol, async (data) => {
|
|
37
|
+
await this.registrar.handle(this.protocol, async (data, connection) => {
|
|
33
38
|
// libp2p invokes the stream handler with the Stream as the FIRST positional argument
|
|
34
39
|
// (see cluster/repo/dispute services, which all use `(stream, connection)`). The block-
|
|
35
40
|
// transfer handler previously read `data.stream`, which is `undefined` for the positional
|
|
@@ -37,7 +42,7 @@ export class BlockTransferService {
|
|
|
37
42
|
// never replied, and every push/pull dialled this service hung with no response. Unwrap
|
|
38
43
|
// defensively (older shape passed `{ stream }`), mirroring sync/service.ts.
|
|
39
44
|
const stream = data?.stream ?? data;
|
|
40
|
-
await this.handleRequest(stream);
|
|
45
|
+
await this.handleRequest(stream, connection);
|
|
41
46
|
});
|
|
42
47
|
this.running = true;
|
|
43
48
|
log('started on %s', this.protocol);
|
|
@@ -49,9 +54,13 @@ export class BlockTransferService {
|
|
|
49
54
|
this.running = false;
|
|
50
55
|
log('stopped');
|
|
51
56
|
}
|
|
52
|
-
async handleRequest(stream) {
|
|
57
|
+
async handleRequest(stream, connection) {
|
|
53
58
|
const self = this;
|
|
54
59
|
try {
|
|
60
|
+
// Authorization runs before ANY decoding or execution. Guarded on the field so a
|
|
61
|
+
// node without a predicate keeps the original path untouched.
|
|
62
|
+
if (this.authorization && await this.authorization.deny(stream, connection?.remotePeer?.toString()))
|
|
63
|
+
return;
|
|
55
64
|
// Read the request, process it, and write the response on ONE continuous duplex
|
|
56
65
|
// pipe (mirrors cluster/repo/dispute services). The earlier read-to-end-then-write
|
|
57
66
|
// design deadlocked over a real stream: the client sends one length-prefixed request
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-transfer-service.js","sourceRoot":"","sources":["../../../src/cluster/block-transfer-service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC/B,OAAO,KAAK,EAAE,MAAM,oBAAoB,CAAC;AACzC,OAAO,EAAE,UAAU,IAAI,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,QAAQ,IAAI,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"block-transfer-service.js","sourceRoot":"","sources":["../../../src/cluster/block-transfer-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { type ClusterConsensusConfig } from "@optimystic/db-core";
|
|
2
|
+
/**
|
|
3
|
+
* Resolves the operator-facing cluster knobs (`clusterSize`, `clusterPolicy.*`) into the concrete
|
|
4
|
+
* numbers the consensus and block-restoration paths run on.
|
|
5
|
+
*
|
|
6
|
+
* Extracted from `createLibp2pNodeBase` rather than left inline so the composition root's defaults
|
|
7
|
+
* are assertable without booting a libp2p node — the layer a real deployment actually uses, and
|
|
8
|
+
* therefore the layer where a default that relaxed the repair corroboration floor to a single voter
|
|
9
|
+
* survived unnoticed (see `test/cluster-policy.spec.ts`).
|
|
10
|
+
*
|
|
11
|
+
* ## Why two size yardsticks, not one
|
|
12
|
+
*
|
|
13
|
+
* One operator field — `clusterPolicy.assumedClusterSize`, "the smallest cohort this deployment can
|
|
14
|
+
* genuinely field" — feeds two consumers whose failure modes point in opposite directions, so its
|
|
15
|
+
* *default* cannot serve both:
|
|
16
|
+
*
|
|
17
|
+
* - **Membership admission gate** (`cluster/cluster-repo.ts`, `admitMembership`) reads it only on its
|
|
18
|
+
* fallback path, when this node has no confident network-size estimate. Too small: a
|
|
19
|
+
* partition-induced downsize slips past while the node is unconfident. Too large: the node refuses
|
|
20
|
+
* legitimate writes — unavailability. It wants a *permissive* default, because an unconfigured
|
|
21
|
+
* two-node mesh must still be able to transact. It gets {@link minAbsoluteClusterSize} (2).
|
|
22
|
+
* - **Repair corroboration floor** (`corroboratorCapacity` in `cluster/quorum-restore.ts`, called by
|
|
23
|
+
* `CoordinatorRepo.queryClusterForLatest` and `createReconcileBlock`) reads it on *every* repair,
|
|
24
|
+
* unconditionally. Too small: a shrunken — and always unauthenticated — cohort view buys a lone
|
|
25
|
+
* peer full trust. Too large: a block stays unrepaired, degraded rather than dead. It wants a
|
|
26
|
+
* *strict* default. It gets {@link ResolvedClusterPolicy.repairCorroborationClusterSize}, which
|
|
27
|
+
* falls back to `clusterSize` (the configured replication factor).
|
|
28
|
+
*
|
|
29
|
+
* A single explicit `clusterPolicy.assumedClusterSize` still sets BOTH — an operator declaring their
|
|
30
|
+
* real cohort size means it for both consumers. Only the unconfigured case diverges.
|
|
31
|
+
*
|
|
32
|
+
* So a genuine two-node mesh needs exactly one setting to self-repair: either
|
|
33
|
+
* `clusterPolicy.assumedClusterSize: 2` (which does not lower the replication factor) or an honest
|
|
34
|
+
* `clusterSize: 2`. Writes and voting still work with zero configuration.
|
|
35
|
+
*
|
|
36
|
+
* ## Future
|
|
37
|
+
*
|
|
38
|
+
* Deriving the yardstick from observation (the largest peer group this node has ever seen for the
|
|
39
|
+
* key) would remove the trade entirely and subsume both values. Filed as backlog
|
|
40
|
+
* `feat-admission-floor-from-observed-cohort-high-water-mark`; do not build it here.
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* Absolute floor below which no cohort is safe, whatever the size references say. Named rather than
|
|
44
|
+
* inlined because the admission gate's `assumedClusterSize` defaults to exactly this value — the two
|
|
45
|
+
* must not drift.
|
|
46
|
+
*/
|
|
47
|
+
export declare const minAbsoluteClusterSize = 2;
|
|
48
|
+
/**
|
|
49
|
+
* The operator-facing cluster knobs. `NodeOptions` (`libp2p-node-base.ts`) intersects this rather
|
|
50
|
+
* than restating it, so a knob added here is one `resolveClusterPolicy` is guaranteed to see — a
|
|
51
|
+
* second declaration would compile fine and be silently dropped.
|
|
52
|
+
*/
|
|
53
|
+
export interface ClusterPolicyOptions {
|
|
54
|
+
/**
|
|
55
|
+
* Desired cluster size per key (default 10) — the replication factor / target cohort breadth
|
|
56
|
+
* the coordinator aims for. NOT a statement about how many peers actually exist, so the
|
|
57
|
+
* membership admission gate is never measured against it (see `cluster/cluster-repo.ts`).
|
|
58
|
+
*
|
|
59
|
+
* The read-repair/reconcile corroboration floor DOES fall back to it when
|
|
60
|
+
* `clusterPolicy.assumedClusterSize` is absent — the strict direction, so an unconfigured node
|
|
61
|
+
* cannot have its floor talked down by a shrunken cohort view. A deployment that genuinely runs
|
|
62
|
+
* fewer peers than this should declare `clusterPolicy.assumedClusterSize`.
|
|
63
|
+
*/
|
|
64
|
+
clusterSize?: number;
|
|
65
|
+
clusterPolicy?: {
|
|
66
|
+
allowDownsize?: boolean;
|
|
67
|
+
/** Acceptable relative difference (e.g. 0.5 = +/-50%). */
|
|
68
|
+
sizeTolerance?: number;
|
|
69
|
+
/** Fraction of peers needed for super-majority (default {@link DEFAULT_SUPER_MAJORITY_THRESHOLD}). */
|
|
70
|
+
superMajorityThreshold?: number;
|
|
71
|
+
/**
|
|
72
|
+
* Opt in to transacting below the safe cluster-size floor when FRET has no confident
|
|
73
|
+
* network-size estimate — the membership-admission and coordinator small-cluster gates both
|
|
74
|
+
* fail closed without it. Default false. Turn on only for single-node / local dev meshes that
|
|
75
|
+
* knowingly run undersized.
|
|
76
|
+
*/
|
|
77
|
+
allowUnvalidatedSmallCluster?: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* The smallest cohort this deployment can genuinely field — normally the number of nodes you
|
|
80
|
+
* actually run, capped at `clusterSize`. Two consumers read it: the membership admission gate,
|
|
81
|
+
* on its fallback path when the node has no confident network-size estimate; and the
|
|
82
|
+
* read-repair/reconcile corroboration floor (`corroboratorCapacity`), unconditionally.
|
|
83
|
+
*
|
|
84
|
+
* Declaring it sets BOTH. Leaving it unset does NOT — see the module doc for why the two
|
|
85
|
+
* defaults point in opposite directions. A large deployment should still set this to its real
|
|
86
|
+
* cohort size, otherwise the admission gate cannot police a partition-induced downsize while
|
|
87
|
+
* its size estimate is unconfident; a genuine two-node mesh needs it (or an honest
|
|
88
|
+
* `clusterSize: 2`) to self-repair.
|
|
89
|
+
*/
|
|
90
|
+
assumedClusterSize?: number;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** Everything a node's consensus + restoration paths need, with every default already applied. */
|
|
94
|
+
export type ResolvedClusterPolicy = ClusterConsensusConfig & {
|
|
95
|
+
/** Replication factor / target cohort breadth. Always concrete after resolution. */
|
|
96
|
+
clusterSize: number;
|
|
97
|
+
/**
|
|
98
|
+
* Yardstick the repair corroboration floor measures a (possibly shrunken, always unauthenticated)
|
|
99
|
+
* cohort view against — see `corroboratorCapacity` in `cluster/quorum-restore.ts`.
|
|
100
|
+
*
|
|
101
|
+
* Deliberately distinct from {@link ClusterConsensusConfig.assumedClusterSize}, which the
|
|
102
|
+
* membership admission gate reads: the two share an operator field but not a default, because
|
|
103
|
+
* over- and under-stating them cost opposite things. See the module doc.
|
|
104
|
+
*/
|
|
105
|
+
repairCorroborationClusterSize: number;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Apply every cluster-policy default a node needs. Pure — same options in, same numbers out — so the
|
|
109
|
+
* composition root's behavior is unit-testable (`test/cluster-policy.spec.ts`).
|
|
110
|
+
*/
|
|
111
|
+
export declare function resolveClusterPolicy(options: ClusterPolicyOptions): ResolvedClusterPolicy;
|
|
112
|
+
//# sourceMappingURL=cluster-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cluster-policy.d.ts","sourceRoot":"","sources":["../../../src/cluster/cluster-policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAEpG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACpC;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE;QACf,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,0DAA0D;QAC1D,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,sGAAsG;QACtG,sBAAsB,CAAC,EAAE,MAAM,CAAC;QAChC;;;;;WAKG;QACH,4BAA4B,CAAC,EAAE,OAAO,CAAC;QACvC;;;;;;;;;;;WAWG;QACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;KAC5B,CAAC;CACF;AAED,kGAAkG;AAClG,MAAM,MAAM,qBAAqB,GAAG,sBAAsB,GAAG;IAC5D,oFAAoF;IACpF,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;;OAOG;IACH,8BAA8B,EAAE,MAAM,CAAC;CACvC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,oBAAoB,GAAG,qBAAqB,CAoCzF"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { DEFAULT_SUPER_MAJORITY_THRESHOLD } from "@optimystic/db-core";
|
|
2
|
+
/**
|
|
3
|
+
* Resolves the operator-facing cluster knobs (`clusterSize`, `clusterPolicy.*`) into the concrete
|
|
4
|
+
* numbers the consensus and block-restoration paths run on.
|
|
5
|
+
*
|
|
6
|
+
* Extracted from `createLibp2pNodeBase` rather than left inline so the composition root's defaults
|
|
7
|
+
* are assertable without booting a libp2p node — the layer a real deployment actually uses, and
|
|
8
|
+
* therefore the layer where a default that relaxed the repair corroboration floor to a single voter
|
|
9
|
+
* survived unnoticed (see `test/cluster-policy.spec.ts`).
|
|
10
|
+
*
|
|
11
|
+
* ## Why two size yardsticks, not one
|
|
12
|
+
*
|
|
13
|
+
* One operator field — `clusterPolicy.assumedClusterSize`, "the smallest cohort this deployment can
|
|
14
|
+
* genuinely field" — feeds two consumers whose failure modes point in opposite directions, so its
|
|
15
|
+
* *default* cannot serve both:
|
|
16
|
+
*
|
|
17
|
+
* - **Membership admission gate** (`cluster/cluster-repo.ts`, `admitMembership`) reads it only on its
|
|
18
|
+
* fallback path, when this node has no confident network-size estimate. Too small: a
|
|
19
|
+
* partition-induced downsize slips past while the node is unconfident. Too large: the node refuses
|
|
20
|
+
* legitimate writes — unavailability. It wants a *permissive* default, because an unconfigured
|
|
21
|
+
* two-node mesh must still be able to transact. It gets {@link minAbsoluteClusterSize} (2).
|
|
22
|
+
* - **Repair corroboration floor** (`corroboratorCapacity` in `cluster/quorum-restore.ts`, called by
|
|
23
|
+
* `CoordinatorRepo.queryClusterForLatest` and `createReconcileBlock`) reads it on *every* repair,
|
|
24
|
+
* unconditionally. Too small: a shrunken — and always unauthenticated — cohort view buys a lone
|
|
25
|
+
* peer full trust. Too large: a block stays unrepaired, degraded rather than dead. It wants a
|
|
26
|
+
* *strict* default. It gets {@link ResolvedClusterPolicy.repairCorroborationClusterSize}, which
|
|
27
|
+
* falls back to `clusterSize` (the configured replication factor).
|
|
28
|
+
*
|
|
29
|
+
* A single explicit `clusterPolicy.assumedClusterSize` still sets BOTH — an operator declaring their
|
|
30
|
+
* real cohort size means it for both consumers. Only the unconfigured case diverges.
|
|
31
|
+
*
|
|
32
|
+
* So a genuine two-node mesh needs exactly one setting to self-repair: either
|
|
33
|
+
* `clusterPolicy.assumedClusterSize: 2` (which does not lower the replication factor) or an honest
|
|
34
|
+
* `clusterSize: 2`. Writes and voting still work with zero configuration.
|
|
35
|
+
*
|
|
36
|
+
* ## Future
|
|
37
|
+
*
|
|
38
|
+
* Deriving the yardstick from observation (the largest peer group this node has ever seen for the
|
|
39
|
+
* key) would remove the trade entirely and subsume both values. Filed as backlog
|
|
40
|
+
* `feat-admission-floor-from-observed-cohort-high-water-mark`; do not build it here.
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* Absolute floor below which no cohort is safe, whatever the size references say. Named rather than
|
|
44
|
+
* inlined because the admission gate's `assumedClusterSize` defaults to exactly this value — the two
|
|
45
|
+
* must not drift.
|
|
46
|
+
*/
|
|
47
|
+
export const minAbsoluteClusterSize = 2;
|
|
48
|
+
/**
|
|
49
|
+
* Apply every cluster-policy default a node needs. Pure — same options in, same numbers out — so the
|
|
50
|
+
* composition root's behavior is unit-testable (`test/cluster-policy.spec.ts`).
|
|
51
|
+
*/
|
|
52
|
+
export function resolveClusterPolicy(options) {
|
|
53
|
+
// undefined here means "the operator said nothing", which is the only case where the two
|
|
54
|
+
// yardsticks below diverge.
|
|
55
|
+
//
|
|
56
|
+
// NOTE: a declared value is passed through unvalidated. The admission gate floors a degenerate one
|
|
57
|
+
// (0, negative, NaN, Infinity) itself — see `cluster-repo.admissionFloor` and its specs — but
|
|
58
|
+
// `corroboratorCapacity` does not: NaN there makes every quorum comparison false, so repair
|
|
59
|
+
// silently declines forever. Fail-safe, and unreachable through the reference-peer CLI (which
|
|
60
|
+
// rejects non-positive integers). If another composition root starts accepting unvalidated config,
|
|
61
|
+
// clamp here rather than in each consumer.
|
|
62
|
+
const declaredCohortSize = options.clusterPolicy?.assumedClusterSize;
|
|
63
|
+
const clusterSize = options.clusterSize ?? 10;
|
|
64
|
+
return {
|
|
65
|
+
superMajorityThreshold: options.clusterPolicy?.superMajorityThreshold ?? DEFAULT_SUPER_MAJORITY_THRESHOLD,
|
|
66
|
+
simpleMajorityThreshold: 0.51,
|
|
67
|
+
minAbsoluteClusterSize,
|
|
68
|
+
allowClusterDownsize: options.clusterPolicy?.allowDownsize ?? true,
|
|
69
|
+
clusterSizeTolerance: options.clusterPolicy?.sizeTolerance ?? 0.5,
|
|
70
|
+
// Fail closed by default (an undersized cluster with no confident network-size estimate is
|
|
71
|
+
// rejected); embedders running knowingly-small meshes opt in through clusterPolicy.
|
|
72
|
+
allowUnvalidatedSmallCluster: options.clusterPolicy?.allowUnvalidatedSmallCluster ?? false,
|
|
73
|
+
partitionDetectionWindow: 60000,
|
|
74
|
+
// Replication factor / target cohort breadth — what the coordinator aims for when selecting a
|
|
75
|
+
// cohort. Deliberately NOT the membership admission gate's yardstick: it says nothing about how
|
|
76
|
+
// many peers actually exist, so an unconfigured small mesh would refuse every write.
|
|
77
|
+
clusterSize,
|
|
78
|
+
// Membership admission gate, fallback path only (no confident network-size estimate). Defaults
|
|
79
|
+
// permissive so a two- or three-node mesh transacts unconfigured; the cost of that default is
|
|
80
|
+
// bounded to the gate, since the repair floor no longer reads this field.
|
|
81
|
+
assumedClusterSize: declaredCohortSize ?? minAbsoluteClusterSize,
|
|
82
|
+
// Repair corroboration floor, every repair. Defaults strict — to the replication factor — so an
|
|
83
|
+
// unconfigured node cannot have its floor talked down to a single voter by a shrunken cohort
|
|
84
|
+
// view. A genuinely small mesh declares its size (either field) to regain self-repair.
|
|
85
|
+
repairCorroborationClusterSize: declaredCohortSize ?? clusterSize
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=cluster-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cluster-policy.js","sourceRoot":"","sources":["../../../src/cluster/cluster-policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gCAAgC,EAA+B,MAAM,qBAAqB,CAAC;AAEpG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AA+DxC;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAA6B;IACjE,yFAAyF;IACzF,4BAA4B;IAC5B,EAAE;IACF,mGAAmG;IACnG,8FAA8F;IAC9F,4FAA4F;IAC5F,8FAA8F;IAC9F,mGAAmG;IACnG,2CAA2C;IAC3C,MAAM,kBAAkB,GAAG,OAAO,CAAC,aAAa,EAAE,kBAAkB,CAAC;IACrE,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC;IAE9C,OAAO;QACN,sBAAsB,EAAE,OAAO,CAAC,aAAa,EAAE,sBAAsB,IAAI,gCAAgC;QACzG,uBAAuB,EAAE,IAAI;QAC7B,sBAAsB;QACtB,oBAAoB,EAAE,OAAO,CAAC,aAAa,EAAE,aAAa,IAAI,IAAI;QAClE,oBAAoB,EAAE,OAAO,CAAC,aAAa,EAAE,aAAa,IAAI,GAAG;QACjE,2FAA2F;QAC3F,oFAAoF;QACpF,4BAA4B,EAAE,OAAO,CAAC,aAAa,EAAE,4BAA4B,IAAI,KAAK;QAC1F,wBAAwB,EAAE,KAAK;QAC/B,8FAA8F;QAC9F,gGAAgG;QAChG,qFAAqF;QACrF,WAAW;QACX,+FAA+F;QAC/F,8FAA8F;QAC9F,0EAA0E;QAC1E,kBAAkB,EAAE,kBAAkB,IAAI,sBAAsB;QAChE,gGAAgG;QAChG,6FAA6F;QAC7F,uFAAuF;QACvF,8BAA8B,EAAE,kBAAkB,IAAI,WAAW;KACjE,CAAC;AACH,CAAC"}
|
|
@@ -68,9 +68,10 @@ export type ExpectedClusterView = {
|
|
|
68
68
|
* Independently derive this member's own view of a block's responsible cluster. Injected so
|
|
69
69
|
* {@link ClusterMember} stays transport-agnostic — the composition root supplies it from
|
|
70
70
|
* `IKeyNetwork.findCluster` + FRET (mirroring how the coordinator derives the cluster). Absent on nodes
|
|
71
|
-
* that cannot derive a view (no FRET, unit tests): with no derived view AND no
|
|
72
|
-
*
|
|
73
|
-
* fail closed on an unjustified downsize. See {@link ClusterMember}
|
|
71
|
+
* that cannot derive a view (no FRET, unit tests): with no derived view AND no asserted
|
|
72
|
+
* {@link ClusterConsensusConfig.assumedClusterSize} the gate preserves legacy approve behavior, but an
|
|
73
|
+
* asserted size still lets the gate fail closed on an unjustified downsize. See {@link ClusterMember}
|
|
74
|
+
* admission gate.
|
|
74
75
|
*/
|
|
75
76
|
export type DeriveExpectedClusterCallback = (blockId: BlockId) => Promise<ExpectedClusterView>;
|
|
76
77
|
/** Stable reject reason a member emits when a declared peer set fails the membership admission gate. */
|
|
@@ -141,8 +142,8 @@ export declare class ClusterMember implements ICluster {
|
|
|
141
142
|
private readonly minAbsoluteClusterSize;
|
|
142
143
|
private readonly clusterSizeTolerance;
|
|
143
144
|
private readonly membershipAdmissionFraction;
|
|
144
|
-
/**
|
|
145
|
-
private readonly
|
|
145
|
+
/** Operator-asserted smallest genuine cohort size, or undefined when unknown. */
|
|
146
|
+
private readonly assumedClusterSize;
|
|
146
147
|
private readonly allowUnvalidatedSmallCluster;
|
|
147
148
|
constructor(storageRepo: IRepo, peerNetwork: IPeerNetwork, peerId: PeerId, privateKey: PrivateKey, protocolPrefix?: string | undefined, _partitionDetector?: PartitionDetector, fretService?: FretService | undefined, validator?: ITransactionValidator | undefined, reputation?: IPeerReputation | undefined, consensusConfig?: ClusterConsensusConfig, stateStore?: ITransactionStateStore | undefined, reconcileBlock?: ReconcileBlockCallback | undefined, onCommitCertificate?: CommitCertificateSink | undefined, onInvalidate?: InvalidationApplySink | undefined, recomputeArbitratorSet?: RecomputeArbitratorSetCapability | undefined, deriveExpectedCluster?: DeriveExpectedClusterCallback | undefined);
|
|
148
149
|
/**
|
|
@@ -240,14 +241,37 @@ export declare class ClusterMember implements ICluster {
|
|
|
240
241
|
* of a peer or two is absorbed, a wholesale-disjoint or half-size set is not.
|
|
241
242
|
*
|
|
242
243
|
* **Fail-closed posture.** When the member cannot confidently derive `E` (no capability, low FRET
|
|
243
|
-
* confidence — exactly what a partition induces), it must refuse any *downsizing* decision
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
244
|
+
* confidence — exactly what a partition induces), it must refuse any *downsizing* decision — but it
|
|
245
|
+
* needs a size reference to judge "downsize" against, and it may NOT borrow `clusterSize` for that:
|
|
246
|
+
* `clusterSize` is the replication factor (what a cohort should aim for), not a claim about how many
|
|
247
|
+
* peers exist, so a small deployment configured with the default 10 would refuse every write. The
|
|
248
|
+
* fallback yardstick is instead {@link ClusterConsensusConfig.assumedClusterSize} — the operator's own
|
|
249
|
+
* assertion of the smallest cohort this deployment can genuinely field — run through the SAME
|
|
250
|
+
* {@link admissionFloor} as the confident path, so the fallback can never be stricter than the measured
|
|
251
|
+
* path (it was: it demanded the full configured size, with no fraction and no slack for churn or a peer
|
|
252
|
+
* not yet discovered). With NEITHER a confident view NOR an asserted size the gate cannot judge a
|
|
253
|
+
* downsize at all, so it preserves the legacy approve behavior (backward-compatible for nodes/tests with
|
|
254
|
+
* no derivation wired). `allowUnvalidatedSmallCluster` is the explicit opt-in (single-node / local dev
|
|
255
|
+
* knowingly below the safe floor), matching the coordinator's `validateSmallCluster` semantics.
|
|
249
256
|
*/
|
|
250
257
|
private admitMembership;
|
|
258
|
+
/**
|
|
259
|
+
* The smallest declared peer set admissible against a cohort-size reference `k`, whether `k` is
|
|
260
|
+
* measured (the confident path's `kEst`) or asserted (`assumedClusterSize`). One function so the
|
|
261
|
+
* fallback can never be stricter than the measured path — which it was, demanding the full configured
|
|
262
|
+
* size with no fraction and no slack. Clamped at `minAbsoluteClusterSize`, so a degenerate `k` of 0, 1
|
|
263
|
+
* or negative yields the absolute floor rather than a floor that admits everything. A non-finite scaled
|
|
264
|
+
* size (a `NaN` or `Infinity` config value) is likewise treated as no usable reference rather than
|
|
265
|
+
* propagating: an unguarded `NaN` floor fails EVERY comparison, which would silently make the node
|
|
266
|
+
* reject every unconfident write.
|
|
267
|
+
*
|
|
268
|
+
* NOTE: partition safety needs `2 · membershipAdmissionFraction · superMajorityThreshold > 1` — each
|
|
269
|
+
* side of a split must recruit `fraction · threshold · K` distinct honest members, and two sides cannot
|
|
270
|
+
* both find them in one K-peer cluster. At the shipped defaults (0.75 · 0.67) that product is 1.005 —
|
|
271
|
+
* true, but with almost no margin. If either default is ever lowered, re-check Theorem 2 in
|
|
272
|
+
* `docs/correctness.md` before shipping it.
|
|
273
|
+
*/
|
|
274
|
+
private admissionFloor;
|
|
251
275
|
/**
|
|
252
276
|
* Derive this member's own view of the record's block cluster via the injected capability, or
|
|
253
277
|
* `undefined` when it cannot (no capability, no coordinating block id, or a derivation error — all of
|
|
@@ -297,9 +321,13 @@ export declare class ClusterMember implements ICluster {
|
|
|
297
321
|
* - **behind**: we missed the prior `pend` cluster-transaction (cohort drift
|
|
298
322
|
* between the independent pend and commit phases, or transient unreachability),
|
|
299
323
|
* so we lack the pending action — `StorageRepo.commit` *throws* "Pending
|
|
300
|
-
* action … not found"
|
|
324
|
+
* action … not found";
|
|
325
|
+
* - **behind (no base)**: we DID see the pend, but we never saw the revision that
|
|
326
|
+
* created the block, so the transform has nothing to apply to —
|
|
327
|
+
* `StorageRepo.commit` returns `success:false` with a `missing-base-revision`
|
|
328
|
+
* reason rather than recording a revision it could not materialize.
|
|
301
329
|
*
|
|
302
|
-
* For
|
|
330
|
+
* For both **behind** cases we hold no usable revision of the committed blocks, so we
|
|
303
331
|
* actively reconcile: pull the committed revision from a cohort peer that holds it
|
|
304
332
|
* (`reconcileBlock`) and restore it locally. Lazy read-repair on a later read cannot
|
|
305
333
|
* recover it on its own when cohort drift has left the block under-replicated (no
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cluster-repo.d.ts","sourceRoot":"","sources":["../../../src/cluster/cluster-repo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,YAAY,EAA0B,qBAAqB,EAAE,sBAAsB,EAAgB,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAiB,UAAU,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC/O,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,EAAiC,KAAK,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAGxG,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAM5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"cluster-repo.d.ts","sourceRoot":"","sources":["../../../src/cluster/cluster-repo.ts"],"names":[],"mappings":"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"}
|