@optimystic/db-core 0.14.1 → 0.16.2
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/blocks/block-store.d.ts +18 -1
- package/dist/src/blocks/block-store.d.ts.map +1 -1
- package/dist/src/blocks/helpers.d.ts +2 -2
- package/dist/src/blocks/helpers.d.ts.map +1 -1
- package/dist/src/blocks/helpers.js +2 -2
- package/dist/src/blocks/helpers.js.map +1 -1
- package/dist/src/btree/btree.d.ts +27 -6
- package/dist/src/btree/btree.d.ts.map +1 -1
- package/dist/src/btree/btree.js +104 -61
- package/dist/src/btree/btree.js.map +1 -1
- package/dist/src/chain/chain.d.ts.map +1 -1
- package/dist/src/chain/chain.js +11 -1
- package/dist/src/chain/chain.js.map +1 -1
- package/dist/src/cluster/index.d.ts +1 -0
- package/dist/src/cluster/index.d.ts.map +1 -1
- package/dist/src/cluster/index.js +1 -0
- package/dist/src/cluster/index.js.map +1 -1
- package/dist/src/cluster/membership.d.ts +49 -0
- package/dist/src/cluster/membership.d.ts.map +1 -0
- package/dist/src/cluster/membership.js +75 -0
- package/dist/src/cluster/membership.js.map +1 -0
- package/dist/src/cluster/structs.d.ts +50 -1
- package/dist/src/cluster/structs.d.ts.map +1 -1
- package/dist/src/cluster/structs.js +9 -1
- package/dist/src/cluster/structs.js.map +1 -1
- package/dist/src/cohort-topic/addressing.d.ts +8 -2
- package/dist/src/cohort-topic/addressing.d.ts.map +1 -1
- package/dist/src/cohort-topic/addressing.js +11 -3
- package/dist/src/cohort-topic/addressing.js.map +1 -1
- package/dist/src/cohort-topic/antidos/bootstrap-evidence.d.ts +13 -7
- package/dist/src/cohort-topic/antidos/bootstrap-evidence.d.ts.map +1 -1
- package/dist/src/cohort-topic/antidos/bootstrap-evidence.js +17 -6
- package/dist/src/cohort-topic/antidos/bootstrap-evidence.js.map +1 -1
- package/dist/src/cohort-topic/antidos/replay-guard.d.ts +17 -0
- package/dist/src/cohort-topic/antidos/replay-guard.d.ts.map +1 -1
- package/dist/src/cohort-topic/antidos/replay-guard.js +33 -0
- package/dist/src/cohort-topic/antidos/replay-guard.js.map +1 -1
- package/dist/src/cohort-topic/antidos/topic-budget.d.ts +7 -0
- package/dist/src/cohort-topic/antidos/topic-budget.d.ts.map +1 -1
- package/dist/src/cohort-topic/antidos/topic-budget.js +8 -2
- package/dist/src/cohort-topic/antidos/topic-budget.js.map +1 -1
- package/dist/src/cohort-topic/coldstart.d.ts +34 -14
- package/dist/src/cohort-topic/coldstart.d.ts.map +1 -1
- package/dist/src/cohort-topic/coldstart.js +25 -11
- package/dist/src/cohort-topic/coldstart.js.map +1 -1
- package/dist/src/cohort-topic/gossip/bus.d.ts +12 -1
- package/dist/src/cohort-topic/gossip/bus.d.ts.map +1 -1
- package/dist/src/cohort-topic/gossip/bus.js +27 -1
- package/dist/src/cohort-topic/gossip/bus.js.map +1 -1
- package/dist/src/cohort-topic/gossip/view.d.ts +8 -0
- package/dist/src/cohort-topic/gossip/view.d.ts.map +1 -1
- package/dist/src/cohort-topic/gossip/view.js +17 -1
- package/dist/src/cohort-topic/gossip/view.js.map +1 -1
- package/dist/src/cohort-topic/member-engine.d.ts +10 -3
- package/dist/src/cohort-topic/member-engine.d.ts.map +1 -1
- package/dist/src/cohort-topic/member-engine.js +29 -14
- package/dist/src/cohort-topic/member-engine.js.map +1 -1
- package/dist/src/cohort-topic/membership/publisher.d.ts +14 -7
- package/dist/src/cohort-topic/membership/publisher.d.ts.map +1 -1
- package/dist/src/cohort-topic/membership/publisher.js +15 -27
- package/dist/src/cohort-topic/membership/publisher.js.map +1 -1
- package/dist/src/cohort-topic/membership/verifier.d.ts +35 -0
- package/dist/src/cohort-topic/membership/verifier.d.ts.map +1 -1
- package/dist/src/cohort-topic/membership/verifier.js +88 -3
- package/dist/src/cohort-topic/membership/verifier.js.map +1 -1
- package/dist/src/cohort-topic/promotion.d.ts +7 -0
- package/dist/src/cohort-topic/promotion.d.ts.map +1 -1
- package/dist/src/cohort-topic/promotion.js +16 -2
- package/dist/src/cohort-topic/promotion.js.map +1 -1
- package/dist/src/cohort-topic/registration/renewal.d.ts +18 -0
- package/dist/src/cohort-topic/registration/renewal.d.ts.map +1 -1
- package/dist/src/cohort-topic/registration/renewal.js +54 -0
- package/dist/src/cohort-topic/registration/renewal.js.map +1 -1
- package/dist/src/cohort-topic/registration/types.d.ts +12 -0
- package/dist/src/cohort-topic/registration/types.d.ts.map +1 -1
- package/dist/src/cohort-topic/registration/types.js +14 -0
- package/dist/src/cohort-topic/registration/types.js.map +1 -1
- package/dist/src/cohort-topic/service.d.ts +4 -3
- package/dist/src/cohort-topic/service.d.ts.map +1 -1
- package/dist/src/cohort-topic/service.js +38 -12
- package/dist/src/cohort-topic/service.js.map +1 -1
- package/dist/src/cohort-topic/sig/payloads.d.ts +23 -7
- package/dist/src/cohort-topic/sig/payloads.d.ts.map +1 -1
- package/dist/src/cohort-topic/sig/payloads.js +22 -6
- package/dist/src/cohort-topic/sig/payloads.js.map +1 -1
- package/dist/src/cohort-topic/traffic.d.ts +6 -0
- package/dist/src/cohort-topic/traffic.d.ts.map +1 -1
- package/dist/src/cohort-topic/traffic.js +16 -1
- package/dist/src/cohort-topic/traffic.js.map +1 -1
- package/dist/src/cohort-topic/walk.d.ts +22 -7
- package/dist/src/cohort-topic/walk.d.ts.map +1 -1
- package/dist/src/cohort-topic/walk.js +78 -18
- package/dist/src/cohort-topic/walk.js.map +1 -1
- package/dist/src/cohort-topic/wire/codec.d.ts +3 -1
- package/dist/src/cohort-topic/wire/codec.d.ts.map +1 -1
- package/dist/src/cohort-topic/wire/codec.js +7 -1
- package/dist/src/cohort-topic/wire/codec.js.map +1 -1
- package/dist/src/cohort-topic/wire/index.d.ts +1 -1
- package/dist/src/cohort-topic/wire/index.d.ts.map +1 -1
- package/dist/src/cohort-topic/wire/index.js +1 -1
- package/dist/src/cohort-topic/wire/index.js.map +1 -1
- package/dist/src/cohort-topic/wire/payloads.d.ts +5 -4
- package/dist/src/cohort-topic/wire/payloads.d.ts.map +1 -1
- package/dist/src/cohort-topic/wire/payloads.js +14 -5
- package/dist/src/cohort-topic/wire/payloads.js.map +1 -1
- package/dist/src/cohort-topic/wire/primitives.d.ts +65 -0
- package/dist/src/cohort-topic/wire/primitives.d.ts.map +1 -0
- package/dist/src/cohort-topic/wire/primitives.js +173 -0
- package/dist/src/cohort-topic/wire/primitives.js.map +1 -0
- package/dist/src/cohort-topic/wire/types.d.ts +132 -5
- package/dist/src/cohort-topic/wire/types.d.ts.map +1 -1
- package/dist/src/cohort-topic/wire/validate.d.ts +15 -5
- package/dist/src/cohort-topic/wire/validate.d.ts.map +1 -1
- package/dist/src/cohort-topic/wire/validate.js +146 -123
- package/dist/src/cohort-topic/wire/validate.js.map +1 -1
- package/dist/src/collection/collection.d.ts +23 -12
- package/dist/src/collection/collection.d.ts.map +1 -1
- package/dist/src/collection/collection.js +111 -35
- package/dist/src/collection/collection.js.map +1 -1
- package/dist/src/collection/struct.d.ts +37 -2
- package/dist/src/collection/struct.d.ts.map +1 -1
- package/dist/src/collection/struct.js +16 -1
- package/dist/src/collection/struct.js.map +1 -1
- package/dist/src/collections/tree/tree.d.ts +18 -1
- package/dist/src/collections/tree/tree.d.ts.map +1 -1
- package/dist/src/collections/tree/tree.js +36 -6
- package/dist/src/collections/tree/tree.js.map +1 -1
- 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/log/log.d.ts +26 -3
- package/dist/src/log/log.d.ts.map +1 -1
- package/dist/src/log/log.js +34 -7
- package/dist/src/log/log.js.map +1 -1
- package/dist/src/log/struct.d.ts +5 -4
- package/dist/src/log/struct.d.ts.map +1 -1
- package/dist/src/log/struct.js.map +1 -1
- package/dist/src/matchmaking/wire.d.ts +2 -1
- package/dist/src/matchmaking/wire.d.ts.map +1 -1
- package/dist/src/matchmaking/wire.js +13 -92
- package/dist/src/matchmaking/wire.js.map +1 -1
- package/dist/src/network/i-key-network.d.ts +9 -0
- package/dist/src/network/i-key-network.d.ts.map +1 -1
- package/dist/src/network/i-repo.d.ts +8 -0
- package/dist/src/network/i-repo.d.ts.map +1 -1
- package/dist/src/network/struct.d.ts +10 -0
- package/dist/src/network/struct.d.ts.map +1 -1
- package/dist/src/reactivity/push-state.d.ts.map +1 -1
- package/dist/src/reactivity/push-state.js +4 -33
- package/dist/src/reactivity/push-state.js.map +1 -1
- package/dist/src/reactivity/wire-validate.d.ts +7 -22
- package/dist/src/reactivity/wire-validate.d.ts.map +1 -1
- package/dist/src/reactivity/wire-validate.js +7 -73
- package/dist/src/reactivity/wire-validate.js.map +1 -1
- package/dist/src/reactivity/wire.js +3 -3
- package/dist/src/reactivity/wire.js.map +1 -1
- package/dist/src/testing/async-wait.d.ts +23 -0
- package/dist/src/testing/async-wait.d.ts.map +1 -0
- package/dist/src/testing/async-wait.js +42 -0
- package/dist/src/testing/async-wait.js.map +1 -0
- package/dist/src/testing/index.d.ts +3 -0
- package/dist/src/testing/index.d.ts.map +1 -0
- package/dist/src/testing/index.js +3 -0
- package/dist/src/testing/index.js.map +1 -0
- package/dist/src/testing/test-transactor.d.ts +44 -0
- package/dist/src/testing/test-transactor.d.ts.map +1 -0
- package/dist/src/testing/test-transactor.js +423 -0
- package/dist/src/testing/test-transactor.js.map +1 -0
- package/dist/src/transaction/actions-engine.d.ts +6 -3
- package/dist/src/transaction/actions-engine.d.ts.map +1 -1
- package/dist/src/transaction/actions-engine.js +8 -7
- package/dist/src/transaction/actions-engine.js.map +1 -1
- package/dist/src/transaction/coordinator.d.ts +43 -22
- package/dist/src/transaction/coordinator.d.ts.map +1 -1
- package/dist/src/transaction/coordinator.js +443 -178
- package/dist/src/transaction/coordinator.js.map +1 -1
- package/dist/src/transaction/errors.d.ts +82 -0
- package/dist/src/transaction/errors.d.ts.map +1 -0
- package/dist/src/transaction/errors.js +93 -0
- package/dist/src/transaction/errors.js.map +1 -0
- package/dist/src/transaction/index.d.ts +6 -3
- package/dist/src/transaction/index.d.ts.map +1 -1
- package/dist/src/transaction/index.js +4 -2
- package/dist/src/transaction/index.js.map +1 -1
- package/dist/src/transaction/operations-hash.d.ts +119 -0
- package/dist/src/transaction/operations-hash.d.ts.map +1 -0
- package/dist/src/transaction/operations-hash.js +180 -0
- package/dist/src/transaction/operations-hash.js.map +1 -0
- package/dist/src/transaction/read-dependency-collector.d.ts +43 -0
- package/dist/src/transaction/read-dependency-collector.d.ts.map +1 -0
- package/dist/src/transaction/read-dependency-collector.js +69 -0
- package/dist/src/transaction/read-dependency-collector.js.map +1 -0
- package/dist/src/transaction/session.d.ts +12 -3
- package/dist/src/transaction/session.d.ts.map +1 -1
- package/dist/src/transaction/session.js +35 -9
- package/dist/src/transaction/session.js.map +1 -1
- package/dist/src/transaction/transaction.d.ts +162 -1
- package/dist/src/transaction/transaction.d.ts.map +1 -1
- package/dist/src/transaction/transaction.js +85 -3
- package/dist/src/transaction/transaction.js.map +1 -1
- package/dist/src/transaction/validator.d.ts +3 -11
- package/dist/src/transaction/validator.d.ts.map +1 -1
- package/dist/src/transaction/validator.js +69 -28
- package/dist/src/transaction/validator.js.map +1 -1
- package/dist/src/transactor/network-transactor.d.ts +35 -0
- package/dist/src/transactor/network-transactor.d.ts.map +1 -1
- package/dist/src/transactor/network-transactor.js +146 -40
- package/dist/src/transactor/network-transactor.js.map +1 -1
- package/dist/src/transactor/transactor-source.d.ts +19 -5
- package/dist/src/transactor/transactor-source.d.ts.map +1 -1
- package/dist/src/transactor/transactor-source.js +43 -11
- package/dist/src/transactor/transactor-source.js.map +1 -1
- package/dist/src/transform/atomic-proxy.d.ts +35 -5
- package/dist/src/transform/atomic-proxy.d.ts.map +1 -1
- package/dist/src/transform/atomic-proxy.js +39 -7
- package/dist/src/transform/atomic-proxy.js.map +1 -1
- package/dist/src/transform/cache-source.d.ts +36 -5
- package/dist/src/transform/cache-source.d.ts.map +1 -1
- package/dist/src/transform/cache-source.js +84 -8
- package/dist/src/transform/cache-source.js.map +1 -1
- package/dist/src/transform/helpers.d.ts.map +1 -1
- package/dist/src/transform/helpers.js +8 -2
- package/dist/src/transform/helpers.js.map +1 -1
- package/dist/src/transform/tracker.d.ts +17 -2
- package/dist/src/transform/tracker.d.ts.map +1 -1
- package/dist/src/transform/tracker.js +66 -11
- package/dist/src/transform/tracker.js.map +1 -1
- package/dist/src/utility/backoff.d.ts +48 -0
- package/dist/src/utility/backoff.d.ts.map +1 -0
- package/dist/src/utility/backoff.js +60 -0
- package/dist/src/utility/backoff.js.map +1 -0
- package/dist/src/utility/pending.d.ts +1 -0
- package/dist/src/utility/pending.d.ts.map +1 -1
- package/dist/src/utility/pending.js +3 -1
- package/dist/src/utility/pending.js.map +1 -1
- package/package.json +4 -4
- package/src/blocks/block-store.ts +19 -1
- package/src/blocks/helpers.ts +3 -3
- package/src/btree/btree.ts +108 -63
- package/src/chain/chain.ts +11 -1
- package/src/cluster/index.ts +1 -0
- package/src/cluster/membership.ts +85 -0
- package/src/cluster/structs.ts +51 -1
- package/src/cohort-topic/addressing.ts +12 -4
- package/src/cohort-topic/antidos/bootstrap-evidence.ts +21 -9
- package/src/cohort-topic/antidos/replay-guard.ts +37 -0
- package/src/cohort-topic/antidos/topic-budget.ts +17 -2
- package/src/cohort-topic/coldstart.ts +48 -15
- package/src/cohort-topic/gossip/bus.ts +39 -2
- package/src/cohort-topic/gossip/view.ts +26 -1
- package/src/cohort-topic/member-engine.ts +36 -15
- package/src/cohort-topic/membership/publisher.ts +25 -33
- package/src/cohort-topic/membership/verifier.ts +119 -3
- package/src/cohort-topic/promotion.ts +23 -2
- package/src/cohort-topic/registration/renewal.ts +73 -1
- package/src/cohort-topic/registration/types.ts +15 -0
- package/src/cohort-topic/service.ts +41 -15
- package/src/cohort-topic/sig/payloads.ts +29 -9
- package/src/cohort-topic/traffic.ts +23 -1
- package/src/cohort-topic/walk.ts +95 -24
- package/src/cohort-topic/wire/codec.ts +12 -0
- package/src/cohort-topic/wire/index.ts +2 -0
- package/src/cohort-topic/wire/payloads.ts +14 -5
- package/src/cohort-topic/wire/primitives.ts +188 -0
- package/src/cohort-topic/wire/types.ts +136 -4
- package/src/cohort-topic/wire/validate.ts +168 -134
- package/src/collection/collection.ts +123 -40
- package/src/collection/struct.ts +44 -2
- package/src/collections/tree/tree.ts +42 -5
- package/src/index.ts +1 -0
- package/src/log/log.ts +37 -9
- package/src/log/struct.ts +5 -4
- package/src/matchmaking/wire.ts +25 -102
- package/src/network/i-key-network.ts +10 -0
- package/src/network/i-repo.ts +8 -0
- package/src/network/struct.ts +10 -0
- package/src/reactivity/push-state.ts +4 -37
- package/src/reactivity/wire-validate.ts +7 -81
- package/src/reactivity/wire.ts +3 -3
- package/src/testing/async-wait.ts +65 -0
- package/src/testing/index.ts +2 -0
- package/src/testing/test-transactor.ts +468 -0
- package/src/transaction/actions-engine.ts +8 -6
- package/src/transaction/coordinator.ts +498 -229
- package/src/transaction/errors.ts +91 -0
- package/src/transaction/index.ts +23 -3
- package/src/transaction/operations-hash.ts +196 -0
- package/src/transaction/read-dependency-collector.ts +78 -0
- package/src/transaction/session.ts +37 -9
- package/src/transaction/transaction.ts +211 -4
- package/src/transaction/validator.ts +73 -48
- package/src/transactor/network-transactor.ts +164 -49
- package/src/transactor/transactor-source.ts +47 -12
- package/src/transform/atomic-proxy.ts +92 -49
- package/src/transform/cache-source.ts +87 -9
- package/src/transform/helpers.ts +8 -2
- package/src/transform/tracker.ts +69 -11
- package/src/utility/backoff.ts +95 -0
- package/src/utility/pending.ts +3 -1
- package/src/transaction/context.ts +0 -103
|
@@ -8,8 +8,28 @@
|
|
|
8
8
|
* narrow cleanly or throw.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import { DEFAULT_D_MAX_CAP } from "../dmax.js";
|
|
12
|
+
import {
|
|
13
|
+
assignDefined,
|
|
14
|
+
asObject,
|
|
15
|
+
b64urlField,
|
|
16
|
+
b64urlFixedLen,
|
|
17
|
+
failWire as fail,
|
|
18
|
+
optBool,
|
|
19
|
+
optFiniteNumber,
|
|
20
|
+
optString,
|
|
21
|
+
optStringArray,
|
|
22
|
+
reqBool,
|
|
23
|
+
reqEnum,
|
|
24
|
+
reqFiniteNumber,
|
|
25
|
+
reqString,
|
|
26
|
+
reqStringArray,
|
|
27
|
+
requireV1,
|
|
28
|
+
} from "./primitives.js";
|
|
12
29
|
import type {
|
|
30
|
+
ChildLinkRefV1,
|
|
31
|
+
ChildLinkReplyV1,
|
|
32
|
+
ChildLinkV1,
|
|
13
33
|
CohortGossipV1,
|
|
14
34
|
CohortTopicSummary,
|
|
15
35
|
DemotionNoticeV1,
|
|
@@ -28,109 +48,11 @@ import type {
|
|
|
28
48
|
TopicTrafficV1,
|
|
29
49
|
} from "./types.js";
|
|
30
50
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function fail(message: string): never {
|
|
40
|
-
throw new CohortWireError(message);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** Set `obj[key]` only when `value` is defined — keeps absent optionals off the decoded object. */
|
|
44
|
-
function assignDefined<T extends object, K extends keyof T>(obj: T, key: K, value: T[K] | undefined): void {
|
|
45
|
-
if (value !== undefined) {
|
|
46
|
-
obj[key] = value;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function asObject(value: unknown, what: string): Record<string, unknown> {
|
|
51
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
52
|
-
fail(`${what}: expected an object`);
|
|
53
|
-
}
|
|
54
|
-
return value as Record<string, unknown>;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function requireV1(obj: Record<string, unknown>, what: string): void {
|
|
58
|
-
if (obj["v"] !== 1) {
|
|
59
|
-
fail(`${what}: expected v === 1, got ${JSON.stringify(obj["v"])}`);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function reqString(obj: Record<string, unknown>, key: string, what: string): string {
|
|
64
|
-
const value = obj[key];
|
|
65
|
-
if (typeof value !== "string") {
|
|
66
|
-
fail(`${what}: field "${key}" must be a string`);
|
|
67
|
-
}
|
|
68
|
-
return value;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function optString(obj: Record<string, unknown>, key: string, what: string): string | undefined {
|
|
72
|
-
const value = obj[key];
|
|
73
|
-
if (value === undefined) {
|
|
74
|
-
return undefined;
|
|
75
|
-
}
|
|
76
|
-
if (typeof value !== "string") {
|
|
77
|
-
fail(`${what}: field "${key}" must be a string when present`);
|
|
78
|
-
}
|
|
79
|
-
return value;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function reqFiniteNumber(obj: Record<string, unknown>, key: string, what: string): number {
|
|
83
|
-
const value = obj[key];
|
|
84
|
-
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
85
|
-
fail(`${what}: field "${key}" must be a finite number`);
|
|
86
|
-
}
|
|
87
|
-
return value;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function optFiniteNumber(obj: Record<string, unknown>, key: string, what: string): number | undefined {
|
|
91
|
-
const value = obj[key];
|
|
92
|
-
if (value === undefined) {
|
|
93
|
-
return undefined;
|
|
94
|
-
}
|
|
95
|
-
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
96
|
-
fail(`${what}: field "${key}" must be a finite number when present`);
|
|
97
|
-
}
|
|
98
|
-
return value;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function reqBool(obj: Record<string, unknown>, key: string, what: string): boolean {
|
|
102
|
-
const value = obj[key];
|
|
103
|
-
if (typeof value !== "boolean") {
|
|
104
|
-
fail(`${what}: field "${key}" must be a boolean`);
|
|
105
|
-
}
|
|
106
|
-
return value;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function optBool(obj: Record<string, unknown>, key: string, what: string): boolean | undefined {
|
|
110
|
-
const value = obj[key];
|
|
111
|
-
if (value === undefined) {
|
|
112
|
-
return undefined;
|
|
113
|
-
}
|
|
114
|
-
if (typeof value !== "boolean") {
|
|
115
|
-
fail(`${what}: field "${key}" must be a boolean when present`);
|
|
116
|
-
}
|
|
117
|
-
return value;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function reqStringArray(obj: Record<string, unknown>, key: string, what: string): string[] {
|
|
121
|
-
const value = obj[key];
|
|
122
|
-
if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) {
|
|
123
|
-
fail(`${what}: field "${key}" must be an array of strings`);
|
|
124
|
-
}
|
|
125
|
-
return value as string[];
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function optStringArray(obj: Record<string, unknown>, key: string, what: string): string[] | undefined {
|
|
129
|
-
if (obj[key] === undefined) {
|
|
130
|
-
return undefined;
|
|
131
|
-
}
|
|
132
|
-
return reqStringArray(obj, key, what);
|
|
133
|
-
}
|
|
51
|
+
// The generic structural-validation primitives (`fail`/`asObject`/`req*`/`opt*`/`b64url*`/`reqEnum`/…)
|
|
52
|
+
// live in ./primitives.js and are imported above; only the cohort-topic domain validators and the
|
|
53
|
+
// tier-semantics helpers below stay local. `CohortWireError` is re-exported here so existing importers
|
|
54
|
+
// of this module (codec, wire/index, matchmaking, reactivity) are unaffected by the move.
|
|
55
|
+
export { CohortWireError } from "./primitives.js";
|
|
134
56
|
|
|
135
57
|
function tier(value: number, what: string): number {
|
|
136
58
|
if (!Number.isInteger(value) || value < 0 || value > 3) {
|
|
@@ -139,23 +61,24 @@ function tier(value: number, what: string): number {
|
|
|
139
61
|
return value;
|
|
140
62
|
}
|
|
141
63
|
|
|
142
|
-
/**
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Validate a `treeTier` (the walk-toward-root start tier `d` a register/redirect targets): an integer in
|
|
66
|
+
* `0..DEFAULT_D_MAX_CAP`. `d_max_cap` (60) is the substrate's own ceiling on useful walk depth, so a
|
|
67
|
+
* `treeTier` above it cannot correspond to a real walk position. Rejecting here keeps an out-of-range value
|
|
68
|
+
* from reaching `addressing.coord()` downstream — whose `coordD` throws a raw `RangeError` for a
|
|
69
|
+
* non-integer / negative / `> 255` tier, an unclassified crash rather than a clean malformed-frame rejection.
|
|
70
|
+
*/
|
|
71
|
+
function treeTier(value: number, what: string): number {
|
|
72
|
+
if (!Number.isInteger(value) || value < 0 || value > DEFAULT_D_MAX_CAP) {
|
|
73
|
+
fail(`${what}: treeTier must be an integer in 0..${DEFAULT_D_MAX_CAP}, got ${value}`);
|
|
148
74
|
}
|
|
149
75
|
return value;
|
|
150
76
|
}
|
|
151
77
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
return value as T;
|
|
158
|
-
}
|
|
78
|
+
/** Ring-coord / topic-id / epoch byte width (SHA-256 truncated to the ring width). */
|
|
79
|
+
const COORD_BYTES = 32;
|
|
80
|
+
/** Correlation-id byte width (a 16-byte nonce minted per walk probe / renew). */
|
|
81
|
+
const CORRELATION_BYTES = 16;
|
|
159
82
|
|
|
160
83
|
const REGISTER_RESULTS: readonly RegisterResult[] = [
|
|
161
84
|
"accepted",
|
|
@@ -171,13 +94,13 @@ export function validateRegisterV1(value: unknown): RegisterV1 {
|
|
|
171
94
|
requireV1(obj, what);
|
|
172
95
|
const out: RegisterV1 = {
|
|
173
96
|
v: 1,
|
|
174
|
-
topicId:
|
|
97
|
+
topicId: b64urlFixedLen(reqString(obj, "topicId", what), "topicId", COORD_BYTES, what),
|
|
175
98
|
tier: tier(reqFiniteNumber(obj, "tier", what), what),
|
|
176
|
-
treeTier: reqFiniteNumber(obj, "treeTier", what),
|
|
99
|
+
treeTier: treeTier(reqFiniteNumber(obj, "treeTier", what), what),
|
|
177
100
|
participantCoord: b64urlField(reqString(obj, "participantCoord", what), "participantCoord", what),
|
|
178
101
|
ttl: reqFiniteNumber(obj, "ttl", what),
|
|
179
102
|
timestamp: reqFiniteNumber(obj, "timestamp", what),
|
|
180
|
-
correlationId:
|
|
103
|
+
correlationId: b64urlFixedLen(reqString(obj, "correlationId", what), "correlationId", CORRELATION_BYTES, what),
|
|
181
104
|
signature: b64urlField(reqString(obj, "signature", what), "signature", what),
|
|
182
105
|
};
|
|
183
106
|
const bootstrap = optBool(obj, "bootstrap", what);
|
|
@@ -188,6 +111,21 @@ export function validateRegisterV1(value: unknown): RegisterV1 {
|
|
|
188
111
|
if (probe !== undefined) {
|
|
189
112
|
out.probe = probe;
|
|
190
113
|
}
|
|
114
|
+
const followOn = optBool(obj, "followOn", what);
|
|
115
|
+
if (followOn !== undefined) {
|
|
116
|
+
out.followOn = followOn;
|
|
117
|
+
}
|
|
118
|
+
// `bootstrap`, `followOn`, and `probe` are pairwise mutually exclusive — the walk sets at most one
|
|
119
|
+
// (bootstrap only at the tier-0 root re-issue, followOn only at a `treeTier >= 1` redirect target,
|
|
120
|
+
// probe never instantiates). A frame that sets more than one is malformed / adversarial.
|
|
121
|
+
if ([bootstrap, followOn, probe].filter((flag) => flag === true).length > 1) {
|
|
122
|
+
fail(`${what}: at most one of bootstrap, followOn, probe may be set`);
|
|
123
|
+
}
|
|
124
|
+
// A follow-on is by definition a deeper-than-root growth point, so `treeTier >= 1`. A `followOn: true`
|
|
125
|
+
// at the root (treeTier 0) would be a bootstrap, not a follow-on — reject it as malformed.
|
|
126
|
+
if (followOn === true && out.treeTier < 1) {
|
|
127
|
+
fail(`${what}: followOn requires treeTier >= 1, got ${out.treeTier}`);
|
|
128
|
+
}
|
|
191
129
|
const appPayload = optString(obj, "appPayload", what);
|
|
192
130
|
if (appPayload !== undefined) {
|
|
193
131
|
out.appPayload = b64urlField(appPayload, "appPayload", what);
|
|
@@ -226,12 +164,17 @@ export function validateRegisterReplyV1(value: unknown): RegisterReplyV1 {
|
|
|
226
164
|
assignDefined(out, "backups", optStringArray(obj, "backups", what));
|
|
227
165
|
const cohortEpoch = optString(obj, "cohortEpoch", what);
|
|
228
166
|
if (cohortEpoch !== undefined) {
|
|
167
|
+
// NOTE: cohortEpoch is NOT length-pinned though real epochs are a 32-byte SHA-256 — several
|
|
168
|
+
// test fixtures (db-core reactivity + db-p2p) feed 1-byte synthetic epochs. Pinning is tracked
|
|
169
|
+
// by debt-cohort-topic-pin-cohort-epoch. See b64urlField's note.
|
|
229
170
|
out.cohortEpoch = b64urlField(cohortEpoch, "cohortEpoch", what);
|
|
230
171
|
}
|
|
231
172
|
assignDefined(out, "cohortMembers", optStringArray(obj, "cohortMembers", what));
|
|
232
173
|
if (obj["topicTraffic"] !== undefined) {
|
|
233
174
|
out.topicTraffic = validateTopicTrafficV1(obj["topicTraffic"]);
|
|
234
175
|
}
|
|
176
|
+
// NOTE: `targetTier` is range-checked in the walk loop (walk.ts, case "promoted"), not here — an
|
|
177
|
+
// out-of-range redirect must surface as a `retry_later` outcome, not a decode-time throw.
|
|
235
178
|
assignDefined(out, "targetTier", optFiniteNumber(obj, "targetTier", what));
|
|
236
179
|
assignDefined(out, "candidateMembers", optStringArray(obj, "candidateMembers", what));
|
|
237
180
|
assignDefined(out, "retryAfterMs", optFiniteNumber(obj, "retryAfterMs", what));
|
|
@@ -245,9 +188,9 @@ export function validateRenewV1(value: unknown): RenewV1 {
|
|
|
245
188
|
requireV1(obj, what);
|
|
246
189
|
const out: RenewV1 = {
|
|
247
190
|
v: 1,
|
|
248
|
-
topicId:
|
|
191
|
+
topicId: b64urlFixedLen(reqString(obj, "topicId", what), "topicId", COORD_BYTES, what),
|
|
249
192
|
participantId: reqString(obj, "participantId", what),
|
|
250
|
-
correlationId:
|
|
193
|
+
correlationId: b64urlFixedLen(reqString(obj, "correlationId", what), "correlationId", CORRELATION_BYTES, what),
|
|
251
194
|
timestamp: reqFiniteNumber(obj, "timestamp", what),
|
|
252
195
|
signature: b64urlField(reqString(obj, "signature", what), "signature", what),
|
|
253
196
|
};
|
|
@@ -268,6 +211,8 @@ export function validateRenewReplyV1(value: unknown): RenewReplyV1 {
|
|
|
268
211
|
assignDefined(out, "newBackups", optStringArray(obj, "newBackups", what));
|
|
269
212
|
const cohortEpoch = optString(obj, "cohortEpoch", what);
|
|
270
213
|
if (cohortEpoch !== undefined) {
|
|
214
|
+
// NOTE: cohortEpoch is NOT length-pinned — see validateRegisterReplyV1's note and
|
|
215
|
+
// debt-cohort-topic-pin-cohort-epoch.
|
|
271
216
|
out.cohortEpoch = b64urlField(cohortEpoch, "cohortEpoch", what);
|
|
272
217
|
}
|
|
273
218
|
return out;
|
|
@@ -277,11 +222,17 @@ export function validatePromotionNoticeV1(value: unknown): PromotionNoticeV1 {
|
|
|
277
222
|
const what = "PromotionNoticeV1";
|
|
278
223
|
const obj = asObject(value, what);
|
|
279
224
|
requireV1(obj, what);
|
|
225
|
+
const fromTier = treeTier(reqFiniteNumber(obj, "fromTier", what), what);
|
|
226
|
+
const toTier = treeTier(reqFiniteNumber(obj, "toTier", what), what);
|
|
227
|
+
if (toTier !== fromTier + 1) {
|
|
228
|
+
fail(`${what}: toTier must equal fromTier + 1, got fromTier=${fromTier} toTier=${toTier}`);
|
|
229
|
+
}
|
|
280
230
|
return {
|
|
281
231
|
v: 1,
|
|
282
|
-
topicId:
|
|
283
|
-
fromTier
|
|
284
|
-
toTier
|
|
232
|
+
topicId: b64urlFixedLen(reqString(obj, "topicId", what), "topicId", COORD_BYTES, what),
|
|
233
|
+
fromTier,
|
|
234
|
+
toTier,
|
|
235
|
+
cohortCoord: b64urlFixedLen(reqString(obj, "cohortCoord", what), "cohortCoord", COORD_BYTES, what),
|
|
285
236
|
effectiveAt: reqFiniteNumber(obj, "effectiveAt", what),
|
|
286
237
|
thresholdSig: b64urlField(reqString(obj, "thresholdSig", what), "thresholdSig", what),
|
|
287
238
|
signers: reqStringArray(obj, "signers", what),
|
|
@@ -295,9 +246,10 @@ export function validateDemotionNoticeV1(value: unknown): DemotionNoticeV1 {
|
|
|
295
246
|
requireV1(obj, what);
|
|
296
247
|
return {
|
|
297
248
|
v: 1,
|
|
298
|
-
topicId:
|
|
299
|
-
tier:
|
|
300
|
-
parentCohortCoord:
|
|
249
|
+
topicId: b64urlFixedLen(reqString(obj, "topicId", what), "topicId", COORD_BYTES, what),
|
|
250
|
+
tier: treeTier(reqFiniteNumber(obj, "tier", what), what),
|
|
251
|
+
parentCohortCoord: b64urlFixedLen(reqString(obj, "parentCohortCoord", what), "parentCohortCoord", COORD_BYTES, what),
|
|
252
|
+
cohortCoord: b64urlFixedLen(reqString(obj, "cohortCoord", what), "cohortCoord", COORD_BYTES, what),
|
|
301
253
|
effectiveAt: reqFiniteNumber(obj, "effectiveAt", what),
|
|
302
254
|
thresholdSig: b64urlField(reqString(obj, "thresholdSig", what), "thresholdSig", what),
|
|
303
255
|
signers: reqStringArray(obj, "signers", what),
|
|
@@ -305,6 +257,56 @@ export function validateDemotionNoticeV1(value: unknown): DemotionNoticeV1 {
|
|
|
305
257
|
};
|
|
306
258
|
}
|
|
307
259
|
|
|
260
|
+
/**
|
|
261
|
+
* Validate a {@link ChildLinkV1}. Enforces `childTier >= 1` (the root never links), `tier` in 0..3, and
|
|
262
|
+
* well-formed base64url on every byte field. The hash-derived fields (`topicId` / `childCohortCoord` /
|
|
263
|
+
* `cohortEpoch`) are additionally length-checked to exactly 32 bytes (each is a SHA-256 truncation); the
|
|
264
|
+
* `childParticipantCoord` follows the lenient `RegisterV1` convention (base64url only — a participant
|
|
265
|
+
* coord is not always 32 raw bytes, e.g. a multihash-encoded peer id in tests). When `minSigs`
|
|
266
|
+
* is supplied AND the frame carries a threshold signature (`thresholdSig` non-empty), `signers.length` must
|
|
267
|
+
* be `>= minSigs`; a key-less-interim frame carries neither, so that cross-field bound is skipped. `minSigs`
|
|
268
|
+
* is optional so a bare structural decode (no quorum context) still narrows the frame.
|
|
269
|
+
*/
|
|
270
|
+
export function validateChildLinkV1(value: unknown, minSigs?: number): ChildLinkV1 {
|
|
271
|
+
const what = "ChildLinkV1";
|
|
272
|
+
const obj = asObject(value, what);
|
|
273
|
+
requireV1(obj, what);
|
|
274
|
+
const childTier = reqFiniteNumber(obj, "childTier", what);
|
|
275
|
+
if (!Number.isInteger(childTier) || childTier < 1) {
|
|
276
|
+
fail(`${what}: childTier must be an integer >= 1, got ${childTier}`);
|
|
277
|
+
}
|
|
278
|
+
const thresholdSig = b64urlField(reqString(obj, "thresholdSig", what), "thresholdSig", what);
|
|
279
|
+
const signers = reqStringArray(obj, "signers", what).map((s) => b64urlField(s, "signers", what));
|
|
280
|
+
if (minSigs !== undefined && thresholdSig.length > 0 && signers.length < minSigs) {
|
|
281
|
+
fail(`${what}: a signed child-link needs signers.length >= ${minSigs}, got ${signers.length}`);
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
v: 1,
|
|
285
|
+
topicId: b64urlFixedLen(reqString(obj, "topicId", what), "topicId", COORD_BYTES, what),
|
|
286
|
+
childCohortCoord: b64urlFixedLen(reqString(obj, "childCohortCoord", what), "childCohortCoord", COORD_BYTES, what),
|
|
287
|
+
childParticipantCoord: b64urlField(reqString(obj, "childParticipantCoord", what), "childParticipantCoord", what),
|
|
288
|
+
childTier,
|
|
289
|
+
tier: tier(reqFiniteNumber(obj, "tier", what), what),
|
|
290
|
+
effectiveAt: reqFiniteNumber(obj, "effectiveAt", what),
|
|
291
|
+
thresholdSig,
|
|
292
|
+
signers,
|
|
293
|
+
cohortEpoch: b64urlField(reqString(obj, "cohortEpoch", what), "cohortEpoch", what),
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/** Validate a {@link ChildLinkReplyV1}: `result` in `linked | rejected`, optional human-readable `reason`. */
|
|
298
|
+
export function validateChildLinkReplyV1(value: unknown): ChildLinkReplyV1 {
|
|
299
|
+
const what = "ChildLinkReplyV1";
|
|
300
|
+
const obj = asObject(value, what);
|
|
301
|
+
requireV1(obj, what);
|
|
302
|
+
const out: ChildLinkReplyV1 = {
|
|
303
|
+
v: 1,
|
|
304
|
+
result: reqEnum(obj, "result", ["linked", "rejected"] as const, what),
|
|
305
|
+
};
|
|
306
|
+
assignDefined(out, "reason", optString(obj, "reason", what));
|
|
307
|
+
return out;
|
|
308
|
+
}
|
|
309
|
+
|
|
308
310
|
function validateCohortTopicSummary(value: unknown): CohortTopicSummary {
|
|
309
311
|
const what = "CohortTopicSummary";
|
|
310
312
|
const obj = asObject(value, what);
|
|
@@ -323,7 +325,7 @@ function validateGossipRecordV1(value: unknown): GossipRecordV1 {
|
|
|
323
325
|
const what = "GossipRecordV1";
|
|
324
326
|
const obj = asObject(value, what);
|
|
325
327
|
const out: GossipRecordV1 = {
|
|
326
|
-
topicId:
|
|
328
|
+
topicId: b64urlFixedLen(reqString(obj, "topicId", what), "topicId", COORD_BYTES, what),
|
|
327
329
|
participantId: b64urlField(reqString(obj, "participantId", what), "participantId", what),
|
|
328
330
|
tier: tier(reqFiniteNumber(obj, "tier", what), what),
|
|
329
331
|
primary: b64urlField(reqString(obj, "primary", what), "primary", what),
|
|
@@ -343,8 +345,19 @@ function validateGossipRecordRefV1(value: unknown): GossipRecordRefV1 {
|
|
|
343
345
|
const what = "GossipRecordRefV1";
|
|
344
346
|
const obj = asObject(value, what);
|
|
345
347
|
return {
|
|
346
|
-
topicId:
|
|
348
|
+
topicId: b64urlFixedLen(reqString(obj, "topicId", what), "topicId", COORD_BYTES, what),
|
|
347
349
|
participantId: b64urlField(reqString(obj, "participantId", what), "participantId", what),
|
|
350
|
+
lastPing: reqFiniteNumber(obj, "lastPing", what),
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function validateChildLinkRefV1(value: unknown): ChildLinkRefV1 {
|
|
355
|
+
const what = "ChildLinkRefV1";
|
|
356
|
+
const obj = asObject(value, what);
|
|
357
|
+
return {
|
|
358
|
+
topicId: b64urlFixedLen(reqString(obj, "topicId", what), "topicId", COORD_BYTES, what),
|
|
359
|
+
childCohortCoord: b64urlField(reqString(obj, "childCohortCoord", what), "childCohortCoord", what),
|
|
360
|
+
effectiveAt: reqFiniteNumber(obj, "effectiveAt", what),
|
|
348
361
|
};
|
|
349
362
|
}
|
|
350
363
|
|
|
@@ -372,11 +385,16 @@ export function validateCohortGossipV1(value: unknown): CohortGossipV1 {
|
|
|
372
385
|
if (!Array.isArray(summaries)) {
|
|
373
386
|
fail(`${what}: field "topicSummaries" must be an array`);
|
|
374
387
|
}
|
|
388
|
+
const treeTier = reqFiniteNumber(obj, "treeTier", what);
|
|
389
|
+
if (!Number.isInteger(treeTier) || treeTier < 0) {
|
|
390
|
+
fail(`${what}: field "treeTier" must be a non-negative integer, got ${treeTier}`);
|
|
391
|
+
}
|
|
375
392
|
const out: CohortGossipV1 = {
|
|
376
393
|
v: 1,
|
|
377
394
|
fromMember: reqString(obj, "fromMember", what),
|
|
378
|
-
coord:
|
|
395
|
+
coord: b64urlFixedLen(reqString(obj, "coord", what), "coord", COORD_BYTES, what),
|
|
379
396
|
cohortEpoch: b64urlField(reqString(obj, "cohortEpoch", what), "cohortEpoch", what),
|
|
397
|
+
treeTier,
|
|
380
398
|
willingnessBits,
|
|
381
399
|
loadBuckets: loadBuckets as number[],
|
|
382
400
|
windowSeconds: reqFiniteNumber(obj, "windowSeconds", what),
|
|
@@ -398,10 +416,24 @@ export function validateCohortGossipV1(value: unknown): CohortGossipV1 {
|
|
|
398
416
|
}
|
|
399
417
|
out.evicted = evicted.map(validateGossipRecordRefV1);
|
|
400
418
|
}
|
|
419
|
+
const childLinks = obj["childLinks"];
|
|
420
|
+
if (childLinks !== undefined) {
|
|
421
|
+
if (!Array.isArray(childLinks)) {
|
|
422
|
+
fail(`${what}: field "childLinks" must be an array when present`);
|
|
423
|
+
}
|
|
424
|
+
out.childLinks = childLinks.map(validateChildLinkRefV1);
|
|
425
|
+
}
|
|
426
|
+
const childUnlinks = obj["childUnlinks"];
|
|
427
|
+
if (childUnlinks !== undefined) {
|
|
428
|
+
if (!Array.isArray(childUnlinks)) {
|
|
429
|
+
fail(`${what}: field "childUnlinks" must be an array when present`);
|
|
430
|
+
}
|
|
431
|
+
out.childUnlinks = childUnlinks.map(validateChildLinkRefV1);
|
|
432
|
+
}
|
|
401
433
|
return out;
|
|
402
434
|
}
|
|
403
435
|
|
|
404
|
-
const SIGN_KINDS: readonly SignKind[] = ["membership", "promotion", "demotion", "rotation"];
|
|
436
|
+
const SIGN_KINDS: readonly SignKind[] = ["membership", "promotion", "demotion", "rotation", "childlink"];
|
|
405
437
|
|
|
406
438
|
export function validateSignRequestV1(value: unknown): SignRequestV1 {
|
|
407
439
|
const what = "SignRequestV1";
|
|
@@ -410,7 +442,7 @@ export function validateSignRequestV1(value: unknown): SignRequestV1 {
|
|
|
410
442
|
return {
|
|
411
443
|
v: 1,
|
|
412
444
|
kind: reqEnum(obj, "kind", SIGN_KINDS, what),
|
|
413
|
-
coord:
|
|
445
|
+
coord: b64urlFixedLen(reqString(obj, "coord", what), "coord", COORD_BYTES, what),
|
|
414
446
|
cohortEpoch: b64urlField(reqString(obj, "cohortEpoch", what), "cohortEpoch", what),
|
|
415
447
|
payload: b64urlField(reqString(obj, "payload", what), "payload", what),
|
|
416
448
|
};
|
|
@@ -440,7 +472,7 @@ export function validateMembershipCertV1(value: unknown): MembershipCertV1 {
|
|
|
440
472
|
requireV1(obj, what);
|
|
441
473
|
const out: MembershipCertV1 = {
|
|
442
474
|
v: 1,
|
|
443
|
-
cohortCoord:
|
|
475
|
+
cohortCoord: b64urlFixedLen(reqString(obj, "cohortCoord", what), "cohortCoord", COORD_BYTES, what),
|
|
444
476
|
cohortEpoch: b64urlField(reqString(obj, "cohortEpoch", what), "cohortEpoch", what),
|
|
445
477
|
members: reqStringArray(obj, "members", what),
|
|
446
478
|
stabilizedAt: reqFiniteNumber(obj, "stabilizedAt", what),
|
|
@@ -472,6 +504,8 @@ function validateRotationAttestation(obj: Record<string, unknown>, out: Membersh
|
|
|
472
504
|
if (presentCount !== 3) {
|
|
473
505
|
fail(`${what}: rotation attestation requires all of prevEpoch, rotationSig, rotationSigners — or none`);
|
|
474
506
|
}
|
|
507
|
+
// prevEpoch is a prior cohortEpoch, so it inherits cohortEpoch's leniency (see the b64urlField note
|
|
508
|
+
// and debt-cohort-topic-pin-cohort-epoch).
|
|
475
509
|
out.prevEpoch = b64urlField(prevEpoch!, "prevEpoch", what);
|
|
476
510
|
out.rotationSig = b64urlField(rotationSig!, "rotationSig", what);
|
|
477
511
|
out.rotationSigners = rotationSigners!;
|