@optimystic/db-p2p 0.21.0 → 0.24.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/client.d.ts +10 -0
- package/dist/src/cluster/client.d.ts.map +1 -1
- package/dist/src/cluster/client.js +30 -1
- package/dist/src/cluster/client.js.map +1 -1
- package/dist/src/cluster/cluster-policy.d.ts +13 -2
- package/dist/src/cluster/cluster-policy.d.ts.map +1 -1
- package/dist/src/cluster/cluster-policy.js +51 -4
- package/dist/src/cluster/cluster-policy.js.map +1 -1
- package/dist/src/cluster/cluster-repo.d.ts +42 -17
- package/dist/src/cluster/cluster-repo.d.ts.map +1 -1
- package/dist/src/cluster/cluster-repo.js +229 -122
- package/dist/src/cluster/cluster-repo.js.map +1 -1
- package/dist/src/cluster/cluster-size-coupling.d.ts +28 -0
- package/dist/src/cluster/cluster-size-coupling.d.ts.map +1 -0
- package/dist/src/cluster/cluster-size-coupling.js +35 -0
- package/dist/src/cluster/cluster-size-coupling.js.map +1 -0
- package/dist/src/cluster/quorum-restore.d.ts +6 -0
- package/dist/src/cluster/quorum-restore.d.ts.map +1 -1
- package/dist/src/cluster/quorum-restore.js +1 -1
- package/dist/src/cluster/quorum-restore.js.map +1 -1
- package/dist/src/cluster/reconcile-block.d.ts.map +1 -1
- package/dist/src/cluster/reconcile-block.js +15 -3
- package/dist/src/cluster/reconcile-block.js.map +1 -1
- package/dist/src/cluster/service.d.ts +32 -1
- package/dist/src/cluster/service.d.ts.map +1 -1
- package/dist/src/cluster/service.js +43 -2
- package/dist/src/cluster/service.js.map +1 -1
- package/dist/src/cohort-topic/stream-util.d.ts +22 -6
- package/dist/src/cohort-topic/stream-util.d.ts.map +1 -1
- package/dist/src/cohort-topic/stream-util.js +56 -10
- package/dist/src/cohort-topic/stream-util.js.map +1 -1
- package/dist/src/dispute/dispute-service.d.ts.map +1 -1
- package/dist/src/dispute/dispute-service.js +9 -3
- package/dist/src/dispute/dispute-service.js.map +1 -1
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +5 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/libp2p-key-network.d.ts +134 -7
- package/dist/src/libp2p-key-network.d.ts.map +1 -1
- package/dist/src/libp2p-key-network.js +174 -37
- package/dist/src/libp2p-key-network.js.map +1 -1
- package/dist/src/libp2p-node-base.d.ts +3 -2
- package/dist/src/libp2p-node-base.d.ts.map +1 -1
- package/dist/src/libp2p-node-base.js +859 -778
- package/dist/src/libp2p-node-base.js.map +1 -1
- package/dist/src/libp2p-node-rn.d.ts +2 -2
- package/dist/src/libp2p-node-rn.d.ts.map +1 -1
- package/dist/src/libp2p-node-rn.js.map +1 -1
- package/dist/src/libp2p-node.d.ts +2 -2
- package/dist/src/libp2p-node.d.ts.map +1 -1
- package/dist/src/libp2p-node.js.map +1 -1
- package/dist/src/logger.d.ts +17 -1
- package/dist/src/logger.d.ts.map +1 -1
- package/dist/src/logger.js +19 -2
- package/dist/src/logger.js.map +1 -1
- package/dist/src/network/network-manager-service.d.ts +2 -0
- package/dist/src/network/network-manager-service.d.ts.map +1 -1
- package/dist/src/network/network-manager-service.js +4 -0
- package/dist/src/network/network-manager-service.js.map +1 -1
- package/dist/src/optimystic-node.d.ts +35 -0
- package/dist/src/optimystic-node.d.ts.map +1 -0
- package/dist/src/optimystic-node.js +2 -0
- package/dist/src/optimystic-node.js.map +1 -0
- package/dist/src/owned-block-seed.d.ts +6 -3
- package/dist/src/owned-block-seed.d.ts.map +1 -1
- package/dist/src/owned-block-seed.js +16 -3
- package/dist/src/owned-block-seed.js.map +1 -1
- package/dist/src/peer-address-book.d.ts +72 -0
- package/dist/src/peer-address-book.d.ts.map +1 -0
- package/dist/src/peer-address-book.js +123 -0
- package/dist/src/peer-address-book.js.map +1 -0
- package/dist/src/repo/client.d.ts.map +1 -1
- package/dist/src/repo/client.js +11 -2
- package/dist/src/repo/client.js.map +1 -1
- package/dist/src/repo/cluster-coordinator.d.ts +30 -0
- package/dist/src/repo/cluster-coordinator.d.ts.map +1 -1
- package/dist/src/repo/cluster-coordinator.js +95 -3
- package/dist/src/repo/cluster-coordinator.js.map +1 -1
- package/dist/src/repo/coordinator-repo.d.ts +78 -14
- package/dist/src/repo/coordinator-repo.d.ts.map +1 -1
- package/dist/src/repo/coordinator-repo.js +266 -81
- package/dist/src/repo/coordinator-repo.js.map +1 -1
- package/dist/src/rn.d.ts +5 -0
- package/dist/src/rn.d.ts.map +1 -1
- package/dist/src/rn.js +5 -0
- package/dist/src/rn.js.map +1 -1
- package/dist/src/storage/block-storage.d.ts.map +1 -1
- package/dist/src/storage/block-storage.js +57 -5
- package/dist/src/storage/block-storage.js.map +1 -1
- package/dist/src/storage/cached-raw-storage.d.ts +83 -0
- package/dist/src/storage/cached-raw-storage.d.ts.map +1 -0
- package/dist/src/storage/cached-raw-storage.js +152 -0
- package/dist/src/storage/cached-raw-storage.js.map +1 -0
- package/dist/src/storage/cached-store-driver.d.ts +186 -0
- package/dist/src/storage/cached-store-driver.d.ts.map +1 -0
- package/dist/src/storage/cached-store-driver.js +775 -0
- package/dist/src/storage/cached-store-driver.js.map +1 -0
- package/dist/src/storage/i-block-storage.d.ts +20 -1
- package/dist/src/storage/i-block-storage.d.ts.map +1 -1
- package/dist/src/storage/i-raw-storage.d.ts +12 -5
- package/dist/src/storage/i-raw-storage.d.ts.map +1 -1
- package/dist/src/storage/shared-cache-pool.d.ts +234 -0
- package/dist/src/storage/shared-cache-pool.d.ts.map +1 -0
- package/dist/src/storage/shared-cache-pool.js +354 -0
- package/dist/src/storage/shared-cache-pool.js.map +1 -0
- package/dist/src/storage/storage-repo.d.ts +56 -3
- package/dist/src/storage/storage-repo.d.ts.map +1 -1
- package/dist/src/storage/storage-repo.js +124 -18
- package/dist/src/storage/storage-repo.js.map +1 -1
- package/dist/src/testing/raw-storage-conformance.d.ts +2 -1
- package/dist/src/testing/raw-storage-conformance.d.ts.map +1 -1
- package/dist/src/testing/raw-storage-conformance.js +52 -2
- package/dist/src/testing/raw-storage-conformance.js.map +1 -1
- package/package.json +3 -3
- package/readme.md +668 -653
- package/src/cluster/block-transfer.ts +424 -424
- package/src/cluster/client.ts +119 -88
- package/src/cluster/cluster-error.ts +64 -64
- package/src/cluster/cluster-policy.ts +203 -152
- package/src/cluster/cluster-repo.ts +245 -125
- package/src/cluster/cluster-size-coupling.ts +45 -0
- package/src/cluster/commit-cert.ts +139 -139
- package/src/cluster/i-transaction-state-store.ts +43 -43
- package/src/cluster/memory-transaction-state-store.ts +56 -56
- package/src/cluster/peer-key-binding.ts +37 -37
- package/src/cluster/persistent-transaction-state-store.ts +92 -92
- package/src/cluster/quorum-restore.ts +223 -223
- package/src/cluster/reconcile-block.ts +203 -191
- package/src/cluster/service.ts +293 -241
- package/src/cluster/supermajority-coupling.ts +37 -37
- package/src/cohort-topic/bootstrap-evidence-builder.ts +122 -122
- package/src/cohort-topic/bootstrap-evidence-verifiers.ts +132 -132
- package/src/cohort-topic/bootstrap-parent-reference.ts +159 -159
- package/src/cohort-topic/change-bridge.ts +109 -109
- package/src/cohort-topic/cohort-gossip-driver.ts +231 -231
- package/src/cohort-topic/cohort-gossip-transport.ts +84 -84
- package/src/cohort-topic/fret-trust-anchor.ts +153 -153
- package/src/cohort-topic/host.ts +2901 -2901
- package/src/cohort-topic/index.ts +13 -13
- package/src/cohort-topic/membership-publish-sink.ts +20 -20
- package/src/cohort-topic/membership-source.ts +68 -68
- package/src/cohort-topic/peer-codec.ts +31 -31
- package/src/cohort-topic/peer-sig.ts +86 -86
- package/src/cohort-topic/protocols.ts +71 -71
- package/src/cohort-topic/reactivity-membership-gate.ts +77 -77
- package/src/cohort-topic/size-estimator.ts +16 -16
- package/src/cohort-topic/stream-util.ts +135 -87
- package/src/cohort-topic/threshold-crypto.ts +239 -239
- package/src/cohort-topic/topic-router.ts +77 -77
- package/src/dispute/arbitrator-selection.ts +138 -138
- package/src/dispute/cascade.ts +524 -524
- package/src/dispute/dispute-service.ts +11 -5
- package/src/dispute/invalidation.ts +625 -625
- package/src/inbound-authorization.ts +190 -190
- package/src/index.ts +52 -47
- package/src/libp2p-key-network.ts +1120 -958
- package/src/libp2p-node-base.ts +1675 -1591
- package/src/libp2p-node-rn.ts +30 -30
- package/src/libp2p-node.ts +36 -36
- package/src/logger.ts +19 -2
- package/src/matchmaking/aggregate-counts.ts +104 -104
- package/src/matchmaking/index.ts +20 -20
- package/src/matchmaking/module.ts +363 -363
- package/src/matchmaking/protocols.ts +51 -51
- package/src/matchmaking/provider-manager.ts +95 -95
- package/src/matchmaking/query-handler.ts +88 -88
- package/src/matchmaking/query-transport.ts +492 -492
- package/src/matchmaking/seeker-manager.ts +64 -64
- package/src/matchmaking/seeker-walk-client.ts +293 -293
- package/src/matchmaking/traffic-validation.ts +195 -195
- package/src/network/network-manager-service.ts +5 -0
- package/src/optimystic-node.ts +36 -0
- package/src/owned-block-seed.ts +53 -40
- package/src/peer-address-book.ts +149 -0
- package/src/protocol-limits.ts +33 -33
- package/src/reactivity/forwarder-host.ts +438 -438
- package/src/reactivity/index.ts +19 -19
- package/src/reactivity/notify-transport.ts +144 -144
- package/src/reactivity/origination-manager.ts +192 -192
- package/src/reactivity/protocols.ts +61 -61
- package/src/reactivity/push-state-gossip.ts +291 -291
- package/src/reactivity/recover-transport.ts +408 -408
- package/src/reactivity/rotation-rereg-scheduler.ts +256 -256
- package/src/reactivity/subscriber-registry.ts +96 -96
- package/src/reactivity/subscription-manager.ts +450 -450
- package/src/reactivity/topic-bytes.ts +37 -37
- package/src/repo/client.ts +12 -2
- package/src/repo/cluster-coordinator.ts +99 -3
- package/src/repo/coordinator-repo.ts +305 -82
- package/src/repo/types.ts +7 -7
- package/src/rn.ts +39 -34
- package/src/rpc-deadline.ts +45 -45
- package/src/storage/arachnode-partition.ts +74 -74
- package/src/storage/block-storage.ts +59 -6
- package/src/storage/cached-raw-storage.ts +180 -0
- package/src/storage/cached-store-driver.ts +859 -0
- package/src/storage/i-block-storage.ts +20 -1
- package/src/storage/i-kv-store.ts +8 -8
- package/src/storage/i-raw-storage.ts +12 -5
- package/src/storage/kv-raw-storage.ts +135 -135
- package/src/storage/memory-kv-store.ts +28 -28
- package/src/storage/memory-storage.ts +25 -25
- package/src/storage/memory-store-driver.ts +157 -157
- package/src/storage/raw-store-codec.ts +42 -42
- package/src/storage/raw-store-driver.ts +80 -80
- package/src/storage/ring-selector.ts +317 -317
- package/src/storage/ring-shift-coordinator.ts +271 -271
- package/src/storage/shared-cache-pool.ts +452 -0
- package/src/storage/storage-repo.ts +1014 -903
- package/src/testing/cohort-topic-mesh-harness.ts +663 -663
- package/src/testing/index.ts +8 -8
- package/src/testing/matchmaking-mesh-harness.ts +475 -475
- package/src/testing/raw-storage-conformance.ts +453 -397
- package/src/testing/reactivity-mesh-harness.ts +922 -922
- package/dist/src/storage/restoration-coordinator-v2.d.ts +0 -67
- package/dist/src/storage/restoration-coordinator-v2.d.ts.map +0 -1
- package/dist/src/storage/restoration-coordinator-v2.js +0 -172
- package/dist/src/storage/restoration-coordinator-v2.js.map +0 -1
|
@@ -7,6 +7,16 @@ export declare class ClusterClient extends ProtocolClient implements ICluster {
|
|
|
7
7
|
/** Create a new client instance */
|
|
8
8
|
static create(peerId: PeerId, peerNetwork: IPeerNetwork, protocolPrefix?: string): ClusterClient;
|
|
9
9
|
update(record: ClusterRecord, hop?: number, options?: RpcDeadlineOptions): Promise<ClusterRecord>;
|
|
10
|
+
/**
|
|
11
|
+
* Offer every address a cluster record carries for its cohort to the dialer's address book.
|
|
12
|
+
*
|
|
13
|
+
* Shares its traversal — and its cap on how many peers one record may introduce — with the
|
|
14
|
+
* inbound side (`ClusterService.learnPeerAddresses`); validation, the per-peer cap, and the
|
|
15
|
+
* trust boundary live in the implementation behind `recordPeerAddresses`. No self-filter is
|
|
16
|
+
* passed: `this.peerId` is the peer we DIALED, not this node, and only the sink knows the
|
|
17
|
+
* local node's identity.
|
|
18
|
+
*/
|
|
19
|
+
private recordRecordPeerAddresses;
|
|
10
20
|
/**
|
|
11
21
|
* Record a coordinator-affinity hint for the block this record's op is
|
|
12
22
|
* coordinated on, so a follow-up op can dial `peerId` directly.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/cluster/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzF,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/cluster/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzF,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAMvD,OAAO,EAA2B,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAKtF,qBAAa,aAAc,SAAQ,cAAe,YAAW,QAAQ;IACL,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM;IAA/F,OAAO;IAIP,mCAAmC;WACrB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,aAAa;IAIjG,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,GAAE,MAAU,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC;IAqD1G;;;;;;;;OAQG;IACH,OAAO,CAAC,yBAAyB;IAMhC;;;;;;;;;;;;;;;OAeG;YACW,qCAAqC;CAWpD"}
|
|
@@ -2,8 +2,11 @@ import { blockIdToBytes, blockIdsForTransforms } from '@optimystic/db-core';
|
|
|
2
2
|
import { ProtocolClient } from '../protocol-client.js';
|
|
3
3
|
import { peerIdFromString } from '@libp2p/peer-id';
|
|
4
4
|
import { isClusterErrorEnvelope, clusterErrorFromEnvelope } from './cluster-error.js';
|
|
5
|
+
import { mergeRecordPeerAddresses } from '../peer-address-book.js';
|
|
6
|
+
import { createLogger } from '../logger.js';
|
|
5
7
|
import { withRpcDeadlineDefaults } from '../rpc-deadline.js';
|
|
6
8
|
import { MAX_CONTROL_MESSAGE_BYTES } from '../protocol-limits.js';
|
|
9
|
+
const log = createLogger('cluster-client');
|
|
7
10
|
export class ClusterClient extends ProtocolClient {
|
|
8
11
|
protocolPrefix;
|
|
9
12
|
constructor(peerId, peerNetwork, protocolPrefix) {
|
|
@@ -34,6 +37,9 @@ export class ClusterClient extends ProtocolClient {
|
|
|
34
37
|
if (isClusterErrorEnvelope(response)) {
|
|
35
38
|
throw clusterErrorFromEnvelope(response);
|
|
36
39
|
}
|
|
40
|
+
// Type the redirect branch against the payload the service actually produces
|
|
41
|
+
// (`RedirectPayload`), not a hand-written narrower shape — the old `{ id: string }`
|
|
42
|
+
// literal is what structurally discarded the `addrs` the sender took the trouble to embed.
|
|
37
43
|
const redirectResponse = response;
|
|
38
44
|
if (redirectResponse?.redirect?.peers?.length) {
|
|
39
45
|
if (hop >= 2) {
|
|
@@ -45,13 +51,36 @@ export class ClusterClient extends ProtocolClient {
|
|
|
45
51
|
if (next.id === currentIdStr) {
|
|
46
52
|
throw new Error('Redirect loop detected in ClusterClient (same peer)');
|
|
47
53
|
}
|
|
54
|
+
// Learn the redirect target's addresses BEFORE dialing it: the redirect is the only
|
|
55
|
+
// notice we get that this peer matters, and if it is relay-only we have no address
|
|
56
|
+
// for it at all. Merging after the dial would help only some later hop.
|
|
57
|
+
this.peerNetwork.recordPeerAddresses?.(nextId, next.addrs ?? []);
|
|
48
58
|
await this.recordCoordinatorForRecordIfSupported(record, nextId);
|
|
49
59
|
const nextClient = ClusterClient.create(nextId, this.peerNetwork, this.protocolPrefix);
|
|
50
60
|
// Thread the caller's *original* options through the redirect hop (the
|
|
51
61
|
// recursive call re-applies its own defaults) so the deadline survives a redirect.
|
|
52
62
|
return await nextClient.update(record, hop + 1, options);
|
|
53
63
|
}
|
|
54
|
-
|
|
64
|
+
const updated = response;
|
|
65
|
+
// The member's reply carries the cohort's peer map too, and it may name addresses this
|
|
66
|
+
// node lacks — the coordinator's own half of the same exchange the service handles inbound.
|
|
67
|
+
this.recordRecordPeerAddresses(updated);
|
|
68
|
+
return updated;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Offer every address a cluster record carries for its cohort to the dialer's address book.
|
|
72
|
+
*
|
|
73
|
+
* Shares its traversal — and its cap on how many peers one record may introduce — with the
|
|
74
|
+
* inbound side (`ClusterService.learnPeerAddresses`); validation, the per-peer cap, and the
|
|
75
|
+
* trust boundary live in the implementation behind `recordPeerAddresses`. No self-filter is
|
|
76
|
+
* passed: `this.peerId` is the peer we DIALED, not this node, and only the sink knows the
|
|
77
|
+
* local node's identity.
|
|
78
|
+
*/
|
|
79
|
+
recordRecordPeerAddresses(record) {
|
|
80
|
+
const sink = this.peerNetwork.recordPeerAddresses;
|
|
81
|
+
if (!sink)
|
|
82
|
+
return;
|
|
83
|
+
mergeRecordPeerAddresses(record?.peers, (pid, addrs) => sink.call(this.peerNetwork, pid, addrs), log);
|
|
55
84
|
}
|
|
56
85
|
/**
|
|
57
86
|
* Record a coordinator-affinity hint for the block this record's op is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/cluster/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/cluster/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAEtF,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,uBAAuB,EAA2B,MAAM,oBAAoB,CAAC;AACtF,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAElE,MAAM,GAAG,GAAG,YAAY,CAAC,gBAAgB,CAAC,CAAC;AAE3C,MAAM,OAAO,aAAc,SAAQ,cAAc;IACwB;IAAxE,YAAoB,MAAc,EAAE,WAAyB,EAAW,cAAuB;QAC9F,KAAK,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QAD4C,mBAAc,GAAd,cAAc,CAAS;IAE/F,CAAC;IAED,mCAAmC;IAC5B,MAAM,CAAC,MAAM,CAAC,MAAc,EAAE,WAAyB,EAAE,cAAuB;QACtF,OAAO,IAAI,aAAa,CAAC,MAAM,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC;IAC/D,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,MAAqB,EAAE,MAAc,CAAC,EAAE,OAA4B;QAChF,MAAM,OAAO,GAAG;YACf,SAAS,EAAE,QAAQ;YACnB,MAAM;SACN,CAAC;QACF,sEAAsE;QACtE,gEAAgE;QAChE,qEAAqE;QACrE,uEAAuE;QACvE,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,cAAc,IAAI,SAAS,CAAC,GAAG,gBAAgB,CAAC;QACvE,yEAAyE;QACzE,wEAAwE;QACxE,sFAAsF;QACtF,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,cAAc,CAAU,OAAO,EAAE,QAAQ,EAAE,EAAE,GAAG,uBAAuB,CAAC,OAAO,CAAC,EAAE,aAAa,EAAE,yBAAyB,EAAE,CAAC,CAAC;QAE1J,sEAAsE;QACtE,sEAAsE;QACtE,uEAAuE;QACvE,IAAI,sBAAsB,CAAC,QAAQ,CAAC,EAAE,CAAC;YACtC,MAAM,wBAAwB,CAAC,QAAQ,CAAC,CAAC;QAC1C,CAAC;QAED,6EAA6E;QAC7E,oFAAoF;QACpF,2FAA2F;QAC3F,MAAM,gBAAgB,GAAG,QAAoC,CAAC;QAC9D,IAAI,gBAAgB,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;YAC/C,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;gBACd,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAA;YAC9E,CAAC;YACD,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAA;YAC3C,MAAM,IAAI,GAAG,gBAAgB,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,YAAY,CAAC,IAAI,gBAAgB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAE,CAAA;YACtH,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YACxC,IAAI,IAAI,CAAC,EAAE,KAAK,YAAY,EAAE,CAAC;gBAC9B,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAA;YACvE,CAAC;YACD,oFAAoF;YACpF,mFAAmF;YACnF,wEAAwE;YACxE,IAAI,CAAC,WAAW,CAAC,mBAAmB,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAA;YAChE,MAAM,IAAI,CAAC,qCAAqC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;YAChE,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,cAAc,CAAC,CAAA;YACtF,uEAAuE;YACvE,mFAAmF;YACnF,OAAO,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,OAAO,CAAC,CAAA;QACzD,CAAC;QACD,MAAM,OAAO,GAAG,QAAyB,CAAC;QAC1C,uFAAuF;QACvF,4FAA4F;QAC5F,IAAI,CAAC,yBAAyB,CAAC,OAAO,CAAC,CAAA;QACvC,OAAO,OAAO,CAAC;IAChB,CAAC;IAED;;;;;;;;OAQG;IACK,yBAAyB,CAAC,MAAqB;QACtD,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,mBAAmB,CAAA;QACjD,IAAI,CAAC,IAAI;YAAE,OAAM;QACjB,wBAAwB,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,GAAG,CAAC,CAAA;IACtG,CAAC;IAEA;;;;;;;;;;;;;;;OAeG;IACK,KAAK,CAAC,qCAAqC,CAAC,MAAqB,EAAE,MAAc;QACvF,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;QACvC,IAAI,CAAC,EAAE;YAAE,OAAM;QACf,IAAI,EAAsB,CAAA;QAC1B,IAAI,QAAQ,IAAI,EAAE;YAAE,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;aACzC,IAAI,MAAM,IAAI,EAAE;YAAE,EAAE,GAAG,qBAAqB,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAA;QACxE,IAAI,EAAE,IAAI,IAAI;YAAE,OAAM;QACtB,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,EAAE,CAAC,CAAA;QACvC,MAAM,EAAE,GAAQ,IAAI,CAAC,WAAkB,CAAA;QACvC,IAAI,OAAO,EAAE,EAAE,iBAAiB,KAAK,UAAU;YAAE,EAAE,CAAC,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACvF,CAAC;CACF"}
|
|
@@ -45,6 +45,15 @@ import { type ClusterConsensusConfig } from "@optimystic/db-core";
|
|
|
45
45
|
* must not drift.
|
|
46
46
|
*/
|
|
47
47
|
export declare const minAbsoluteClusterSize = 2;
|
|
48
|
+
/**
|
|
49
|
+
* Default replication factor / target cohort breadth when the operator declares no `clusterSize`.
|
|
50
|
+
*
|
|
51
|
+
* Exported (and re-exported from the package root) rather than left inline because a caller that
|
|
52
|
+
* must construct a `Libp2pKeyPeerNetwork` for a node it did not build has to state a cluster size —
|
|
53
|
+
* the constructor no longer supplies one — and the only defensible answer is "whatever a node built
|
|
54
|
+
* here would have resolved to". Repeating the literal is how the two drifted last time.
|
|
55
|
+
*/
|
|
56
|
+
export declare const DEFAULT_CLUSTER_SIZE = 10;
|
|
48
57
|
/**
|
|
49
58
|
* The operator-facing cluster knobs. `NodeOptions` (`libp2p-node-base.ts`) intersects this rather
|
|
50
59
|
* than restating it, so a knob added here is one `resolveClusterPolicy` is guaranteed to see — a
|
|
@@ -105,8 +114,10 @@ export type ResolvedClusterPolicy = ClusterConsensusConfig & {
|
|
|
105
114
|
repairCorroborationClusterSize: number;
|
|
106
115
|
};
|
|
107
116
|
/**
|
|
108
|
-
* Apply every cluster-policy default a node needs.
|
|
109
|
-
* composition root's behavior is unit-testable (`test/cluster-policy.spec.ts`).
|
|
117
|
+
* Apply every cluster-policy default a node needs. Same options in, same numbers out, so the
|
|
118
|
+
* composition root's behavior is unit-testable (`test/cluster-policy.spec.ts`). Its one side effect
|
|
119
|
+
* is the `assumed-cluster-size-unset` advisory below, which lives here because this is the only place
|
|
120
|
+
* that knows the resolution produced a self-defeating combination.
|
|
110
121
|
*/
|
|
111
122
|
export declare function resolveClusterPolicy(options: ClusterPolicyOptions): ResolvedClusterPolicy;
|
|
112
123
|
//# sourceMappingURL=cluster-policy.d.ts.map
|
|
@@ -1 +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;
|
|
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;AAMpG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAEvC;;;;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;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,oBAAoB,GAAG,qBAAqB,CAuEzF"}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { DEFAULT_SUPER_MAJORITY_THRESHOLD } from "@optimystic/db-core";
|
|
2
|
+
import { createLogger } from "../logger.js";
|
|
3
|
+
import { CORROBORATION_FLOOR } from "./quorum-restore.js";
|
|
4
|
+
const log = createLogger('cluster-policy');
|
|
2
5
|
/**
|
|
3
6
|
* Resolves the operator-facing cluster knobs (`clusterSize`, `clusterPolicy.*`) into the concrete
|
|
4
7
|
* numbers the consensus and block-restoration paths run on.
|
|
@@ -46,8 +49,19 @@ import { DEFAULT_SUPER_MAJORITY_THRESHOLD } from "@optimystic/db-core";
|
|
|
46
49
|
*/
|
|
47
50
|
export const minAbsoluteClusterSize = 2;
|
|
48
51
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
52
|
+
* Default replication factor / target cohort breadth when the operator declares no `clusterSize`.
|
|
53
|
+
*
|
|
54
|
+
* Exported (and re-exported from the package root) rather than left inline because a caller that
|
|
55
|
+
* must construct a `Libp2pKeyPeerNetwork` for a node it did not build has to state a cluster size —
|
|
56
|
+
* the constructor no longer supplies one — and the only defensible answer is "whatever a node built
|
|
57
|
+
* here would have resolved to". Repeating the literal is how the two drifted last time.
|
|
58
|
+
*/
|
|
59
|
+
export const DEFAULT_CLUSTER_SIZE = 10;
|
|
60
|
+
/**
|
|
61
|
+
* Apply every cluster-policy default a node needs. Same options in, same numbers out, so the
|
|
62
|
+
* composition root's behavior is unit-testable (`test/cluster-policy.spec.ts`). Its one side effect
|
|
63
|
+
* is the `assumed-cluster-size-unset` advisory below, which lives here because this is the only place
|
|
64
|
+
* that knows the resolution produced a self-defeating combination.
|
|
51
65
|
*/
|
|
52
66
|
export function resolveClusterPolicy(options) {
|
|
53
67
|
// undefined here means "the operator said nothing", which is the only case where the two
|
|
@@ -60,7 +74,40 @@ export function resolveClusterPolicy(options) {
|
|
|
60
74
|
// rejects non-positive integers). If another composition root starts accepting unvalidated config,
|
|
61
75
|
// clamp here rather than in each consumer.
|
|
62
76
|
const declaredCohortSize = options.clusterPolicy?.assumedClusterSize;
|
|
63
|
-
const clusterSize = options.clusterSize ??
|
|
77
|
+
const clusterSize = options.clusterSize ?? DEFAULT_CLUSTER_SIZE;
|
|
78
|
+
const repairCorroborationClusterSize = declaredCohortSize ?? clusterSize;
|
|
79
|
+
// Called once per node (resolveClusterPolicy runs once at construction), so this fires once per
|
|
80
|
+
// node startup, not per repair — a per-attempt warn on a busy node would be noise that gets
|
|
81
|
+
// filtered, defeating the point. Fires purely off configuration (not an observed cohort), so a
|
|
82
|
+
// deployment that genuinely runs `clusterSize` machines sees it too; worded as a conditional
|
|
83
|
+
// ("if you run fewer than N machines") rather than a fault for exactly that reason.
|
|
84
|
+
//
|
|
85
|
+
// The machine count in the message is CORROBORATION_FLOOR + 1, NOT repairCorroborationClusterSize:
|
|
86
|
+
// `corroboratorCapacity` caps only the FLOOR of two (`quorum-restore.ts`), so a cohort with two
|
|
87
|
+
// peers besides the reader meets it whatever the declared size. What an undeclared size costs is
|
|
88
|
+
// the relaxation below two, which is only reachable when repairCorroborationClusterSize <= 2.
|
|
89
|
+
// NOTE: only the UNDECLARED case warns. An operator who declares an assumedClusterSize larger than
|
|
90
|
+
// the cohort they actually run is equally unable to repair and gets no warning — deliberate, since
|
|
91
|
+
// a declaration is an explicit assertion and this function has no observed cohort to contradict it
|
|
92
|
+
// with. If `feat-admission-floor-from-observed-cohort-high-water-mark` ever lands (deriving the
|
|
93
|
+
// yardstick from observation), that warning becomes cheap and worth adding here.
|
|
94
|
+
if (declaredCohortSize === undefined && clusterSize > minAbsoluteClusterSize) {
|
|
95
|
+
const minimumSelfHealingDeployment = CORROBORATION_FLOOR + 1;
|
|
96
|
+
log('assumed-cluster-size-unset', {
|
|
97
|
+
clusterSize,
|
|
98
|
+
repairCorroborationClusterSize,
|
|
99
|
+
corroborationFloor: CORROBORATION_FLOOR,
|
|
100
|
+
minimumSelfHealingDeployment,
|
|
101
|
+
message: `No clusterPolicy.assumedClusterSize declared: block repair (read-repair and reconcile) requires ` +
|
|
102
|
+
`${CORROBORATION_FLOOR} distinct corroborating peers other than the reader, and that floor is ` +
|
|
103
|
+
`relaxed only for a cohort that DECLARES it is smaller — with ` +
|
|
104
|
+
`repairCorroborationClusterSize=${repairCorroborationClusterSize} it never relaxes. So a deployment ` +
|
|
105
|
+
`that actually runs fewer than ${minimumSelfHealingDeployment} machines can never supply the floor ` +
|
|
106
|
+
`and every repair declines, permanently. If you run fewer than ${minimumSelfHealingDeployment} ` +
|
|
107
|
+
`machines, set clusterPolicy.assumedClusterSize to your real cohort size; it does not lower ` +
|
|
108
|
+
`clusterSize=${clusterSize} (the replication factor). Larger deployments can ignore this.`
|
|
109
|
+
});
|
|
110
|
+
}
|
|
64
111
|
return {
|
|
65
112
|
superMajorityThreshold: options.clusterPolicy?.superMajorityThreshold ?? DEFAULT_SUPER_MAJORITY_THRESHOLD,
|
|
66
113
|
simpleMajorityThreshold: 0.51,
|
|
@@ -82,7 +129,7 @@ export function resolveClusterPolicy(options) {
|
|
|
82
129
|
// Repair corroboration floor, every repair. Defaults strict — to the replication factor — so an
|
|
83
130
|
// unconfigured node cannot have its floor talked down to a single voter by a shrunken cohort
|
|
84
131
|
// view. A genuinely small mesh declares its size (either field) to regain self-repair.
|
|
85
|
-
repairCorroborationClusterSize
|
|
132
|
+
repairCorroborationClusterSize
|
|
86
133
|
};
|
|
87
134
|
}
|
|
88
135
|
//# sourceMappingURL=cluster-policy.js.map
|
|
@@ -1 +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;
|
|
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;AACpG,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,MAAM,GAAG,GAAG,YAAY,CAAC,gBAAgB,CAAC,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAExC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AA+DvC;;;;;GAKG;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,oBAAoB,CAAC;IAChE,MAAM,8BAA8B,GAAG,kBAAkB,IAAI,WAAW,CAAC;IAEzE,gGAAgG;IAChG,4FAA4F;IAC5F,+FAA+F;IAC/F,6FAA6F;IAC7F,oFAAoF;IACpF,EAAE;IACF,mGAAmG;IACnG,gGAAgG;IAChG,iGAAiG;IACjG,8FAA8F;IAC9F,mGAAmG;IACnG,mGAAmG;IACnG,mGAAmG;IACnG,gGAAgG;IAChG,iFAAiF;IACjF,IAAI,kBAAkB,KAAK,SAAS,IAAI,WAAW,GAAG,sBAAsB,EAAE,CAAC;QAC9E,MAAM,4BAA4B,GAAG,mBAAmB,GAAG,CAAC,CAAC;QAC7D,GAAG,CAAC,4BAA4B,EAAE;YACjC,WAAW;YACX,8BAA8B;YAC9B,kBAAkB,EAAE,mBAAmB;YACvC,4BAA4B;YAC5B,OAAO,EACN,kGAAkG;gBAClG,GAAG,mBAAmB,yEAAyE;gBAC/F,+DAA+D;gBAC/D,kCAAkC,8BAA8B,qCAAqC;gBACrG,iCAAiC,4BAA4B,uCAAuC;gBACpG,iEAAiE,4BAA4B,GAAG;gBAChG,6FAA6F;gBAC7F,eAAe,WAAW,gEAAgE;SAC3F,CAAC,CAAC;IACJ,CAAC;IAED,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;KAC9B,CAAC;AACH,CAAC"}
|
|
@@ -199,7 +199,6 @@ export declare class ClusterMember implements ICluster {
|
|
|
199
199
|
private static canonicalJson;
|
|
200
200
|
private computePromiseHash;
|
|
201
201
|
private computeCommitHash;
|
|
202
|
-
private computeSigningPayload;
|
|
203
202
|
private signVote;
|
|
204
203
|
/**
|
|
205
204
|
* Verify one vote signature and classify the outcome (see {@link VerifyOutcome}). Total on hostile
|
|
@@ -217,6 +216,16 @@ export declare class ClusterMember implements ICluster {
|
|
|
217
216
|
private getTransactionPhase;
|
|
218
217
|
private hasMajority;
|
|
219
218
|
private handlePromiseNeeded;
|
|
219
|
+
/**
|
|
220
|
+
* Answer a record that lost the deterministic race to a transaction this member already holds
|
|
221
|
+
* (`docs/correctness.md` Theorems 1 & 9: the loser is TOLD it lost, not ignored — an unanswered
|
|
222
|
+
* loss is indistinguishable from an unreachable cohort at the coordinator). `conflictWith` — the
|
|
223
|
+
* winning rival's messageHash — is folded into the signed payload, so the claim is
|
|
224
|
+
* integrity-protected in transit and readable without parsing prose. NOT a validity judgement:
|
|
225
|
+
* {@link getTransactionPhase} never counts conflict votes toward the permanent-rejection
|
|
226
|
+
* threshold, and the coordinator surfaces them as a retryable loss, never a validator rejection.
|
|
227
|
+
*/
|
|
228
|
+
private handleConflictVoteNeeded;
|
|
220
229
|
/**
|
|
221
230
|
* The full promise-phase decision for a record: admit the declared membership FIRST, then (only if
|
|
222
231
|
* admitted) validate its pend operations. Failing either yields a `{ valid:false, reason }` the caller
|
|
@@ -267,9 +276,9 @@ export declare class ClusterMember implements ICluster {
|
|
|
267
276
|
*
|
|
268
277
|
* NOTE: partition safety needs `2 · membershipAdmissionFraction · superMajorityThreshold > 1` — each
|
|
269
278
|
* 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.
|
|
271
|
-
*
|
|
272
|
-
* `docs/correctness.md` before shipping it.
|
|
279
|
+
* both find them in one K-peer cluster. At the shipped defaults (0.75 · 0.75 — both default to
|
|
280
|
+
* `DEFAULT_SUPER_MAJORITY_THRESHOLD` / `membershipAdmissionFraction`'s own default) that product is
|
|
281
|
+
* 1.125. If either default is ever lowered, re-check Theorem 2 in `docs/correctness.md` before shipping it.
|
|
273
282
|
*/
|
|
274
283
|
private admissionFloor;
|
|
275
284
|
/**
|
|
@@ -389,36 +398,52 @@ export declare class ClusterMember implements ICluster {
|
|
|
389
398
|
private withReconcileTimeout;
|
|
390
399
|
private handleRejection;
|
|
391
400
|
private setupTimeouts;
|
|
392
|
-
|
|
401
|
+
/**
|
|
402
|
+
* Scan this member's reservation table (`activeTransactions`) for a held transaction that
|
|
403
|
+
* conflicts with `record` AND wins the deterministic race against it. Returns the winner's
|
|
404
|
+
* identity — `{ blockedBy: messageHash }` — rather than a bare boolean, because that identity is
|
|
405
|
+
* exactly what the resulting conflict vote must name (`Signature.conflictWith`); the old boolean
|
|
406
|
+
* lost it. `undefined` means no blocking conflict. Side-effectful on the way through: stale
|
|
407
|
+
* entries are swept, and a held transaction that LOSES the race to `record` is cleared.
|
|
408
|
+
*/
|
|
409
|
+
private findConflict;
|
|
410
|
+
/** Number of *approve* promise votes on a record — the count the commit rule uses. */
|
|
411
|
+
private static approvalCount;
|
|
393
412
|
/**
|
|
394
413
|
* Resolve a race between two conflicting transactions. Total and deterministic, so every honest
|
|
395
414
|
* member computes the identical winner (the Theorem 1 Case-2 premise). Order:
|
|
396
|
-
* 1. more promise signatures wins (progress monotonicity — see safety note below);
|
|
397
|
-
* 2. equal
|
|
415
|
+
* 1. more *approve* promise signatures wins (progress monotonicity — see safety note below);
|
|
416
|
+
* 2. equal approval counts → higher aged priority wins (fairness — see {@link recordPriority});
|
|
398
417
|
* 3. still tied → higher message hash wins.
|
|
399
418
|
*
|
|
400
|
-
*
|
|
419
|
+
* The count is APPROVALS, not `promises` keys. `promises` is the vote map — a reject occupies a key
|
|
420
|
+
* there exactly as an approve does — so counting keys would treat a rejection as progress, letting a
|
|
421
|
+
* record that can never commit outrank (and therefore block, via {@link findConflict}) a fresh rival
|
|
422
|
+
* for the whole staleness window. Approvals is also the count the invariant below actually needs:
|
|
423
|
+
* the commit rule is `approvedPromises >= superMajority`, which never looks at rejections.
|
|
424
|
+
*
|
|
425
|
+
* Approval count is FIRST so this comparison never displaces a transaction that is further along.
|
|
401
426
|
* That restores the pre-priority safety invariant: a member commits purely on promise supermajority
|
|
402
427
|
* (`handleCommitNeeded` signs whenever `approvedPromises >= superMajority`; the commit path has NO
|
|
403
428
|
* conflict re-check), so `resolveRace` is the ONLY arbiter among concurrently-pending conflicts.
|
|
404
|
-
* With
|
|
405
|
-
* strictly fewer
|
|
406
|
-
*
|
|
429
|
+
* With approvals-first, once transaction X holds a promise supermajority every conflicting rival Y has
|
|
430
|
+
* strictly fewer approvals — Y can only match X's count by getting the intersecting quorum member to
|
|
431
|
+
* approve it, but that member already holds X at supermajority and `resolveRace(X, Y)` returns
|
|
407
432
|
* `keep-existing` on X's higher count, so it never does. By quorum intersection any Y-supermajority
|
|
408
433
|
* overlaps X's in ≥1 honest member, and that member rejects Y. One winner (docs/correctness.md
|
|
409
434
|
* Theorem 9). Priority-first would break this: it could displace an already-quorum-reached X for a
|
|
410
|
-
* higher-priority Y with fewer
|
|
435
|
+
* higher-priority Y with fewer approvals, letting BOTH commit (split brain) — the regression fixed by
|
|
411
436
|
* ticket occ-priority-first-breaks-promise-monotonicity.
|
|
412
437
|
*
|
|
413
|
-
* Priority is now a tie-break that runs only at EQUAL
|
|
438
|
+
* Priority is now a tie-break that runs only at EQUAL approval counts, which is exactly the
|
|
414
439
|
* concurrent-starvation case aging targets (two fresh rivals, 0 promises each, otherwise coin-flipping
|
|
415
440
|
* on the hash). Priority still breaks those ties deterministically, so aging still solves the stated
|
|
416
441
|
* fairness problem in its common case. It only orders two *concurrently-pending* conflicts; it does NOT
|
|
417
442
|
* defer a fresh pend for an absent aged transaction (that residual — sequential sub-window starvation —
|
|
418
443
|
* is the deferred feat-occ-priority-reservation).
|
|
419
444
|
*
|
|
420
|
-
* NOTE: residual-fairness tripwire. Under
|
|
421
|
-
* rival that has *legitimately* gathered even one more
|
|
445
|
+
* NOTE: residual-fairness tripwire. Under approvals-first an aged transaction can still lose to a fresh
|
|
446
|
+
* rival that has *legitimately* gathered even one more approval — that is not the pure-coin-flip
|
|
422
447
|
* starvation aging targets (equal counts, priority wins), it is the monotonicity behaviour we WANT (a
|
|
423
448
|
* more-progressed rival is never displaced). If deeper fairness against a genuinely-more-progressed
|
|
424
449
|
* rival is ever needed, it belongs to feat-occ-priority-reservation (reserve/defer at pend time), NOT
|
|
@@ -427,7 +452,7 @@ export declare class ClusterMember implements ICluster {
|
|
|
427
452
|
* NOTE: Byzantine self-assert is a fairness DoS, not a safety hole. A coordinator can stamp
|
|
428
453
|
* priority == MaxPriority on every transaction; recordPriority clamps to the cap so it cannot
|
|
429
454
|
* exceed it, and priority never influences validity/operationsHash/stale-read checks — and now sits
|
|
430
|
-
* below the
|
|
455
|
+
* below the approval count, so it can only break equal-count ties it might have ~50% won anyway,
|
|
431
456
|
* degrading to at-worst-status-quo fairness (the same graceful-degradation class as spam under
|
|
432
457
|
* honest-majority). Binding priority to provable age is out of scope (feat-occ-priority-reservation).
|
|
433
458
|
*
|
|
@@ -448,7 +473,7 @@ export declare class ClusterMember implements ICluster {
|
|
|
448
473
|
* NOTE: `message` is fixed for a transaction's whole lifecycle (promises/commits accrue in the
|
|
449
474
|
* separate `promises`/`commits` maps, never in `message`), so a transaction keeps its rank through
|
|
450
475
|
* the commit phase — there is no "priority drops to 0 at commit" asymmetry. resolveRace is only
|
|
451
|
-
* consulted at the promise decision (
|
|
476
|
+
* consulted at the promise decision (findConflict), i.e. between two still-open conflicting
|
|
452
477
|
* transactions, which is exactly the concurrent-contention case priority is meant to order.
|
|
453
478
|
*/
|
|
454
479
|
private recordPriority;
|
|
@@ -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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"}
|