@optimystic/db-p2p 0.26.0 → 0.27.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/certified-claims.d.ts +17 -3
- package/dist/src/cluster/certified-claims.d.ts.map +1 -1
- package/dist/src/cluster/certified-claims.js +5 -3
- package/dist/src/cluster/certified-claims.js.map +1 -1
- package/dist/src/cluster/cluster-repo.d.ts +10 -1
- package/dist/src/cluster/cluster-repo.d.ts.map +1 -1
- package/dist/src/cluster/cluster-repo.js +11 -1
- package/dist/src/cluster/cluster-repo.js.map +1 -1
- package/dist/src/cluster/commit-proof.d.ts +16 -0
- package/dist/src/cluster/commit-proof.d.ts.map +1 -1
- package/dist/src/cluster/commit-proof.js +32 -1
- package/dist/src/cluster/commit-proof.js.map +1 -1
- package/dist/src/cluster/quorum-restore.d.ts +81 -28
- package/dist/src/cluster/quorum-restore.d.ts.map +1 -1
- package/dist/src/cluster/quorum-restore.js +148 -51
- package/dist/src/cluster/quorum-restore.js.map +1 -1
- package/dist/src/cluster/reconcile-block.d.ts +9 -4
- package/dist/src/cluster/reconcile-block.d.ts.map +1 -1
- package/dist/src/cluster/reconcile-block.js +28 -11
- package/dist/src/cluster/reconcile-block.js.map +1 -1
- package/dist/src/libp2p-node-base.d.ts +6 -0
- package/dist/src/libp2p-node-base.d.ts.map +1 -1
- package/dist/src/libp2p-node-base.js.map +1 -1
- package/dist/src/repo/cluster-coordinator.d.ts +9 -0
- package/dist/src/repo/cluster-coordinator.d.ts.map +1 -1
- package/dist/src/repo/cluster-coordinator.js +13 -2
- package/dist/src/repo/cluster-coordinator.js.map +1 -1
- package/dist/src/repo/coordinator-repo.d.ts +34 -2
- package/dist/src/repo/coordinator-repo.d.ts.map +1 -1
- package/dist/src/repo/coordinator-repo.js +57 -3
- package/dist/src/repo/coordinator-repo.js.map +1 -1
- package/package.json +2 -2
- package/src/cluster/certified-claims.ts +22 -9
- package/src/cluster/cluster-repo.ts +12 -1
- package/src/cluster/commit-proof.ts +38 -2
- package/src/cluster/quorum-restore.ts +183 -56
- package/src/cluster/reconcile-block.ts +34 -11
- package/src/libp2p-node-base.ts +6 -0
- package/src/repo/cluster-coordinator.ts +1039 -1027
- package/src/repo/coordinator-repo.ts +1937 -1855
|
@@ -15,8 +15,13 @@ import type { BlockCommitProof } from "./commit-proof.js";
|
|
|
15
15
|
* caller has already verified (`cluster/certified-claims.ts`) and marked via the
|
|
16
16
|
* injected `certified` flag — so a lone honest holder with a valid proof is
|
|
17
17
|
* sufficient where uncertified claims still need distinct-peer corroboration.
|
|
18
|
-
*
|
|
19
|
-
*
|
|
18
|
+
* Certified claims are additionally weighed by the proof's SIGNER COUNT
|
|
19
|
+
* (`certifiedSignerCount`, injected alongside the flag): a single-signer proof —
|
|
20
|
+
* routine since solo cohorts mint their own commit receipts — is one machine's
|
|
21
|
+
* honest word about its own commit, so it wins only where nothing multi-peer
|
|
22
|
+
* contests it, and never outranks several distinct peers agreeing at the same
|
|
23
|
+
* revision. Verification itself never happens here: both selectors stay pure and
|
|
24
|
+
* synchronous; verdicts arrive as booleans and counts.
|
|
20
25
|
*/
|
|
21
26
|
/** A single peer's self-reported (rev, actionId) for a block. */
|
|
22
27
|
export interface RevClaim {
|
|
@@ -39,6 +44,16 @@ export interface RevClaim {
|
|
|
39
44
|
* Never set this from the mere presence of {@link proof}.
|
|
40
45
|
*/
|
|
41
46
|
certified?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Distinct signers in the verified proof, injected by the caller from the certification verdict
|
|
49
|
+
* (`ClaimCertification.signerCount`, `cluster/certified-claims.ts`) — never read off
|
|
50
|
+
* {@link proof} here. Meaningful only when {@link certified} is set. Selection weighs a certified
|
|
51
|
+
* claim as SINGLE-SIGNER when this is absent or below two: the conservative direction, since a
|
|
52
|
+
* single-signer proof (a solo cohort's self-signed commit receipt) must never outrank multi-peer
|
|
53
|
+
* agreement, and a caller that forgot to plumb the count should degrade toward corroboration,
|
|
54
|
+
* not toward trusting one signature.
|
|
55
|
+
*/
|
|
56
|
+
certifiedSignerCount?: number;
|
|
42
57
|
}
|
|
43
58
|
/** The (rev, actionId) pair a quorum agreed on, plus the peers that corroborated it. */
|
|
44
59
|
export interface QuorumRev {
|
|
@@ -120,30 +135,40 @@ export declare function corroboratorCapacity(cohortPeerCount: number, repairCorr
|
|
|
120
135
|
*
|
|
121
136
|
* **Certified claims** (`certified === true`, injected by a caller that verified the claim's
|
|
122
137
|
* cohort commit proof — see `cluster/certified-claims.ts`) short-circuit the distinct-peer rule,
|
|
123
|
-
* because the proof's signature set IS the corroboration
|
|
138
|
+
* because the proof's signature set IS the corroboration — weighed by how many signers that set
|
|
139
|
+
* actually holds ({@link RevClaim.certifiedSignerCount}):
|
|
124
140
|
*
|
|
125
141
|
* - No certified claims → today's corroboration result, unchanged.
|
|
126
142
|
* - A corroborated pair at a HIGHER rev than every certified claim wins — corroboration stays a
|
|
127
143
|
* legitimate weaker path, so a legacy uncertified tail written after the last proven rev
|
|
128
144
|
* remains readable.
|
|
129
|
-
* -
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
145
|
+
* - A MULTI-SIGNER certified claim (two-plus signers) at the top certified rev wins over an
|
|
146
|
+
* equal-rev corroborated pair and over any uncorroborated claim: the proof outweighs votes.
|
|
147
|
+
* Single-signer certified claims at that rev neither outrank it nor equivocate against it — a
|
|
148
|
+
* solo cohort's self-signed receipt is one machine's word, not the cohort's second signature.
|
|
149
|
+
* - A SINGLE-SIGNER-only certified rev still wins where nothing multi-peer contests it (a lone
|
|
150
|
+
* holder with a solo proof stays repairable), but it never beats corroboration by
|
|
151
|
+
* {@link CORROBORATION_FLOOR}-plus distinct peers at the SAME revision — one machine that was
|
|
152
|
+
* briefly alone must not outrank the cohort that stayed together. A corroborated pair that
|
|
153
|
+
* AGREES with the sole certified action is convergence, not a contest; the certified verdict
|
|
154
|
+
* is kept.
|
|
155
|
+
* - Two distinct `actionId`s still CONTENDING at the top certified rev is equivocation — the
|
|
156
|
+
* same keys provably signed two different actions into one revision — and the whole selection
|
|
157
|
+
* declines (`undefined`). Callers distinguish this decline from a plain no-quorum via
|
|
135
158
|
* {@link certifiedEquivocation}.
|
|
136
159
|
*/
|
|
137
160
|
export declare function selectQuorumRev(claims: RevClaim[], simpleMajorityThreshold: number, corroboratorCapacity?: number): QuorumRev | undefined;
|
|
138
161
|
/**
|
|
139
162
|
* The conflicting certified set at the top certified rev, when there is one: two-plus distinct
|
|
140
|
-
* `actionId`s
|
|
141
|
-
*
|
|
142
|
-
*
|
|
163
|
+
* `actionId`s that CONTEND there ({@link certifiedContenders}) — each carrying a verified cohort
|
|
164
|
+
* commit proof for the SAME revision, at comparable weight. It deserves a distinct log line from a
|
|
165
|
+
* plain no-quorum — whoever holds the signing keys provably signed both sides. Selection stays
|
|
166
|
+
* pure, so callers do the logging with what this reports.
|
|
143
167
|
*
|
|
144
|
-
* `undefined` when no certified claim exists or the top certified rev
|
|
145
|
-
* conflicts at LOWER certified revs are history already superseded,
|
|
146
|
-
*
|
|
168
|
+
* `undefined` when no certified claim exists or a single action contends at the top certified rev —
|
|
169
|
+
* conflicts at LOWER certified revs are history already superseded, and a single-signer proof
|
|
170
|
+
* disagreeing with a multi-signer one at the same rev is a solo machine's fork losing to the
|
|
171
|
+
* cohort, not equivocation worth declining over.
|
|
147
172
|
*
|
|
148
173
|
* **Ask this only on a decline.** A non-`undefined` result does NOT imply {@link selectQuorumRev}
|
|
149
174
|
* returned `undefined`: a corroborated pair STRICTLY above the top certified rev still wins, and
|
|
@@ -166,6 +191,13 @@ export interface BlockHashCandidate {
|
|
|
166
191
|
* bytes), so the cohort's signatures stand in for other peers serving the same hash.
|
|
167
192
|
*/
|
|
168
193
|
certified?: boolean;
|
|
194
|
+
/**
|
|
195
|
+
* Distinct signers in the verified proof, from the certification verdict
|
|
196
|
+
* (`ContentCertification.signerCount`) — the content-side sibling of
|
|
197
|
+
* {@link RevClaim.certifiedSignerCount}, with the same weighing: meaningful only when
|
|
198
|
+
* {@link certified} is set, and absent or sub-two counts as single-signer.
|
|
199
|
+
*/
|
|
200
|
+
certifiedSignerCount?: number;
|
|
169
201
|
}
|
|
170
202
|
/**
|
|
171
203
|
* Among candidates already known to corroborate the target `(rev, actionId)`,
|
|
@@ -188,26 +220,47 @@ export interface BlockHashCandidate {
|
|
|
188
220
|
* *genuinely* that small reaches this branch.
|
|
189
221
|
*
|
|
190
222
|
* **Certified candidates** (`certified === true` — a caller verified a cohort commit proof whose
|
|
191
|
-
* declared digest matches these exact bytes)
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
223
|
+
* declared digest matches these exact bytes) are weighed by the proof's signer count, mirroring
|
|
224
|
+
* {@link selectQuorumRev}:
|
|
225
|
+
*
|
|
226
|
+
* - Exactly one distinct MULTI-SIGNER certified hash → that block wins outright, however many
|
|
227
|
+
* peers served anything else: the cohort's own signatures over the digest outweigh other
|
|
228
|
+
* carriers' bytes. Two-plus distinct multi-signer certified hashes is certified content
|
|
229
|
+
* equivocation → decline (`undefined`); a single-signer certified hash alongside a
|
|
230
|
+
* multi-signer one neither wins nor forces that decline (a solo receipt cannot equivocate
|
|
231
|
+
* against the cohort's proof).
|
|
232
|
+
* - SINGLE-SIGNER-only certified hashes no longer short-circuit: a hash group carried by
|
|
233
|
+
* {@link CORROBORATION_FLOOR}-plus distinct peers that meets the ordinary quorum displaces
|
|
234
|
+
* them (two-plus such groups is a genuine content disagreement → decline, as ever). With no
|
|
235
|
+
* multi-peer group to defer to, a sole single-signer certified hash still wins on its proof —
|
|
236
|
+
* a lone certified holder stays repairable — and two-plus distinct ones decline.
|
|
237
|
+
* - No certified candidate → the hash quorum below, unchanged.
|
|
238
|
+
*
|
|
239
|
+
* Callers name the certified declines via {@link certifiedContentEquivocation}.
|
|
196
240
|
*/
|
|
197
241
|
export declare function selectQuorumBlock(candidates: BlockHashCandidate[], simpleMajorityThreshold: number, corroboratorCapacity?: number): {
|
|
198
242
|
block: IBlock;
|
|
199
243
|
hash: string;
|
|
200
244
|
} | undefined;
|
|
201
245
|
/**
|
|
202
|
-
* The conflicting certified hashes when there are two or more — the content-side
|
|
203
|
-
* {@link certifiedEquivocation}, and the reason {@link selectQuorumBlock} declines
|
|
204
|
-
* Candidates reaching that selector all carry the SAME `(rev, actionId)`, so two
|
|
205
|
-
* mean the
|
|
206
|
-
* operator must be able to tell apart from the routine "not enough carriers
|
|
207
|
-
* declines return `undefined`, so without this they log identically.
|
|
208
|
-
*
|
|
209
|
-
*
|
|
246
|
+
* The conflicting certified hashes when there are two or more CONTENDING — the content-side
|
|
247
|
+
* sibling of {@link certifiedEquivocation}, and the reason {@link selectQuorumBlock} declines
|
|
248
|
+
* outright. Candidates reaching that selector all carry the SAME `(rev, actionId)`, so two
|
|
249
|
+
* contending certified hashes mean the same keys signed two different digests into one revision: a
|
|
250
|
+
* provable compromise an operator must be able to tell apart from the routine "not enough carriers
|
|
251
|
+
* agreed" decline. Both declines return `undefined`, so without this they log identically.
|
|
252
|
+
* Contention mirrors the selector: multi-signer certified hashes when any exist, else the
|
|
253
|
+
* single-signer ones among themselves — a solo receipt disagreeing with a cohort proof is a fork
|
|
254
|
+
* losing, not equivocation.
|
|
255
|
+
*
|
|
256
|
+
* `undefined` when fewer than two certified hashes contend — including the ordinary
|
|
210
257
|
* no-certified-candidate case, where a decline really is a plain content-quorum shortfall.
|
|
258
|
+
*
|
|
259
|
+
* **Ask this only on a decline**, exactly as with {@link certifiedEquivocation}: a non-`undefined`
|
|
260
|
+
* result does NOT imply {@link selectQuorumBlock} returned `undefined`. Two contending
|
|
261
|
+
* single-signer certified hashes yield to a {@link CORROBORATION_FLOOR}-plus-carrier quorum group,
|
|
262
|
+
* so selection can succeed while the solo-versus-solo conflict is still reported here. Call it when
|
|
263
|
+
* selection declined, to say WHY.
|
|
211
264
|
*/
|
|
212
265
|
export declare function certifiedContentEquivocation(candidates: BlockHashCandidate[]): {
|
|
213
266
|
hashes: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quorum-restore.d.ts","sourceRoot":"","sources":["../../../src/cluster/quorum-restore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D
|
|
1
|
+
{"version":3,"file":"quorum-restore.d.ts","sourceRoot":"","sources":["../../../src/cluster/quorum-restore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,iEAAiE;AACjE,MAAM,WAAW,QAAQ;IACxB,wFAAwF;IACxF,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;;;;OAQG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,wFAAwF;AACxF,MAAM,WAAW,SAAS;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,yFAAyF;IACzF,SAAS,CAAC,EAAE,IAAI,CAAC;CACjB;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CACzB,cAAc,EAAE,MAAM,EACtB,uBAAuB,EAAE,MAAM,EAC/B,oBAAoB,GAAE,MAAiC,GACrD,MAAM,CAGR;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,oBAAoB,CAAC,eAAe,EAAE,MAAM,EAAE,8BAA8B,EAAE,MAAM,GAAG,MAAM,CAE5G;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,wBAAgB,eAAe,CAC9B,MAAM,EAAE,QAAQ,EAAE,EAClB,uBAAuB,EAAE,MAAM,EAC/B,oBAAoB,CAAC,EAAE,MAAM,GAC3B,SAAS,GAAG,SAAS,CA8DvB;AAiDD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,SAAS,CAM1G;AAED;wDACwD;AACxD,MAAM,WAAW,kBAAkB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,iBAAiB,CAChC,UAAU,EAAE,kBAAkB,EAAE,EAChC,uBAAuB,EAAE,MAAM,EAC/B,oBAAoB,CAAC,EAAE,MAAM,GAC3B;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAmD7C;AAmBD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,kBAAkB,EAAE,GAAG;IAAE,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,SAAS,CAK/G"}
|
|
@@ -70,18 +70,26 @@ export function corroboratorCapacity(cohortPeerCount, repairCorroborationCluster
|
|
|
70
70
|
*
|
|
71
71
|
* **Certified claims** (`certified === true`, injected by a caller that verified the claim's
|
|
72
72
|
* cohort commit proof — see `cluster/certified-claims.ts`) short-circuit the distinct-peer rule,
|
|
73
|
-
* because the proof's signature set IS the corroboration
|
|
73
|
+
* because the proof's signature set IS the corroboration — weighed by how many signers that set
|
|
74
|
+
* actually holds ({@link RevClaim.certifiedSignerCount}):
|
|
74
75
|
*
|
|
75
76
|
* - No certified claims → today's corroboration result, unchanged.
|
|
76
77
|
* - A corroborated pair at a HIGHER rev than every certified claim wins — corroboration stays a
|
|
77
78
|
* legitimate weaker path, so a legacy uncertified tail written after the last proven rev
|
|
78
79
|
* remains readable.
|
|
79
|
-
* -
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
80
|
+
* - A MULTI-SIGNER certified claim (two-plus signers) at the top certified rev wins over an
|
|
81
|
+
* equal-rev corroborated pair and over any uncorroborated claim: the proof outweighs votes.
|
|
82
|
+
* Single-signer certified claims at that rev neither outrank it nor equivocate against it — a
|
|
83
|
+
* solo cohort's self-signed receipt is one machine's word, not the cohort's second signature.
|
|
84
|
+
* - A SINGLE-SIGNER-only certified rev still wins where nothing multi-peer contests it (a lone
|
|
85
|
+
* holder with a solo proof stays repairable), but it never beats corroboration by
|
|
86
|
+
* {@link CORROBORATION_FLOOR}-plus distinct peers at the SAME revision — one machine that was
|
|
87
|
+
* briefly alone must not outrank the cohort that stayed together. A corroborated pair that
|
|
88
|
+
* AGREES with the sole certified action is convergence, not a contest; the certified verdict
|
|
89
|
+
* is kept.
|
|
90
|
+
* - Two distinct `actionId`s still CONTENDING at the top certified rev is equivocation — the
|
|
91
|
+
* same keys provably signed two different actions into one revision — and the whole selection
|
|
92
|
+
* declines (`undefined`). Callers distinguish this decline from a plain no-quorum via
|
|
85
93
|
* {@link certifiedEquivocation}.
|
|
86
94
|
*/
|
|
87
95
|
export function selectQuorumRev(claims, simpleMajorityThreshold, corroboratorCapacity) {
|
|
@@ -124,15 +132,30 @@ export function selectQuorumRev(claims, simpleMajorityThreshold, corroboratorCap
|
|
|
124
132
|
// `corroborated`), so it cannot outrank a proof.
|
|
125
133
|
if (corroborated && corroborated.rev > certified.rev)
|
|
126
134
|
return corroborated;
|
|
127
|
-
|
|
128
|
-
//
|
|
129
|
-
|
|
135
|
+
const contenders = certifiedContenders(certified.byAction);
|
|
136
|
+
// A single-signer-only certified rev loses the equal-rev tie to genuinely multi-peer
|
|
137
|
+
// corroboration — unless the corroborated pair AGREES with the sole certified action, which is
|
|
138
|
+
// convergence rather than a contest and keeps the certified verdict (and its logging/penalty
|
|
139
|
+
// exemptions) intact.
|
|
140
|
+
// NOTE: the weighing reaches EQUAL revisions only. A solo fork that committed twice while its
|
|
141
|
+
// cohort committed once claims the higher rev and still wins above. That is not an oversight of
|
|
142
|
+
// this rule: a claim carries no lineage, so "one peer ahead of two" is identical whether it
|
|
143
|
+
// forked or the two are lagging, and refusing it would break ordinary lagging-cohort repair.
|
|
144
|
+
// Pinned by 'does NOT reach a solo fork one revision AHEAD' in quorum-restore-certified.spec.ts;
|
|
145
|
+
// closing it needs new evidence — debt-repair-cannot-tell-a-fork-from-a-lagging-cohort.
|
|
146
|
+
if (!contenders.multiSigner && corroborated && corroborated.rev === certified.rev
|
|
147
|
+
&& corroborated.supporters.length >= CORROBORATION_FLOOR
|
|
148
|
+
&& !(certified.byAction.size === 1 && certified.byAction.has(corroborated.actionId))) {
|
|
149
|
+
return corroborated;
|
|
150
|
+
}
|
|
151
|
+
// Two actions provably signed into the same top revision by contending proofs: decline the
|
|
152
|
+
// whole selection rather than pick a side. Callers log via certifiedEquivocation.
|
|
153
|
+
if (contenders.entries.length !== 1)
|
|
130
154
|
return undefined;
|
|
131
|
-
const [
|
|
132
|
-
|
|
133
|
-
return { rev: certified.rev, actionId, supporters: [...supporters], certified: true };
|
|
155
|
+
const [actionId, group] = contenders.entries[0];
|
|
156
|
+
return { rev: certified.rev, actionId, supporters: [...group.supporters], certified: true };
|
|
134
157
|
}
|
|
135
|
-
/** Certified claims at the top certified rev, keyed by actionId →
|
|
158
|
+
/** Certified claims at the top certified rev, keyed by actionId → the claimants behind each. */
|
|
136
159
|
function certifiedGroups(claims) {
|
|
137
160
|
let top;
|
|
138
161
|
for (const c of claims) {
|
|
@@ -145,24 +168,43 @@ function certifiedGroups(claims) {
|
|
|
145
168
|
for (const c of claims) {
|
|
146
169
|
if (c.certified !== true || c.rev !== top)
|
|
147
170
|
continue;
|
|
148
|
-
let
|
|
149
|
-
if (!
|
|
150
|
-
|
|
151
|
-
byAction.set(c.actionId,
|
|
171
|
+
let g = byAction.get(c.actionId);
|
|
172
|
+
if (!g) {
|
|
173
|
+
g = { supporters: new Set(), multiSigner: false };
|
|
174
|
+
byAction.set(c.actionId, g);
|
|
152
175
|
}
|
|
153
|
-
|
|
176
|
+
g.supporters.add(c.peerId);
|
|
177
|
+
// Absent or sub-two count weighs as single-signer — see RevClaim.certifiedSignerCount.
|
|
178
|
+
if ((c.certifiedSignerCount ?? 1) >= 2)
|
|
179
|
+
g.multiSigner = true;
|
|
154
180
|
}
|
|
155
181
|
return { rev: top, byAction };
|
|
156
182
|
}
|
|
183
|
+
/**
|
|
184
|
+
* Which certified actions at the top rev actually CONTEND for selection. A multi-signer proof is
|
|
185
|
+
* the cohort's own signature set; a single-signer proof is one machine's word about its own solo
|
|
186
|
+
* commit — so when any action is multi-signer-backed, only the multi-signer-backed ones contend
|
|
187
|
+
* (a solo receipt can neither outrank nor equivocate against a cohort proof), and only with no
|
|
188
|
+
* multi-signer action anywhere do the single-signer ones contend among themselves. One helper so
|
|
189
|
+
* {@link selectQuorumRev} and {@link certifiedEquivocation} cannot drift on the rule.
|
|
190
|
+
*/
|
|
191
|
+
function certifiedContenders(byAction) {
|
|
192
|
+
const multi = [...byAction].filter(([, g]) => g.multiSigner);
|
|
193
|
+
return multi.length > 0
|
|
194
|
+
? { entries: multi, multiSigner: true }
|
|
195
|
+
: { entries: [...byAction], multiSigner: false };
|
|
196
|
+
}
|
|
157
197
|
/**
|
|
158
198
|
* The conflicting certified set at the top certified rev, when there is one: two-plus distinct
|
|
159
|
-
* `actionId`s
|
|
160
|
-
*
|
|
161
|
-
*
|
|
199
|
+
* `actionId`s that CONTEND there ({@link certifiedContenders}) — each carrying a verified cohort
|
|
200
|
+
* commit proof for the SAME revision, at comparable weight. It deserves a distinct log line from a
|
|
201
|
+
* plain no-quorum — whoever holds the signing keys provably signed both sides. Selection stays
|
|
202
|
+
* pure, so callers do the logging with what this reports.
|
|
162
203
|
*
|
|
163
|
-
* `undefined` when no certified claim exists or the top certified rev
|
|
164
|
-
* conflicts at LOWER certified revs are history already superseded,
|
|
165
|
-
*
|
|
204
|
+
* `undefined` when no certified claim exists or a single action contends at the top certified rev —
|
|
205
|
+
* conflicts at LOWER certified revs are history already superseded, and a single-signer proof
|
|
206
|
+
* disagreeing with a multi-signer one at the same rev is a solo machine's fork losing to the
|
|
207
|
+
* cohort, not equivocation worth declining over.
|
|
166
208
|
*
|
|
167
209
|
* **Ask this only on a decline.** A non-`undefined` result does NOT imply {@link selectQuorumRev}
|
|
168
210
|
* returned `undefined`: a corroborated pair STRICTLY above the top certified rev still wins, and
|
|
@@ -171,9 +213,12 @@ function certifiedGroups(claims) {
|
|
|
171
213
|
*/
|
|
172
214
|
export function certifiedEquivocation(claims) {
|
|
173
215
|
const groups = certifiedGroups(claims);
|
|
174
|
-
if (!groups
|
|
216
|
+
if (!groups)
|
|
175
217
|
return undefined;
|
|
176
|
-
|
|
218
|
+
const contenders = certifiedContenders(groups.byAction);
|
|
219
|
+
if (contenders.entries.length < 2)
|
|
220
|
+
return undefined;
|
|
221
|
+
return { rev: groups.rev, actionIds: contenders.entries.map(([actionId]) => actionId) };
|
|
177
222
|
}
|
|
178
223
|
/**
|
|
179
224
|
* Among candidates already known to corroborate the target `(rev, actionId)`,
|
|
@@ -196,22 +241,34 @@ export function certifiedEquivocation(claims) {
|
|
|
196
241
|
* *genuinely* that small reaches this branch.
|
|
197
242
|
*
|
|
198
243
|
* **Certified candidates** (`certified === true` — a caller verified a cohort commit proof whose
|
|
199
|
-
* declared digest matches these exact bytes)
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
244
|
+
* declared digest matches these exact bytes) are weighed by the proof's signer count, mirroring
|
|
245
|
+
* {@link selectQuorumRev}:
|
|
246
|
+
*
|
|
247
|
+
* - Exactly one distinct MULTI-SIGNER certified hash → that block wins outright, however many
|
|
248
|
+
* peers served anything else: the cohort's own signatures over the digest outweigh other
|
|
249
|
+
* carriers' bytes. Two-plus distinct multi-signer certified hashes is certified content
|
|
250
|
+
* equivocation → decline (`undefined`); a single-signer certified hash alongside a
|
|
251
|
+
* multi-signer one neither wins nor forces that decline (a solo receipt cannot equivocate
|
|
252
|
+
* against the cohort's proof).
|
|
253
|
+
* - SINGLE-SIGNER-only certified hashes no longer short-circuit: a hash group carried by
|
|
254
|
+
* {@link CORROBORATION_FLOOR}-plus distinct peers that meets the ordinary quorum displaces
|
|
255
|
+
* them (two-plus such groups is a genuine content disagreement → decline, as ever). With no
|
|
256
|
+
* multi-peer group to defer to, a sole single-signer certified hash still wins on its proof —
|
|
257
|
+
* a lone certified holder stays repairable — and two-plus distinct ones decline.
|
|
258
|
+
* - No certified candidate → the hash quorum below, unchanged.
|
|
259
|
+
*
|
|
260
|
+
* Callers name the certified declines via {@link certifiedContentEquivocation}.
|
|
204
261
|
*/
|
|
205
262
|
export function selectQuorumBlock(candidates, simpleMajorityThreshold, corroboratorCapacity) {
|
|
206
263
|
if (candidates.length === 0)
|
|
207
264
|
return undefined;
|
|
208
265
|
const certifiedByHash = certifiedHashes(candidates);
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
const [hash, block] =
|
|
266
|
+
const multiSignerHashes = [...certifiedByHash].filter(([, v]) => v.multiSigner);
|
|
267
|
+
if (multiSignerHashes.length === 1) {
|
|
268
|
+
const [hash, { block }] = multiSignerHashes[0];
|
|
212
269
|
return { block, hash };
|
|
213
270
|
}
|
|
214
|
-
if (
|
|
271
|
+
if (multiSignerHashes.length > 1)
|
|
215
272
|
return undefined; // certified content equivocation — decline
|
|
216
273
|
// One vote per distinct peer per hash group, matching selectQuorumRev — a peer appearing twice
|
|
217
274
|
// must not be able to second itself into a content quorum.
|
|
@@ -228,34 +285,74 @@ export function selectQuorumBlock(candidates, simpleMajorityThreshold, corrobora
|
|
|
228
285
|
}
|
|
229
286
|
const quorum = quorumSize(voters.size, simpleMajorityThreshold, corroboratorCapacity);
|
|
230
287
|
const meeting = [...groups.entries()].filter(([, g]) => g.supporters.size >= quorum);
|
|
231
|
-
|
|
232
|
-
|
|
288
|
+
if (certifiedByHash.size === 0) {
|
|
289
|
+
// Exactly one hash may meet quorum; a tie is a genuine content disagreement → decline.
|
|
290
|
+
if (meeting.length !== 1)
|
|
291
|
+
return undefined;
|
|
292
|
+
const [hash, group] = meeting[0];
|
|
293
|
+
return { block: group.block, hash };
|
|
294
|
+
}
|
|
295
|
+
// Only single-signer certified hashes remain. Genuinely multi-peer agreement — a quorum-meeting
|
|
296
|
+
// group of CORROBORATION_FLOOR-plus distinct carriers — outranks a solo proof, with the usual
|
|
297
|
+
// uniqueness rule among such groups. (A quorum-meeting group of ONE carrier, possible only on a
|
|
298
|
+
// capacity-one cohort, is a bare assertion and does not displace a verified proof.)
|
|
299
|
+
const multiPeer = meeting.filter(([, g]) => g.supporters.size >= CORROBORATION_FLOOR);
|
|
300
|
+
if (multiPeer.length > 1)
|
|
233
301
|
return undefined;
|
|
234
|
-
|
|
235
|
-
|
|
302
|
+
if (multiPeer.length === 1) {
|
|
303
|
+
const [hash, group] = multiPeer[0];
|
|
304
|
+
return { block: group.block, hash };
|
|
305
|
+
}
|
|
306
|
+
// No multi-peer agreement to defer to: a sole single-signer certified hash wins on its proof;
|
|
307
|
+
// two-plus distinct ones are solo-vs-solo equivocation → decline.
|
|
308
|
+
if (certifiedByHash.size > 1)
|
|
309
|
+
return undefined;
|
|
310
|
+
const [entry] = certifiedByHash;
|
|
311
|
+
const [hash, { block }] = entry;
|
|
312
|
+
return { block, hash };
|
|
236
313
|
}
|
|
237
|
-
/** Distinct hashes carried by certified candidates → the first block instance serving each
|
|
314
|
+
/** Distinct hashes carried by certified candidates → the first block instance serving each, and
|
|
315
|
+
* whether any certified candidate at that hash carried a two-plus-signer proof. */
|
|
238
316
|
function certifiedHashes(candidates) {
|
|
239
317
|
const byHash = new Map();
|
|
240
318
|
for (const c of candidates) {
|
|
241
|
-
if (c.certified
|
|
242
|
-
|
|
319
|
+
if (c.certified !== true)
|
|
320
|
+
continue;
|
|
321
|
+
let entry = byHash.get(c.hash);
|
|
322
|
+
if (!entry) {
|
|
323
|
+
entry = { block: c.block, multiSigner: false };
|
|
324
|
+
byHash.set(c.hash, entry);
|
|
325
|
+
}
|
|
326
|
+
// Absent or sub-two count weighs as single-signer — see BlockHashCandidate.certifiedSignerCount.
|
|
327
|
+
if ((c.certifiedSignerCount ?? 1) >= 2)
|
|
328
|
+
entry.multiSigner = true;
|
|
243
329
|
}
|
|
244
330
|
return byHash;
|
|
245
331
|
}
|
|
246
332
|
/**
|
|
247
|
-
* The conflicting certified hashes when there are two or more — the content-side
|
|
248
|
-
* {@link certifiedEquivocation}, and the reason {@link selectQuorumBlock} declines
|
|
249
|
-
* Candidates reaching that selector all carry the SAME `(rev, actionId)`, so two
|
|
250
|
-
* mean the
|
|
251
|
-
* operator must be able to tell apart from the routine "not enough carriers
|
|
252
|
-
* declines return `undefined`, so without this they log identically.
|
|
333
|
+
* The conflicting certified hashes when there are two or more CONTENDING — the content-side
|
|
334
|
+
* sibling of {@link certifiedEquivocation}, and the reason {@link selectQuorumBlock} declines
|
|
335
|
+
* outright. Candidates reaching that selector all carry the SAME `(rev, actionId)`, so two
|
|
336
|
+
* contending certified hashes mean the same keys signed two different digests into one revision: a
|
|
337
|
+
* provable compromise an operator must be able to tell apart from the routine "not enough carriers
|
|
338
|
+
* agreed" decline. Both declines return `undefined`, so without this they log identically.
|
|
339
|
+
* Contention mirrors the selector: multi-signer certified hashes when any exist, else the
|
|
340
|
+
* single-signer ones among themselves — a solo receipt disagreeing with a cohort proof is a fork
|
|
341
|
+
* losing, not equivocation.
|
|
253
342
|
*
|
|
254
|
-
* `undefined` when fewer than two
|
|
343
|
+
* `undefined` when fewer than two certified hashes contend — including the ordinary
|
|
255
344
|
* no-certified-candidate case, where a decline really is a plain content-quorum shortfall.
|
|
345
|
+
*
|
|
346
|
+
* **Ask this only on a decline**, exactly as with {@link certifiedEquivocation}: a non-`undefined`
|
|
347
|
+
* result does NOT imply {@link selectQuorumBlock} returned `undefined`. Two contending
|
|
348
|
+
* single-signer certified hashes yield to a {@link CORROBORATION_FLOOR}-plus-carrier quorum group,
|
|
349
|
+
* so selection can succeed while the solo-versus-solo conflict is still reported here. Call it when
|
|
350
|
+
* selection declined, to say WHY.
|
|
256
351
|
*/
|
|
257
352
|
export function certifiedContentEquivocation(candidates) {
|
|
258
353
|
const byHash = certifiedHashes(candidates);
|
|
259
|
-
|
|
354
|
+
const multi = [...byHash].filter(([, v]) => v.multiSigner);
|
|
355
|
+
const contenders = multi.length > 0 ? multi : [...byHash];
|
|
356
|
+
return contenders.length < 2 ? undefined : { hashes: contenders.map(([hash]) => hash) };
|
|
260
357
|
}
|
|
261
358
|
//# sourceMappingURL=quorum-restore.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quorum-restore.js","sourceRoot":"","sources":["../../../src/cluster/quorum-restore.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"quorum-restore.js","sourceRoot":"","sources":["../../../src/cluster/quorum-restore.ts"],"names":[],"mappings":"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"}
|
|
@@ -52,8 +52,11 @@ export interface ReconcileBlockDeps {
|
|
|
52
52
|
*
|
|
53
53
|
* Peer-attached cohort commit proofs are verified first ({@link certifyCandidates}) and both gates
|
|
54
54
|
* weigh the verdicts: a claim — and, separately, the bytes — that a verified proof certifies is
|
|
55
|
-
* accepted with no second peer
|
|
56
|
-
*
|
|
55
|
+
* accepted with no second peer where nothing multi-peer contests it. The proof's signer count is
|
|
56
|
+
* weighed too: a SINGLE-SIGNER proof (a solo cohort's self-signed receipt) never outranks several
|
|
57
|
+
* distinct peers agreeing at the same revision or on the same bytes — see `quorum-restore.ts`. The
|
|
58
|
+
* proof that certified the agreed bytes is persisted alongside them so the repaired replica serves
|
|
59
|
+
* it onward.
|
|
57
60
|
*
|
|
58
61
|
* Both quorums are capped by {@link corroboratorCapacity} for the claims that still need
|
|
59
62
|
* corroboration: demanding two corroborators from a cohort that contains exactly one other peer is
|
|
@@ -69,8 +72,10 @@ export interface ReconcileBlockDeps {
|
|
|
69
72
|
* no honest majority to appeal to in the first place. It is closed for a candidate that carries a
|
|
70
73
|
* verified cohort commit proof — {@link certifyCandidates} binds the proof's declared digest to the
|
|
71
74
|
* served bytes, which is a check against the *cohort's own signatures* rather than against other
|
|
72
|
-
* peers, so a certified carrier wins the content gate
|
|
73
|
-
*
|
|
75
|
+
* peers, so a certified carrier wins the content gate with no second carrier and this exposure
|
|
76
|
+
* never applies to it. (Weighing still applies at larger widths: a SINGLE-SIGNER certified carrier
|
|
77
|
+
* does not displace a multi-peer hash quorum — see `selectQuorumBlock` — but at the capacity-one
|
|
78
|
+
* width this paragraph describes there is no multi-peer group to lose to.) It remains open for a proof-less candidate, and for the residual that layer 1 proves only
|
|
74
79
|
* that the listed signers signed (`feat-cluster-membership-threshold-cert-anchoring`).
|
|
75
80
|
*
|
|
76
81
|
* Declines are cheap and retryable: nothing is persisted, nothing is marked, and the next commit
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconcile-block.d.ts","sourceRoot":"","sources":["../../../src/cluster/reconcile-block.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAY,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAEhF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAO9D,OAAO,EACqE,KAAK,cAAc,EAC9F,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAK1D;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"reconcile-block.d.ts","sourceRoot":"","sources":["../../../src/cluster/reconcile-block.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAY,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAEhF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAO9D,OAAO,EACqE,KAAK,cAAc,EAC9F,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAK1D;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAmCzC,wGAAwG;AACxG,MAAM,WAAW,kBAAkB;IAClC,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAC;IACnB,2GAA2G;IAC3G,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAAC;IACtF;;;;OAIG;IACH,mBAAmB,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,CAAC,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7H,oFAAoF;IACpF,uBAAuB,EAAE,MAAM,CAAC;IAChC,wFAAwF;IACxF,sBAAsB,EAAE,MAAM,CAAC;IAC/B,8GAA8G;IAC9G,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B;;;;;;;;OAQG;IACH,8BAA8B,EAAE,MAAM,CAAC;IACvC,iFAAiF;IACjF,UAAU,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;CACjD;AAqMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,kBAAkB,GAAG,sBAAsB,CAmGrF"}
|