@optimystic/db-p2p 0.13.5 → 0.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/dist/src/cluster/block-transfer-service.d.ts +67 -8
- package/dist/src/cluster/block-transfer-service.d.ts.map +1 -1
- package/dist/src/cluster/block-transfer-service.js +101 -62
- package/dist/src/cluster/block-transfer-service.js.map +1 -1
- package/dist/src/cluster/client.d.ts +18 -1
- package/dist/src/cluster/client.d.ts.map +1 -1
- package/dist/src/cluster/client.js +55 -39
- package/dist/src/cluster/client.js.map +1 -1
- package/dist/src/cluster/cluster-error.d.ts +38 -0
- package/dist/src/cluster/cluster-error.d.ts.map +1 -0
- package/dist/src/cluster/cluster-error.js +51 -0
- package/dist/src/cluster/cluster-error.js.map +1 -0
- package/dist/src/cluster/cluster-repo.d.ts +135 -3
- package/dist/src/cluster/cluster-repo.d.ts.map +1 -1
- package/dist/src/cluster/cluster-repo.js +333 -58
- package/dist/src/cluster/cluster-repo.js.map +1 -1
- package/dist/src/cluster/commit-cert.d.ts +63 -0
- package/dist/src/cluster/commit-cert.d.ts.map +1 -0
- package/dist/src/cluster/commit-cert.js +108 -0
- package/dist/src/cluster/commit-cert.js.map +1 -0
- package/dist/src/cluster/service.d.ts +46 -11
- package/dist/src/cluster/service.d.ts.map +1 -1
- package/dist/src/cluster/service.js +97 -33
- package/dist/src/cluster/service.js.map +1 -1
- package/dist/src/cluster/spread-on-churn.d.ts +13 -0
- package/dist/src/cluster/spread-on-churn.d.ts.map +1 -1
- package/dist/src/cluster/spread-on-churn.js +34 -4
- package/dist/src/cluster/spread-on-churn.js.map +1 -1
- package/dist/src/cohort-topic/bootstrap-evidence-builder.d.ts +59 -0
- package/dist/src/cohort-topic/bootstrap-evidence-builder.d.ts.map +1 -0
- package/dist/src/cohort-topic/bootstrap-evidence-builder.js +79 -0
- package/dist/src/cohort-topic/bootstrap-evidence-builder.js.map +1 -0
- package/dist/src/cohort-topic/bootstrap-evidence-verifiers.d.ts +81 -0
- package/dist/src/cohort-topic/bootstrap-evidence-verifiers.d.ts.map +1 -0
- package/dist/src/cohort-topic/bootstrap-evidence-verifiers.js +93 -0
- package/dist/src/cohort-topic/bootstrap-evidence-verifiers.js.map +1 -0
- package/dist/src/cohort-topic/bootstrap-parent-reference.d.ts +108 -0
- package/dist/src/cohort-topic/bootstrap-parent-reference.d.ts.map +1 -0
- package/dist/src/cohort-topic/bootstrap-parent-reference.js +108 -0
- package/dist/src/cohort-topic/bootstrap-parent-reference.js.map +1 -0
- package/dist/src/cohort-topic/change-bridge.d.ts +65 -0
- package/dist/src/cohort-topic/change-bridge.d.ts.map +1 -0
- package/dist/src/cohort-topic/change-bridge.js +76 -0
- package/dist/src/cohort-topic/change-bridge.js.map +1 -0
- package/dist/src/cohort-topic/cohort-gossip-driver.d.ts +74 -0
- package/dist/src/cohort-topic/cohort-gossip-driver.d.ts.map +1 -0
- package/dist/src/cohort-topic/cohort-gossip-driver.js +87 -0
- package/dist/src/cohort-topic/cohort-gossip-driver.js.map +1 -0
- package/dist/src/cohort-topic/cohort-gossip-transport.d.ts +42 -0
- package/dist/src/cohort-topic/cohort-gossip-transport.d.ts.map +1 -0
- package/dist/src/cohort-topic/cohort-gossip-transport.js +57 -0
- package/dist/src/cohort-topic/cohort-gossip-transport.js.map +1 -0
- package/dist/src/cohort-topic/fret-trust-anchor.d.ts +100 -0
- package/dist/src/cohort-topic/fret-trust-anchor.d.ts.map +1 -0
- package/dist/src/cohort-topic/fret-trust-anchor.js +115 -0
- package/dist/src/cohort-topic/fret-trust-anchor.js.map +1 -0
- package/dist/src/cohort-topic/host.d.ts +573 -0
- package/dist/src/cohort-topic/host.d.ts.map +1 -0
- package/dist/src/cohort-topic/host.js +1460 -0
- package/dist/src/cohort-topic/host.js.map +1 -0
- package/dist/src/cohort-topic/index.d.ts +14 -0
- package/dist/src/cohort-topic/index.d.ts.map +1 -0
- package/dist/src/cohort-topic/index.js +14 -0
- package/dist/src/cohort-topic/index.js.map +1 -0
- package/dist/src/cohort-topic/membership-publish-sink.d.ts +14 -0
- package/dist/src/cohort-topic/membership-publish-sink.d.ts.map +1 -0
- package/dist/src/cohort-topic/membership-publish-sink.js +17 -0
- package/dist/src/cohort-topic/membership-publish-sink.js.map +1 -0
- package/dist/src/cohort-topic/membership-source.d.ts +36 -0
- package/dist/src/cohort-topic/membership-source.d.ts.map +1 -0
- package/dist/src/cohort-topic/membership-source.js +58 -0
- package/dist/src/cohort-topic/membership-source.js.map +1 -0
- package/dist/src/cohort-topic/peer-codec.d.ts +18 -0
- package/dist/src/cohort-topic/peer-codec.d.ts.map +1 -0
- package/dist/src/cohort-topic/peer-codec.js +26 -0
- package/dist/src/cohort-topic/peer-codec.js.map +1 -0
- package/dist/src/cohort-topic/peer-sig.d.ts +52 -0
- package/dist/src/cohort-topic/peer-sig.d.ts.map +1 -0
- package/dist/src/cohort-topic/peer-sig.js +83 -0
- package/dist/src/cohort-topic/peer-sig.js.map +1 -0
- package/dist/src/cohort-topic/protocols.d.ts +49 -0
- package/dist/src/cohort-topic/protocols.d.ts.map +1 -0
- package/dist/src/cohort-topic/protocols.js +58 -0
- package/dist/src/cohort-topic/protocols.js.map +1 -0
- package/dist/src/cohort-topic/reactivity-membership-gate.d.ts +49 -0
- package/dist/src/cohort-topic/reactivity-membership-gate.d.ts.map +1 -0
- package/dist/src/cohort-topic/reactivity-membership-gate.js +42 -0
- package/dist/src/cohort-topic/reactivity-membership-gate.js.map +1 -0
- package/dist/src/cohort-topic/size-estimator.d.ts +16 -0
- package/dist/src/cohort-topic/size-estimator.d.ts.map +1 -0
- package/dist/src/cohort-topic/size-estimator.js +16 -0
- package/dist/src/cohort-topic/size-estimator.js.map +1 -0
- package/dist/src/cohort-topic/stream-util.d.ts +19 -0
- package/dist/src/cohort-topic/stream-util.d.ts.map +1 -0
- package/dist/src/cohort-topic/stream-util.js +76 -0
- package/dist/src/cohort-topic/stream-util.js.map +1 -0
- package/dist/src/cohort-topic/threshold-crypto.d.ts +94 -0
- package/dist/src/cohort-topic/threshold-crypto.d.ts.map +1 -0
- package/dist/src/cohort-topic/threshold-crypto.js +178 -0
- package/dist/src/cohort-topic/threshold-crypto.js.map +1 -0
- package/dist/src/cohort-topic/topic-router.d.ts +41 -0
- package/dist/src/cohort-topic/topic-router.d.ts.map +1 -0
- package/dist/src/cohort-topic/topic-router.js +63 -0
- package/dist/src/cohort-topic/topic-router.js.map +1 -0
- package/dist/src/dispute/cascade.d.ts +179 -0
- package/dist/src/dispute/cascade.d.ts.map +1 -0
- package/dist/src/dispute/cascade.js +315 -0
- package/dist/src/dispute/cascade.js.map +1 -0
- package/dist/src/dispute/client.d.ts +2 -1
- package/dist/src/dispute/client.d.ts.map +1 -1
- package/dist/src/dispute/client.js +12 -3
- package/dist/src/dispute/client.js.map +1 -1
- package/dist/src/dispute/dispute-service.d.ts +41 -1
- package/dist/src/dispute/dispute-service.d.ts.map +1 -1
- package/dist/src/dispute/dispute-service.js +147 -21
- package/dist/src/dispute/dispute-service.js.map +1 -1
- package/dist/src/dispute/index.d.ts +2 -0
- package/dist/src/dispute/index.d.ts.map +1 -1
- package/dist/src/dispute/index.js +2 -0
- package/dist/src/dispute/index.js.map +1 -1
- package/dist/src/dispute/invalidation.d.ts +266 -0
- package/dist/src/dispute/invalidation.d.ts.map +1 -0
- package/dist/src/dispute/invalidation.js +405 -0
- package/dist/src/dispute/invalidation.js.map +1 -0
- package/dist/src/dispute/types.d.ts +14 -0
- package/dist/src/dispute/types.d.ts.map +1 -1
- package/dist/src/dispute/types.js.map +1 -1
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/libp2p-key-network.d.ts +7 -0
- package/dist/src/libp2p-key-network.d.ts.map +1 -1
- package/dist/src/libp2p-key-network.js +49 -5
- package/dist/src/libp2p-key-network.js.map +1 -1
- package/dist/src/libp2p-node-base.d.ts +45 -3
- package/dist/src/libp2p-node-base.d.ts.map +1 -1
- package/dist/src/libp2p-node-base.js +522 -5
- package/dist/src/libp2p-node-base.js.map +1 -1
- package/dist/src/matchmaking/aggregate-counts.d.ts +67 -0
- package/dist/src/matchmaking/aggregate-counts.d.ts.map +1 -0
- package/dist/src/matchmaking/aggregate-counts.js +60 -0
- package/dist/src/matchmaking/aggregate-counts.js.map +1 -0
- package/dist/src/matchmaking/index.d.ts +20 -0
- package/dist/src/matchmaking/index.d.ts.map +1 -0
- package/dist/src/matchmaking/index.js +20 -0
- package/dist/src/matchmaking/index.js.map +1 -0
- package/dist/src/matchmaking/module.d.ts +181 -0
- package/dist/src/matchmaking/module.d.ts.map +1 -0
- package/dist/src/matchmaking/module.js +221 -0
- package/dist/src/matchmaking/module.js.map +1 -0
- package/dist/src/matchmaking/protocols.d.ts +37 -0
- package/dist/src/matchmaking/protocols.d.ts.map +1 -0
- package/dist/src/matchmaking/protocols.js +42 -0
- package/dist/src/matchmaking/protocols.js.map +1 -0
- package/dist/src/matchmaking/provider-manager.d.ts +52 -0
- package/dist/src/matchmaking/provider-manager.d.ts.map +1 -0
- package/dist/src/matchmaking/provider-manager.js +74 -0
- package/dist/src/matchmaking/provider-manager.js.map +1 -0
- package/dist/src/matchmaking/query-handler.d.ts +34 -0
- package/dist/src/matchmaking/query-handler.d.ts.map +1 -0
- package/dist/src/matchmaking/query-handler.js +62 -0
- package/dist/src/matchmaking/query-handler.js.map +1 -0
- package/dist/src/matchmaking/query-transport.d.ts +180 -0
- package/dist/src/matchmaking/query-transport.d.ts.map +1 -0
- package/dist/src/matchmaking/query-transport.js +315 -0
- package/dist/src/matchmaking/query-transport.js.map +1 -0
- package/dist/src/matchmaking/seeker-manager.d.ts +39 -0
- package/dist/src/matchmaking/seeker-manager.d.ts.map +1 -0
- package/dist/src/matchmaking/seeker-manager.js +49 -0
- package/dist/src/matchmaking/seeker-manager.js.map +1 -0
- package/dist/src/matchmaking/seeker-walk-client.d.ts +127 -0
- package/dist/src/matchmaking/seeker-walk-client.d.ts.map +1 -0
- package/dist/src/matchmaking/seeker-walk-client.js +189 -0
- package/dist/src/matchmaking/seeker-walk-client.js.map +1 -0
- package/dist/src/matchmaking/traffic-validation.d.ts +128 -0
- package/dist/src/matchmaking/traffic-validation.d.ts.map +1 -0
- package/dist/src/matchmaking/traffic-validation.js +105 -0
- package/dist/src/matchmaking/traffic-validation.js.map +1 -0
- package/dist/src/network/network-manager-service.d.ts +4 -2
- package/dist/src/network/network-manager-service.d.ts.map +1 -1
- package/dist/src/network/network-manager-service.js +9 -3
- package/dist/src/network/network-manager-service.js.map +1 -1
- package/dist/src/protocol-client.d.ts +13 -0
- package/dist/src/protocol-client.d.ts.map +1 -1
- package/dist/src/protocol-client.js +74 -2
- package/dist/src/protocol-client.js.map +1 -1
- package/dist/src/reactivity/forwarder-host.d.ts +198 -0
- package/dist/src/reactivity/forwarder-host.d.ts.map +1 -0
- package/dist/src/reactivity/forwarder-host.js +355 -0
- package/dist/src/reactivity/forwarder-host.js.map +1 -0
- package/dist/src/reactivity/index.d.ts +19 -0
- package/dist/src/reactivity/index.d.ts.map +1 -0
- package/dist/src/reactivity/index.js +19 -0
- package/dist/src/reactivity/index.js.map +1 -0
- package/dist/src/reactivity/notify-transport.d.ts +70 -0
- package/dist/src/reactivity/notify-transport.d.ts.map +1 -0
- package/dist/src/reactivity/notify-transport.js +111 -0
- package/dist/src/reactivity/notify-transport.js.map +1 -0
- package/dist/src/reactivity/origination-manager.d.ts +110 -0
- package/dist/src/reactivity/origination-manager.d.ts.map +1 -0
- package/dist/src/reactivity/origination-manager.js +129 -0
- package/dist/src/reactivity/origination-manager.js.map +1 -0
- package/dist/src/reactivity/protocols.d.ts +43 -0
- package/dist/src/reactivity/protocols.d.ts.map +1 -0
- package/dist/src/reactivity/protocols.js +50 -0
- package/dist/src/reactivity/protocols.js.map +1 -0
- package/dist/src/reactivity/push-state-gossip.d.ts +132 -0
- package/dist/src/reactivity/push-state-gossip.d.ts.map +1 -0
- package/dist/src/reactivity/push-state-gossip.js +231 -0
- package/dist/src/reactivity/push-state-gossip.js.map +1 -0
- package/dist/src/reactivity/recover-transport.d.ts +167 -0
- package/dist/src/reactivity/recover-transport.d.ts.map +1 -0
- package/dist/src/reactivity/recover-transport.js +308 -0
- package/dist/src/reactivity/recover-transport.js.map +1 -0
- package/dist/src/reactivity/rotation-rereg-scheduler.d.ts +142 -0
- package/dist/src/reactivity/rotation-rereg-scheduler.d.ts.map +1 -0
- package/dist/src/reactivity/rotation-rereg-scheduler.js +223 -0
- package/dist/src/reactivity/rotation-rereg-scheduler.js.map +1 -0
- package/dist/src/reactivity/subscriber-registry.d.ts +47 -0
- package/dist/src/reactivity/subscriber-registry.d.ts.map +1 -0
- package/dist/src/reactivity/subscriber-registry.js +87 -0
- package/dist/src/reactivity/subscriber-registry.js.map +1 -0
- package/dist/src/reactivity/subscription-manager.d.ts +221 -0
- package/dist/src/reactivity/subscription-manager.d.ts.map +1 -0
- package/dist/src/reactivity/subscription-manager.js +302 -0
- package/dist/src/reactivity/subscription-manager.js.map +1 -0
- package/dist/src/reactivity/topic-bytes.d.ts +32 -0
- package/dist/src/reactivity/topic-bytes.d.ts.map +1 -0
- package/dist/src/reactivity/topic-bytes.js +34 -0
- package/dist/src/reactivity/topic-bytes.js.map +1 -0
- package/dist/src/repo/client.d.ts.map +1 -1
- package/dist/src/repo/client.js +51 -23
- package/dist/src/repo/client.js.map +1 -1
- package/dist/src/repo/service.d.ts +46 -1
- package/dist/src/repo/service.d.ts.map +1 -1
- package/dist/src/repo/service.js +79 -45
- package/dist/src/repo/service.js.map +1 -1
- package/dist/src/rpc-deadline.d.ts +37 -0
- package/dist/src/rpc-deadline.d.ts.map +1 -0
- package/dist/src/rpc-deadline.js +31 -0
- package/dist/src/rpc-deadline.js.map +1 -0
- package/dist/src/storage/block-storage.d.ts +2 -0
- package/dist/src/storage/block-storage.d.ts.map +1 -1
- package/dist/src/storage/block-storage.js +95 -2
- package/dist/src/storage/block-storage.js.map +1 -1
- package/dist/src/storage/i-block-storage.d.ts +25 -0
- package/dist/src/storage/i-block-storage.d.ts.map +1 -1
- package/dist/src/storage/storage-repo.d.ts +53 -2
- package/dist/src/storage/storage-repo.d.ts.map +1 -1
- package/dist/src/storage/storage-repo.js +193 -9
- package/dist/src/storage/storage-repo.js.map +1 -1
- package/dist/src/sync/client.d.ts +4 -1
- package/dist/src/sync/client.d.ts.map +1 -1
- package/dist/src/sync/client.js +5 -2
- package/dist/src/sync/client.js.map +1 -1
- package/dist/src/testing/cohort-topic-mesh-harness.d.ts +219 -0
- package/dist/src/testing/cohort-topic-mesh-harness.d.ts.map +1 -0
- package/dist/src/testing/cohort-topic-mesh-harness.js +467 -0
- package/dist/src/testing/cohort-topic-mesh-harness.js.map +1 -0
- package/dist/src/testing/matchmaking-mesh-harness.d.ts +187 -0
- package/dist/src/testing/matchmaking-mesh-harness.d.ts.map +1 -0
- package/dist/src/testing/matchmaking-mesh-harness.js +358 -0
- package/dist/src/testing/matchmaking-mesh-harness.js.map +1 -0
- package/dist/src/testing/mesh-harness.d.ts.map +1 -1
- package/dist/src/testing/mesh-harness.js +23 -1
- package/dist/src/testing/mesh-harness.js.map +1 -1
- package/dist/src/testing/reactivity-mesh-harness.d.ts +298 -0
- package/dist/src/testing/reactivity-mesh-harness.d.ts.map +1 -0
- package/dist/src/testing/reactivity-mesh-harness.js +663 -0
- package/dist/src/testing/reactivity-mesh-harness.js.map +1 -0
- package/package.json +7 -4
- package/src/cluster/block-transfer-service.ts +133 -68
- package/src/cluster/client.ts +64 -45
- package/src/cluster/cluster-error.ts +64 -0
- package/src/cluster/cluster-repo.ts +405 -55
- package/src/cluster/commit-cert.ts +139 -0
- package/src/cluster/service.ts +116 -44
- package/src/cluster/spread-on-churn.ts +328 -285
- package/src/cohort-topic/bootstrap-evidence-builder.ts +122 -0
- package/src/cohort-topic/bootstrap-evidence-verifiers.ts +132 -0
- package/src/cohort-topic/bootstrap-parent-reference.ts +159 -0
- package/src/cohort-topic/change-bridge.ts +109 -0
- package/src/cohort-topic/cohort-gossip-driver.ts +144 -0
- package/src/cohort-topic/cohort-gossip-transport.ts +74 -0
- package/src/cohort-topic/fret-trust-anchor.ts +153 -0
- package/src/cohort-topic/host.ts +2175 -0
- package/src/cohort-topic/index.ts +13 -0
- package/src/cohort-topic/membership-publish-sink.ts +20 -0
- package/src/cohort-topic/membership-source.ts +68 -0
- package/src/cohort-topic/peer-codec.ts +31 -0
- package/src/cohort-topic/peer-sig.ts +86 -0
- package/src/cohort-topic/protocols.ts +71 -0
- package/src/cohort-topic/reactivity-membership-gate.ts +77 -0
- package/src/cohort-topic/size-estimator.ts +16 -0
- package/src/cohort-topic/stream-util.ts +87 -0
- package/src/cohort-topic/threshold-crypto.ts +239 -0
- package/src/cohort-topic/topic-router.ts +77 -0
- package/src/dispute/cascade.ts +517 -0
- package/src/dispute/client.ts +12 -2
- package/src/dispute/dispute-service.ts +171 -24
- package/src/dispute/index.ts +42 -0
- package/src/dispute/invalidation.ts +587 -0
- package/src/dispute/types.ts +14 -0
- package/src/index.ts +4 -0
- package/src/libp2p-key-network.ts +49 -6
- package/src/libp2p-node-base.ts +620 -12
- package/src/matchmaking/aggregate-counts.ts +104 -0
- package/src/matchmaking/index.ts +20 -0
- package/src/matchmaking/module.ts +363 -0
- package/src/matchmaking/protocols.ts +51 -0
- package/src/matchmaking/provider-manager.ts +95 -0
- package/src/matchmaking/query-handler.ts +88 -0
- package/src/matchmaking/query-transport.ts +483 -0
- package/src/matchmaking/seeker-manager.ts +64 -0
- package/src/matchmaking/seeker-walk-client.ts +293 -0
- package/src/matchmaking/traffic-validation.ts +195 -0
- package/src/network/network-manager-service.ts +9 -2
- package/src/protocol-client.ts +64 -3
- package/src/reactivity/forwarder-host.ts +438 -0
- package/src/reactivity/index.ts +19 -0
- package/src/reactivity/notify-transport.ts +144 -0
- package/src/reactivity/origination-manager.ts +192 -0
- package/src/reactivity/protocols.ts +61 -0
- package/src/reactivity/push-state-gossip.ts +291 -0
- package/src/reactivity/recover-transport.ts +408 -0
- package/src/reactivity/rotation-rereg-scheduler.ts +256 -0
- package/src/reactivity/subscriber-registry.ts +96 -0
- package/src/reactivity/subscription-manager.ts +450 -0
- package/src/reactivity/topic-bytes.ts +37 -0
- package/src/repo/client.ts +54 -23
- package/src/repo/service.ts +90 -42
- package/src/rpc-deadline.ts +45 -0
- package/src/storage/block-storage.ts +106 -3
- package/src/storage/i-block-storage.ts +27 -0
- package/src/storage/storage-repo.ts +209 -13
- package/src/sync/client.ts +5 -2
- package/src/testing/cohort-topic-mesh-harness.ts +613 -0
- package/src/testing/matchmaking-mesh-harness.ts +475 -0
- package/src/testing/mesh-harness.ts +22 -2
- package/src/testing/reactivity-mesh-harness.ts +922 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { bytesToB64url, b64urlToBytes, encodeCohortMessage } from "@optimystic/db-core";
|
|
2
|
+
import { bytesToPeerId } from "./peer-codec.js";
|
|
3
|
+
import { requestResponse, DEFAULT_STREAM_MAX_BYTES } from "./stream-util.js";
|
|
4
|
+
import { PROTOCOL_COHORT_REGISTER } from "./protocols.js";
|
|
5
|
+
/** A FRET `routeAct` result carrying a cohort reply. */
|
|
6
|
+
function isCommit(res) {
|
|
7
|
+
return typeof res === "object" && res !== null && "commitCertificate" in res;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* FRET-backed {@link ITopicRouter}.
|
|
11
|
+
*
|
|
12
|
+
* `routeAndAct` maps onto FRET's `RouteAndMaybeAct` (`FretService.routeAct`): the `RegisterV1` frame
|
|
13
|
+
* rides the `activity` field (base64url), routed to the cohort owning `key = coord_d(self, topicId)`,
|
|
14
|
+
* collecting `want_k = k` participants and `min_sigs = k − x`. The cohort's activity callback (set by
|
|
15
|
+
* the host) runs the willingness / cold-start / admission decision and returns the encoded
|
|
16
|
+
* `RegisterReplyV1` as the `commitCertificate`; this adapter decodes it back to bytes. A bare
|
|
17
|
+
* `NearAnchorV1` (no in-cluster activity ran) is surfaced to the walk as `no_state`.
|
|
18
|
+
*
|
|
19
|
+
* `dialMember` is the post-registration direct path: a libp2p dial of the `/register` protocol to the
|
|
20
|
+
* cached primary, used by the renewal ping (`docs/cohort-topic.md` §FRET integration L457-460).
|
|
21
|
+
*/
|
|
22
|
+
export class FretTopicRouter {
|
|
23
|
+
node;
|
|
24
|
+
fret;
|
|
25
|
+
registerProtocol;
|
|
26
|
+
ttl;
|
|
27
|
+
maxBytes;
|
|
28
|
+
clock;
|
|
29
|
+
constructor(node, fret, options = {}) {
|
|
30
|
+
this.node = node;
|
|
31
|
+
this.fret = fret;
|
|
32
|
+
this.registerProtocol = options.registerProtocol ?? PROTOCOL_COHORT_REGISTER;
|
|
33
|
+
this.ttl = options.ttl ?? 16;
|
|
34
|
+
this.maxBytes = options.maxBytes ?? DEFAULT_STREAM_MAX_BYTES;
|
|
35
|
+
this.clock = options.clock ?? (() => Date.now());
|
|
36
|
+
}
|
|
37
|
+
async routeAndAct(key, activity, opts) {
|
|
38
|
+
const now = this.clock();
|
|
39
|
+
const msg = {
|
|
40
|
+
v: 1,
|
|
41
|
+
key: bytesToB64url(key),
|
|
42
|
+
want_k: opts.wantK,
|
|
43
|
+
min_sigs: opts.minSigs,
|
|
44
|
+
ttl: this.ttl,
|
|
45
|
+
activity: bytesToB64url(activity),
|
|
46
|
+
correlation_id: bytesToB64url(key) + ":" + now,
|
|
47
|
+
timestamp: now,
|
|
48
|
+
signature: "",
|
|
49
|
+
};
|
|
50
|
+
const res = await this.fret.routeAct(msg);
|
|
51
|
+
if (isCommit(res)) {
|
|
52
|
+
return b64urlToBytes(res.commitCertificate);
|
|
53
|
+
}
|
|
54
|
+
// No in-cluster activity ran (we only reached an anchor hint): the walk treats this as NoState
|
|
55
|
+
// and steps toward the root.
|
|
56
|
+
return encodeCohortMessage({ v: 1, result: "no_state" }, this.maxBytes);
|
|
57
|
+
}
|
|
58
|
+
async dialMember(member, activity) {
|
|
59
|
+
const peer = bytesToPeerId(member.id);
|
|
60
|
+
return requestResponse(this.node, peer, this.registerProtocol, activity, this.maxBytes);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=topic-router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"topic-router.js","sourceRoot":"","sources":["../../../src/cohort-topic/topic-router.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAGxF,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wDAAwD;AACxD,SAAS,QAAQ,CAAC,GAAiD;IAClE,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,mBAAmB,IAAI,GAAG,CAAC;AAC9E,CAAC;AAaD;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,eAAe;IAME;IAA+B;IAL3C,gBAAgB,CAAS;IACzB,GAAG,CAAS;IACZ,QAAQ,CAAS;IACjB,KAAK,CAAe;IAErC,YAA6B,IAAY,EAAmB,IAAiB,EAAE,UAAkC,EAAE;QAAtF,SAAI,GAAJ,IAAI,CAAQ;QAAmB,SAAI,GAAJ,IAAI,CAAa;QAC5E,IAAI,CAAC,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,IAAI,wBAAwB,CAAC;QAC7E,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,EAAE,CAAC;QAC7B,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,wBAAwB,CAAC;QAC7D,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,GAAW,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,GAAc,EAAE,QAAoB,EAAE,IAAwC;QAC/F,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,GAAuB;YAC/B,CAAC,EAAE,CAAC;YACJ,GAAG,EAAE,aAAa,CAAC,GAAG,CAAC;YACvB,MAAM,EAAE,IAAI,CAAC,KAAK;YAClB,QAAQ,EAAE,IAAI,CAAC,OAAO;YACtB,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,QAAQ,EAAE,aAAa,CAAC,QAAQ,CAAC;YACjC,cAAc,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG;YAC9C,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,EAAE;SACb,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC1C,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACnB,OAAO,aAAa,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QAC7C,CAAC;QACD,+FAA+F;QAC/F,6BAA6B;QAC7B,OAAO,mBAAmB,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IACzE,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,MAAe,EAAE,QAAoB;QACrD,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACtC,OAAO,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IACzF,CAAC;CACD"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import type { ActionId, BlockId, CollectionId, Log, DisputeResolutionProof, RevertedBlock, ReadDependency } from '@optimystic/db-core';
|
|
2
|
+
import type { IBlockStorage } from '../storage/i-block-storage.js';
|
|
3
|
+
import { type CertificateTarget } from './invalidation.js';
|
|
4
|
+
export type CascadeConfig = {
|
|
5
|
+
/**
|
|
6
|
+
* Maximum number of re-evaluation rounds. Each round rescans the in-scope collections for fresh
|
|
7
|
+
* read-dependents of everything invalidated so far; a linear chain processed in revision order
|
|
8
|
+
* collapses into a single round, so this caps pathological out-of-order dependency graphs.
|
|
9
|
+
*/
|
|
10
|
+
readonly maxCascadeDepth: number;
|
|
11
|
+
/** Maximum transactions the cascade may invalidate, counting the root. */
|
|
12
|
+
readonly maxCascadeTransactions: number;
|
|
13
|
+
};
|
|
14
|
+
export declare const DEFAULT_CASCADE_CONFIG: CascadeConfig;
|
|
15
|
+
/**
|
|
16
|
+
* Everything the cascade needs from one collection: its append-only log (where child invalidation
|
|
17
|
+
* entries land and where read-dependents are discovered) and a resolver for the per-block storage
|
|
18
|
+
* its actions wrote. The caller supplies one per collection in the cascade's universe — the root's
|
|
19
|
+
* collections plus every collection reachable via a cross-collection read edge. (Discovering that
|
|
20
|
+
* universe requires a block→collection read index; the engine consumes the universe rather than
|
|
21
|
+
* computing it — see the handoff's cross-collection note.)
|
|
22
|
+
*/
|
|
23
|
+
export type CollectionEnv = {
|
|
24
|
+
readonly collectionId: CollectionId;
|
|
25
|
+
readonly log: Log<unknown>;
|
|
26
|
+
readonly createBlockStorage: (blockId: BlockId) => IBlockStorage;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* A block revision proven invalid: a committed action wrote `blockId` at `rev`, and that action has
|
|
30
|
+
* been invalidated (the root, or a cascade child). Any committed transaction whose read set contains
|
|
31
|
+
* `(blockId, rev)` observed this now-invalid revision and is a read-dependent.
|
|
32
|
+
*
|
|
33
|
+
* `restoredContentHash` is the content hash of the as-if-absent (reverted) value — the hash the
|
|
34
|
+
* invalidation recorded. The default re-evaluator compares it against the content the dependent
|
|
35
|
+
* actually observed: equal ⇒ the revert did not change what was read ⇒ retain.
|
|
36
|
+
*/
|
|
37
|
+
export type InvalidatedPair = {
|
|
38
|
+
readonly blockId: BlockId;
|
|
39
|
+
readonly rev: number;
|
|
40
|
+
readonly restoredContentHash: string;
|
|
41
|
+
/** The collection whose invalidation produced this pair (so same-collection rev ordering is checkable). */
|
|
42
|
+
readonly collectionId: CollectionId;
|
|
43
|
+
/** Resolves storage for this block, from its owning collection — the dependent may live elsewhere. */
|
|
44
|
+
readonly createBlockStorage: (blockId: BlockId) => IBlockStorage;
|
|
45
|
+
};
|
|
46
|
+
/** A candidate read-dependent under re-evaluation against post-invalidation state. */
|
|
47
|
+
export type CascadeCandidate = {
|
|
48
|
+
readonly env: CollectionEnv;
|
|
49
|
+
readonly collectionId: CollectionId;
|
|
50
|
+
readonly actionId: ActionId;
|
|
51
|
+
readonly rev: number;
|
|
52
|
+
/** Blocks this action wrote (its entry's blockIds) — what gets reverted if it is invalidated. */
|
|
53
|
+
readonly blockIds: ReadonlyArray<BlockId>;
|
|
54
|
+
/** This action's persisted read set, or `undefined` for a legacy (pre-cascade) entry. */
|
|
55
|
+
readonly reads: ReadonlyArray<ReadDependency> | undefined;
|
|
56
|
+
/** The subset of `reads` intersecting an invalidated `(blockId, rev)`. Empty for a legacy candidate. */
|
|
57
|
+
readonly matched: ReadonlyArray<InvalidatedPair>;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Verdict for a candidate re-evaluated against the reverted state:
|
|
61
|
+
* - `retain` — the read still holds; the transaction stands untouched (the re-evaluation prune).
|
|
62
|
+
* - `invalidate` — the read no longer holds; revert this transaction and recurse into its dependents.
|
|
63
|
+
* - `unevaluable` — cannot decide from available data (e.g. a legacy entry with no persisted reads,
|
|
64
|
+
* and no engine to re-execute). Escalated rather than guessed.
|
|
65
|
+
*/
|
|
66
|
+
export type CascadeVerdict = 'retain' | 'invalidate' | 'unevaluable';
|
|
67
|
+
/** Decides whether a candidate still holds against the reverted state. */
|
|
68
|
+
export type Reevaluate = (candidate: CascadeCandidate) => Promise<CascadeVerdict>;
|
|
69
|
+
/**
|
|
70
|
+
* The default, engine-free re-evaluator: deterministic from stored revisions alone (no engine replay),
|
|
71
|
+
* matching the compensating-state philosophy of the single-collection core.
|
|
72
|
+
*
|
|
73
|
+
* For each of the candidate's intersecting reads `(blockId, rev)`, it compares the content the
|
|
74
|
+
* candidate *observed* (the immutable historical revision `blockId@rev`) against the `restoredContentHash`
|
|
75
|
+
* the invalidation recorded (the as-if-absent value):
|
|
76
|
+
* - any read whose observed content differs from the restored content ⇒ the read no longer holds ⇒ **invalidate**;
|
|
77
|
+
* - a writer that *created* the block (deleted-block sentinel) ⇒ the observed content no longer exists ⇒ **invalidate**;
|
|
78
|
+
* - all intersecting reads unchanged ⇒ **retain** (e.g. a structural-block false dependent whose content the
|
|
79
|
+
* revert did not actually alter, or a redundant write that reverted to the same bytes).
|
|
80
|
+
* - a legacy entry (no persisted reads) ⇒ **unevaluable** (escalate, never guess independent).
|
|
81
|
+
*
|
|
82
|
+
* This is *sound but conservative* at block granularity: it never wrongly retains, but because reads are
|
|
83
|
+
* block-granular it may invalidate a dependent that read an unchanged *field* of a changed block. That is
|
|
84
|
+
* safe (over-invalidation just resubmits the transaction). Field/operation-granular pruning — re-executing
|
|
85
|
+
* the transaction and checking its operations still reproduce — requires an engine and is provided by
|
|
86
|
+
* injecting a custom {@link Reevaluate} instead (see the handoff).
|
|
87
|
+
*/
|
|
88
|
+
export declare function contentEqualityReevaluator(): Reevaluate;
|
|
89
|
+
/** A `(blockId, rev)` the root invalidation proved invalid in a given collection, with its restored hash. */
|
|
90
|
+
export type CascadeSeed = {
|
|
91
|
+
readonly collectionId: CollectionId;
|
|
92
|
+
readonly blockId: BlockId;
|
|
93
|
+
readonly rev: number;
|
|
94
|
+
readonly restoredContentHash: string;
|
|
95
|
+
};
|
|
96
|
+
export type CascadeInput = {
|
|
97
|
+
/** actionId of the root invalidation — recorded as `cascadeRoot` on every child entry. */
|
|
98
|
+
readonly rootActionId: ActionId;
|
|
99
|
+
/** The root's invalidation certificate; reused to authorize each child invalidation. */
|
|
100
|
+
readonly proof: DisputeResolutionProof;
|
|
101
|
+
/** The `(blockId, rev)` pairs the root reversal produced — seeds the dependency frontier. */
|
|
102
|
+
readonly seed: ReadonlyArray<CascadeSeed>;
|
|
103
|
+
/**
|
|
104
|
+
* The target the root proof's votes are bound to — `(rootActionId, root blockIds)`. Every child
|
|
105
|
+
* reuses the root proof, whose votes were signed over the *root's* targetHash, so each child's
|
|
106
|
+
* certificate verification must be against this target, not the child's own. Defaults to the root
|
|
107
|
+
* action id plus the distinct block ids across {@link seed} (the root's reverted blocks). Pass it
|
|
108
|
+
* explicitly when the seed is not a faithful 1:1 image of the root's commit blockIds.
|
|
109
|
+
*/
|
|
110
|
+
readonly certificateTarget?: CertificateTarget;
|
|
111
|
+
/** Every collection the cascade may walk: the root's, plus any reachable via cross-collection reads. */
|
|
112
|
+
readonly envs: ReadonlyArray<CollectionEnv>;
|
|
113
|
+
readonly config?: CascadeConfig;
|
|
114
|
+
/** Re-evaluation strategy; defaults to {@link contentEqualityReevaluator}. */
|
|
115
|
+
readonly reevaluate?: Reevaluate;
|
|
116
|
+
/**
|
|
117
|
+
* Operator-escalation health signal: invoked once when the cascade stops at a hard horizon (or hits
|
|
118
|
+
* an unevaluable candidate) and the affected collection(s) need a full re-sync. Never throws past here.
|
|
119
|
+
*/
|
|
120
|
+
readonly onEscalation?: (escalation: CascadeEscalation) => void;
|
|
121
|
+
};
|
|
122
|
+
export type CascadeChild = {
|
|
123
|
+
readonly collectionId: CollectionId;
|
|
124
|
+
readonly actionId: ActionId;
|
|
125
|
+
readonly rev: number;
|
|
126
|
+
readonly reverted: ReadonlyArray<RevertedBlock>;
|
|
127
|
+
};
|
|
128
|
+
export type CascadeStanding = {
|
|
129
|
+
readonly collectionId: CollectionId;
|
|
130
|
+
readonly actionId: ActionId;
|
|
131
|
+
readonly rev: number;
|
|
132
|
+
};
|
|
133
|
+
export type CascadeEscalation = {
|
|
134
|
+
readonly reason: 'max-depth' | 'max-transactions' | 'unevaluable';
|
|
135
|
+
/** Collections to flag for operator-escalated full re-sync. */
|
|
136
|
+
readonly collections: ReadonlyArray<CollectionId>;
|
|
137
|
+
/** Read-dependents left un-cascaded at the horizon — surfaced, never silently dropped. */
|
|
138
|
+
readonly remainder: ReadonlyArray<CascadeStanding>;
|
|
139
|
+
/** Candidates that could not be re-evaluated (e.g. legacy entries with no engine to re-execute them). */
|
|
140
|
+
readonly unevaluable: ReadonlyArray<CascadeStanding>;
|
|
141
|
+
};
|
|
142
|
+
export type CascadeResult = {
|
|
143
|
+
readonly rootActionId: ActionId;
|
|
144
|
+
/** Read-dependents invalidated by the cascade (children only — the root is the caller's to apply). */
|
|
145
|
+
readonly invalidated: ReadonlyArray<CascadeChild>;
|
|
146
|
+
/** Read-dependents re-evaluated and retained (appeared in the chain but did not actually depend). */
|
|
147
|
+
readonly retained: ReadonlyArray<CascadeStanding>;
|
|
148
|
+
/** Re-evaluation rounds run (dependency-graph depth proxy). */
|
|
149
|
+
readonly rounds: number;
|
|
150
|
+
/** Present iff the cascade stopped at a hard horizon or hit an unevaluable candidate. */
|
|
151
|
+
readonly escalation?: CascadeEscalation;
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* Detects and re-evaluates the transitive read-dependents of an already-applied root invalidation,
|
|
155
|
+
* invalidating only those that no longer hold against the reverted state and leaving the rest in place.
|
|
156
|
+
*
|
|
157
|
+
* Preconditions: the caller has already applied the *root* reversal (driven through cluster consensus)
|
|
158
|
+
* and supplies its proven-invalid `(blockId, rev)` pairs as `seed`. This engine owns only the *cascade*:
|
|
159
|
+
* each child invalidation is appended via {@link applyInvalidation} carrying `cascadeRoot`, exactly the
|
|
160
|
+
* deterministic primitive every member runs — so a member replaying the same seed + logs converges on
|
|
161
|
+
* the same children (no per-child consensus round is required while the re-evaluator is deterministic;
|
|
162
|
+
* a non-deterministic/engine-based re-evaluator would need each child driven through consensus instead).
|
|
163
|
+
*
|
|
164
|
+
* Algorithm (fixpoint):
|
|
165
|
+
* 1. Seed the invalidated `(blockId, rev)` frontier from the root.
|
|
166
|
+
* 2. Each round, walk every in-scope collection log forward, collecting unprocessed actions whose read
|
|
167
|
+
* set intersects the frontier (legacy reads-less entries are always candidates — unknown dependency).
|
|
168
|
+
* 3. Process candidates in `(rev, collectionId, actionId)` order, deduped by actionId. Re-evaluate each
|
|
169
|
+
* against the reverted state; **retain** leaves it (revisited next round in case a later ancestor
|
|
170
|
+
* reverts), **invalidate** appends its child entry and feeds its reverted blocks back into the frontier.
|
|
171
|
+
* 4. Repeat until a round makes no progress (fixpoint) or a horizon trips (escalate, applying what it did).
|
|
172
|
+
*
|
|
173
|
+
* Diamonds: a dependent of two invalidated ancestors is evaluated once (dedup), after both are reverted
|
|
174
|
+
* (revision order within a collection; cross-collection retains are re-examined every round until fixpoint).
|
|
175
|
+
* Cycle-freedom: a read observes a strictly earlier write, so within a collection a child's rev exceeds the
|
|
176
|
+
* pair it depends on — a back-edge is corruption and throws.
|
|
177
|
+
*/
|
|
178
|
+
export declare function cascadeInvalidate(input: CascadeInput): Promise<CascadeResult>;
|
|
179
|
+
//# sourceMappingURL=cascade.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cascade.d.ts","sourceRoot":"","sources":["../../../src/dispute/cascade.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,EACpC,sBAAsB,EAAE,aAAa,EAAE,cAAc,EACrD,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAA8D,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAOvH,MAAM,MAAM,aAAa,GAAG;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,0EAA0E;IAC1E,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;CACxC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,aAGpC,CAAC;AAIF;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG;IAC3B,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IAC3B,QAAQ,CAAC,kBAAkB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,aAAa,CAAC;CACjE,CAAC;AAIF;;;;;;;;GAQG;AACH,MAAM,MAAM,eAAe,GAAG;IAC7B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,2GAA2G;IAC3G,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,sGAAsG;IACtG,QAAQ,CAAC,kBAAkB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,aAAa,CAAC;CACjE,CAAC;AAkBF,sFAAsF;AACtF,MAAM,MAAM,gBAAgB,GAAG;IAC9B,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,iGAAiG;IACjG,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAC1C,yFAAyF;IACzF,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAC1D,wGAAwG;IACxG,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;CACjD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,YAAY,GAAG,aAAa,CAAC;AAErE,0EAA0E;AAC1E,MAAM,MAAM,UAAU,GAAG,CAAC,SAAS,EAAE,gBAAgB,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;AAElF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,0BAA0B,IAAI,UAAU,CAwBvD;AAID,6GAA6G;AAC7G,MAAM,MAAM,WAAW,GAAG;IACzB,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IAC1B,0FAA0F;IAC1F,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC;IAChC,wFAAwF;IACxF,QAAQ,CAAC,KAAK,EAAE,sBAAsB,CAAC;IACvC,6FAA6F;IAC7F,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IAC1C;;;;;;OAMG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IAC/C,wGAAwG;IACxG,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IAC5C,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;IACjC;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAChE,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IAC1B,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC7B,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC/B,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,kBAAkB,GAAG,aAAa,CAAC;IAClE,+DAA+D;IAC/D,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IAClD,0FAA0F;IAC1F,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IACnD,yGAAyG;IACzG,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;CACrD,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC3B,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC;IAChC,sGAAsG;IACtG,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IAClD,qGAAqG;IACrG,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAClD,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,yFAAyF;IACzF,QAAQ,CAAC,UAAU,CAAC,EAAE,iBAAiB,CAAC;CACxC,CAAC;AAIF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAuKnF"}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { applyInvalidation, hashBlockContent, DELETED_BLOCK_RESTORE } from './invalidation.js';
|
|
2
|
+
import { createLogger } from '../logger.js';
|
|
3
|
+
const log = createLogger('cascade');
|
|
4
|
+
export const DEFAULT_CASCADE_CONFIG = {
|
|
5
|
+
maxCascadeDepth: 32,
|
|
6
|
+
maxCascadeTransactions: 1000,
|
|
7
|
+
};
|
|
8
|
+
function pairKey(blockId, rev) {
|
|
9
|
+
return `${blockId}\0${rev}`;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Dedup identity for a reverted log entry: the (collectionId, actionId) pair, not the actionId
|
|
13
|
+
* alone. A transaction spanning N collections has one entry per collection (same actionId,
|
|
14
|
+
* different collection/blockIds/rev) — each must be reverted independently, tracked separately.
|
|
15
|
+
* Uses a NUL separator, mirroring {@link pairKey}, so ids containing spaces cannot collide.
|
|
16
|
+
*/
|
|
17
|
+
function entryKey(collectionId, actionId) {
|
|
18
|
+
return `${collectionId}\0${actionId}`;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The default, engine-free re-evaluator: deterministic from stored revisions alone (no engine replay),
|
|
22
|
+
* matching the compensating-state philosophy of the single-collection core.
|
|
23
|
+
*
|
|
24
|
+
* For each of the candidate's intersecting reads `(blockId, rev)`, it compares the content the
|
|
25
|
+
* candidate *observed* (the immutable historical revision `blockId@rev`) against the `restoredContentHash`
|
|
26
|
+
* the invalidation recorded (the as-if-absent value):
|
|
27
|
+
* - any read whose observed content differs from the restored content ⇒ the read no longer holds ⇒ **invalidate**;
|
|
28
|
+
* - a writer that *created* the block (deleted-block sentinel) ⇒ the observed content no longer exists ⇒ **invalidate**;
|
|
29
|
+
* - all intersecting reads unchanged ⇒ **retain** (e.g. a structural-block false dependent whose content the
|
|
30
|
+
* revert did not actually alter, or a redundant write that reverted to the same bytes).
|
|
31
|
+
* - a legacy entry (no persisted reads) ⇒ **unevaluable** (escalate, never guess independent).
|
|
32
|
+
*
|
|
33
|
+
* This is *sound but conservative* at block granularity: it never wrongly retains, but because reads are
|
|
34
|
+
* block-granular it may invalidate a dependent that read an unchanged *field* of a changed block. That is
|
|
35
|
+
* safe (over-invalidation just resubmits the transaction). Field/operation-granular pruning — re-executing
|
|
36
|
+
* the transaction and checking its operations still reproduce — requires an engine and is provided by
|
|
37
|
+
* injecting a custom {@link Reevaluate} instead (see the handoff).
|
|
38
|
+
*/
|
|
39
|
+
export function contentEqualityReevaluator() {
|
|
40
|
+
return async (candidate) => {
|
|
41
|
+
if (candidate.reads === undefined) {
|
|
42
|
+
return 'unevaluable';
|
|
43
|
+
}
|
|
44
|
+
// Defensive: a candidate with no intersecting reads is not actually a dependent.
|
|
45
|
+
if (candidate.matched.length === 0) {
|
|
46
|
+
return 'retain';
|
|
47
|
+
}
|
|
48
|
+
for (const pair of candidate.matched) {
|
|
49
|
+
if (pair.restoredContentHash === DELETED_BLOCK_RESTORE) {
|
|
50
|
+
return 'invalidate';
|
|
51
|
+
}
|
|
52
|
+
const observed = await pair.createBlockStorage(pair.blockId).getBlock(pair.rev);
|
|
53
|
+
if (!observed) {
|
|
54
|
+
// Cannot confirm the observed revision still materializes → conservative invalidate.
|
|
55
|
+
return 'invalidate';
|
|
56
|
+
}
|
|
57
|
+
if (await hashBlockContent(observed.block) !== pair.restoredContentHash) {
|
|
58
|
+
return 'invalidate';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return 'retain';
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
// ─── Engine ───
|
|
65
|
+
/**
|
|
66
|
+
* Detects and re-evaluates the transitive read-dependents of an already-applied root invalidation,
|
|
67
|
+
* invalidating only those that no longer hold against the reverted state and leaving the rest in place.
|
|
68
|
+
*
|
|
69
|
+
* Preconditions: the caller has already applied the *root* reversal (driven through cluster consensus)
|
|
70
|
+
* and supplies its proven-invalid `(blockId, rev)` pairs as `seed`. This engine owns only the *cascade*:
|
|
71
|
+
* each child invalidation is appended via {@link applyInvalidation} carrying `cascadeRoot`, exactly the
|
|
72
|
+
* deterministic primitive every member runs — so a member replaying the same seed + logs converges on
|
|
73
|
+
* the same children (no per-child consensus round is required while the re-evaluator is deterministic;
|
|
74
|
+
* a non-deterministic/engine-based re-evaluator would need each child driven through consensus instead).
|
|
75
|
+
*
|
|
76
|
+
* Algorithm (fixpoint):
|
|
77
|
+
* 1. Seed the invalidated `(blockId, rev)` frontier from the root.
|
|
78
|
+
* 2. Each round, walk every in-scope collection log forward, collecting unprocessed actions whose read
|
|
79
|
+
* set intersects the frontier (legacy reads-less entries are always candidates — unknown dependency).
|
|
80
|
+
* 3. Process candidates in `(rev, collectionId, actionId)` order, deduped by actionId. Re-evaluate each
|
|
81
|
+
* against the reverted state; **retain** leaves it (revisited next round in case a later ancestor
|
|
82
|
+
* reverts), **invalidate** appends its child entry and feeds its reverted blocks back into the frontier.
|
|
83
|
+
* 4. Repeat until a round makes no progress (fixpoint) or a horizon trips (escalate, applying what it did).
|
|
84
|
+
*
|
|
85
|
+
* Diamonds: a dependent of two invalidated ancestors is evaluated once (dedup), after both are reverted
|
|
86
|
+
* (revision order within a collection; cross-collection retains are re-examined every round until fixpoint).
|
|
87
|
+
* Cycle-freedom: a read observes a strictly earlier write, so within a collection a child's rev exceeds the
|
|
88
|
+
* pair it depends on — a back-edge is corruption and throws.
|
|
89
|
+
*/
|
|
90
|
+
export async function cascadeInvalidate(input) {
|
|
91
|
+
const config = input.config ?? DEFAULT_CASCADE_CONFIG;
|
|
92
|
+
const reevaluate = input.reevaluate ?? contentEqualityReevaluator();
|
|
93
|
+
const envByCollection = new Map(input.envs.map(e => [e.collectionId, e]));
|
|
94
|
+
// Invalidated frontier, seeded from the root's reverted blocks.
|
|
95
|
+
const pairs = new Map();
|
|
96
|
+
for (const s of input.seed) {
|
|
97
|
+
const env = envByCollection.get(s.collectionId);
|
|
98
|
+
if (!env) {
|
|
99
|
+
throw new Error(`cascade: seed references collection ${s.collectionId} not present in envs`);
|
|
100
|
+
}
|
|
101
|
+
pairs.set(pairKey(s.blockId, s.rev), {
|
|
102
|
+
blockId: s.blockId, rev: s.rev, restoredContentHash: s.restoredContentHash,
|
|
103
|
+
collectionId: s.collectionId, createBlockStorage: env.createBlockStorage,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
const rootActionId = input.rootActionId;
|
|
107
|
+
// The root proof's votes are bound to the ROOT's target; every child reuses that proof, so each
|
|
108
|
+
// child's applyInvalidation must verify against the root's target rather than the child's own. The
|
|
109
|
+
// child-specific justification is THIS deterministic read-dependency derivation, replayed identically
|
|
110
|
+
// by every member — not the certificate (which only attests the root is invalid).
|
|
111
|
+
const rootCertificateTarget = input.certificateTarget
|
|
112
|
+
?? { invalidatedActionId: rootActionId, blockIds: [...new Set(input.seed.map(s => s.blockId))] };
|
|
113
|
+
// Dedup identity is per collection-entry (collectionId, actionId), not actionId alone: a
|
|
114
|
+
// multi-collection transaction has one entry per collection and each must be reverted separately.
|
|
115
|
+
const processedEntries = new Set(); // entryKey() of collection-entries reverted this cascade
|
|
116
|
+
// The horizon counts distinct transactions (the root counts once, a multi-collection dependent once),
|
|
117
|
+
// so a transaction is never split across the budget — reverted in some collections, escalated in others.
|
|
118
|
+
const invalidatedTxns = new Set([rootActionId]);
|
|
119
|
+
const children = [];
|
|
120
|
+
const affectedCollections = new Set(input.seed.map(s => s.collectionId));
|
|
121
|
+
const unevaluable = [];
|
|
122
|
+
let retained = [];
|
|
123
|
+
let rounds = 0;
|
|
124
|
+
let escalation;
|
|
125
|
+
// Set once a new transaction is refused at the transaction horizon. We do NOT break the cascade
|
|
126
|
+
// on that refusal: already-counted transactions must still finish every remaining collection-entry
|
|
127
|
+
// (all-or-nothing), so we skip only the over-budget newcomer and let the round complete. The
|
|
128
|
+
// max-transactions escalation is built once at the end, after the protected transactions drain.
|
|
129
|
+
let horizonReached = false;
|
|
130
|
+
while (true) {
|
|
131
|
+
// Depth horizon: stop before another rescan, surfacing the un-cascaded frontier.
|
|
132
|
+
if (rounds >= config.maxCascadeDepth) {
|
|
133
|
+
const remainder = await collectCandidates(input.envs, pairs, rootActionId, processedEntries);
|
|
134
|
+
escalation = makeEscalation('max-depth', affectedCollections, remainder, unevaluable);
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
rounds++;
|
|
138
|
+
const candidates = await collectCandidates(input.envs, pairs, rootActionId, processedEntries);
|
|
139
|
+
if (candidates.length === 0) {
|
|
140
|
+
break; // fixpoint: no remaining read-dependents
|
|
141
|
+
}
|
|
142
|
+
retained = [];
|
|
143
|
+
let progressed = false;
|
|
144
|
+
for (const cand of candidates) {
|
|
145
|
+
if (processedEntries.has(entryKey(cand.collectionId, cand.actionId))) {
|
|
146
|
+
continue; // diamond: an ancestor pass already reverted this collection-entry
|
|
147
|
+
}
|
|
148
|
+
// Recompute matches against the live frontier (picks up same-round ancestors, ordered by rev).
|
|
149
|
+
const matched = matchReads(cand.reads, pairs);
|
|
150
|
+
const isLegacy = cand.reads === undefined;
|
|
151
|
+
if (matched.length === 0 && !isLegacy) {
|
|
152
|
+
continue; // no longer a dependent this round — revisit next round
|
|
153
|
+
}
|
|
154
|
+
assertForwardOnly(cand, matched);
|
|
155
|
+
const verdict = await reevaluate({ ...cand, matched });
|
|
156
|
+
if (verdict === 'retain') {
|
|
157
|
+
retained.push(standing(cand));
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (verdict === 'unevaluable') {
|
|
161
|
+
if (!unevaluable.some(u => u.collectionId === cand.collectionId && u.actionId === cand.actionId)) {
|
|
162
|
+
unevaluable.push(standing(cand));
|
|
163
|
+
}
|
|
164
|
+
affectedCollections.add(cand.collectionId);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
// invalidate — but never START a new transaction past the horizon. An already-counted
|
|
168
|
+
// transaction's remaining collection-entries pass freely (the `has` short-circuit), so a
|
|
169
|
+
// multi-collection dependent is reverted all-or-nothing and is never split across the budget.
|
|
170
|
+
// Crucially we only SKIP the over-budget newcomer here — we must not break the round, or a
|
|
171
|
+
// counted transaction's later-sorted sibling entry would be abandoned (silent partial revert).
|
|
172
|
+
if (!invalidatedTxns.has(cand.actionId) && invalidatedTxns.size + 1 > config.maxCascadeTransactions) {
|
|
173
|
+
horizonReached = true;
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
const env = cand.env;
|
|
177
|
+
const result = await applyInvalidation({ log: env.log, createBlockStorage: env.createBlockStorage }, {
|
|
178
|
+
invalidatedActionId: cand.actionId,
|
|
179
|
+
invalidatedRev: cand.rev,
|
|
180
|
+
blockIds: cand.blockIds,
|
|
181
|
+
proof: input.proof,
|
|
182
|
+
cascadeRoot: input.rootActionId,
|
|
183
|
+
// Verify the reused root proof against the root's target, not this child's own.
|
|
184
|
+
certificateTarget: rootCertificateTarget,
|
|
185
|
+
});
|
|
186
|
+
// `applied:false, already-applied` is the idempotent re-run path: the child entry already
|
|
187
|
+
// exists (prior cascade run / restart). Treat it as invalidated and reuse its reverted blocks
|
|
188
|
+
// so the frontier still grows and the cascade reconverges without a second entry.
|
|
189
|
+
if (!result.applied && result.reason !== 'already-applied') {
|
|
190
|
+
// invalid-certificate should be impossible: the child verifies the root proof against the
|
|
191
|
+
// root's target (rootCertificateTarget), and the root proof is a valid challenger-wins cert.
|
|
192
|
+
log('child-apply-rejected actionId=%s reason=%s', cand.actionId, result.reason);
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
processedEntries.add(entryKey(cand.collectionId, cand.actionId));
|
|
196
|
+
invalidatedTxns.add(cand.actionId);
|
|
197
|
+
progressed = true;
|
|
198
|
+
affectedCollections.add(cand.collectionId);
|
|
199
|
+
children.push({ collectionId: cand.collectionId, actionId: cand.actionId, rev: cand.rev, reverted: result.reverted });
|
|
200
|
+
for (const rb of result.reverted) {
|
|
201
|
+
pairs.set(pairKey(rb.blockId, cand.rev), {
|
|
202
|
+
blockId: rb.blockId, rev: cand.rev, restoredContentHash: rb.restoredContentHash,
|
|
203
|
+
collectionId: cand.collectionId, createBlockStorage: env.createBlockStorage,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (!progressed) {
|
|
208
|
+
break; // only retains / unevaluable / over-budget newcomers remain — fixpoint
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// Transaction-horizon escalation, built after the protected transactions have fully drained so the
|
|
212
|
+
// remainder reflects only what was genuinely left un-cascaded (never a half-reverted transaction).
|
|
213
|
+
if (horizonReached && !escalation) {
|
|
214
|
+
const remainder = await collectCandidates(input.envs, pairs, rootActionId, processedEntries);
|
|
215
|
+
escalation = makeEscalation('max-transactions', affectedCollections, remainder, unevaluable);
|
|
216
|
+
}
|
|
217
|
+
if (!escalation && unevaluable.length > 0) {
|
|
218
|
+
escalation = makeEscalation('unevaluable', affectedCollections, [], unevaluable);
|
|
219
|
+
}
|
|
220
|
+
if (escalation) {
|
|
221
|
+
log('escalate reason=%s collections=%d remainder=%d unevaluable=%d', escalation.reason, escalation.collections.length, escalation.remainder.length, escalation.unevaluable.length);
|
|
222
|
+
try {
|
|
223
|
+
input.onEscalation?.(escalation);
|
|
224
|
+
}
|
|
225
|
+
catch (err) {
|
|
226
|
+
log('escalation-sink-error error=%s', err.message);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
rootActionId: input.rootActionId,
|
|
231
|
+
invalidated: children,
|
|
232
|
+
retained,
|
|
233
|
+
rounds,
|
|
234
|
+
...(escalation ? { escalation } : {}),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
// ─── Walk / match helpers ───
|
|
238
|
+
/** Walk every in-scope collection log forward, collecting unprocessed actions that are read-dependents. */
|
|
239
|
+
async function collectCandidates(envs, pairs, rootActionId, processedEntries) {
|
|
240
|
+
const candidates = [];
|
|
241
|
+
for (const env of envs) {
|
|
242
|
+
for await (const entry of env.log.select()) {
|
|
243
|
+
const action = entry.action;
|
|
244
|
+
// Exclude the root (invalidated by the caller across all its collections) and any
|
|
245
|
+
// collection-entry already reverted this cascade — but a not-yet-reverted entry of the
|
|
246
|
+
// same transaction in a different collection is still a live candidate.
|
|
247
|
+
if (!action || action.actionId === rootActionId || processedEntries.has(entryKey(env.collectionId, action.actionId))) {
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
const reads = action.reads;
|
|
251
|
+
const isLegacy = reads === undefined;
|
|
252
|
+
const matched = matchReads(reads, pairs);
|
|
253
|
+
if (matched.length === 0 && !isLegacy) {
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
candidates.push({
|
|
257
|
+
env,
|
|
258
|
+
collectionId: env.collectionId,
|
|
259
|
+
actionId: action.actionId,
|
|
260
|
+
rev: entry.rev,
|
|
261
|
+
blockIds: action.blockIds,
|
|
262
|
+
reads,
|
|
263
|
+
matched,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
// Deterministic processing order: revision, then collection, then actionId.
|
|
268
|
+
candidates.sort((a, b) => a.rev - b.rev
|
|
269
|
+
|| (a.collectionId < b.collectionId ? -1 : a.collectionId > b.collectionId ? 1 : 0)
|
|
270
|
+
|| (a.actionId < b.actionId ? -1 : a.actionId > b.actionId ? 1 : 0));
|
|
271
|
+
return candidates;
|
|
272
|
+
}
|
|
273
|
+
/** The subset of `reads` that intersect the invalidated frontier; `[]` for a legacy (reads-less) entry. */
|
|
274
|
+
function matchReads(reads, pairs) {
|
|
275
|
+
if (!reads) {
|
|
276
|
+
return [];
|
|
277
|
+
}
|
|
278
|
+
const matched = [];
|
|
279
|
+
for (const r of reads) {
|
|
280
|
+
const pair = pairs.get(pairKey(r.blockId, r.revision));
|
|
281
|
+
if (pair) {
|
|
282
|
+
matched.push(pair);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return matched;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Cycle-freedom guard. A read observes a strictly earlier write, so within a single collection a
|
|
289
|
+
* dependent's revision must exceed the pair it depends on. A same-collection back-edge means the log
|
|
290
|
+
* is corrupt — throw rather than risk a non-terminating walk. Cross-collection pairs live in
|
|
291
|
+
* independent revision sequences and are not comparable, so they are skipped.
|
|
292
|
+
*/
|
|
293
|
+
function assertForwardOnly(cand, matched) {
|
|
294
|
+
for (const pair of matched) {
|
|
295
|
+
if (pair.collectionId === cand.collectionId && cand.rev <= pair.rev) {
|
|
296
|
+
throw new Error(`cascade: back-edge detected — action ${cand.actionId} at rev ${cand.rev} reads ${pair.blockId}@${pair.rev} in the same collection (dependency graph must be a forward DAG)`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
function standing(cand) {
|
|
301
|
+
return { collectionId: cand.collectionId, actionId: cand.actionId, rev: cand.rev };
|
|
302
|
+
}
|
|
303
|
+
function makeEscalation(reason, collections, remainder, unevaluable) {
|
|
304
|
+
const affected = new Set(collections);
|
|
305
|
+
for (const r of remainder) {
|
|
306
|
+
affected.add(r.collectionId);
|
|
307
|
+
}
|
|
308
|
+
return {
|
|
309
|
+
reason,
|
|
310
|
+
collections: [...affected],
|
|
311
|
+
remainder: remainder.map(standing),
|
|
312
|
+
unevaluable: [...unevaluable],
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
//# sourceMappingURL=cascade.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cascade.js","sourceRoot":"","sources":["../../../src/dispute/cascade.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PeerId, IPeerNetwork } from '@optimystic/db-core';
|
|
2
2
|
import { ProtocolClient } from '../protocol-client.js';
|
|
3
|
+
import { type RpcDeadlineOptions } from '../rpc-deadline.js';
|
|
3
4
|
import type { DisputeChallenge, DisputeResolution, ArbitrationVote } from './types.js';
|
|
4
5
|
/**
|
|
5
6
|
* Client for the dispute protocol. Sends challenges to arbitrators
|
|
@@ -12,6 +13,6 @@ export declare class DisputeClient extends ProtocolClient {
|
|
|
12
13
|
/** Send a challenge to an arbitrator and get their vote */
|
|
13
14
|
sendChallenge(challenge: DisputeChallenge, timeoutMs?: number): Promise<ArbitrationVote>;
|
|
14
15
|
/** Send a resolution to a peer (broadcast) */
|
|
15
|
-
sendResolution(resolution: DisputeResolution): Promise<void>;
|
|
16
|
+
sendResolution(resolution: DisputeResolution, options?: RpcDeadlineOptions): Promise<void>;
|
|
16
17
|
}
|
|
17
18
|
//# sourceMappingURL=client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/dispute/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,eAAe,EAAkB,MAAM,YAAY,CAAC;AAEvG;;;GAGG;AACH,qBAAa,aAAc,SAAQ,cAAc;IAChD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,CAAC,EAAE,MAAM;IAK9E,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,aAAa;IAIhG,2DAA2D;IACrD,aAAa,CAAC,SAAS,EAAE,gBAAgB,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/dispute/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAoD,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC/G,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,eAAe,EAAkB,MAAM,YAAY,CAAC;AAEvG;;;GAGG;AACH,qBAAa,aAAc,SAAQ,cAAc;IAChD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,CAAC,EAAE,MAAM;IAK9E,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,aAAa;IAIhG,2DAA2D;IACrD,aAAa,CAAC,SAAS,EAAE,gBAAgB,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAiB9F,8CAA8C;IACxC,cAAc,CAAC,UAAU,EAAE,iBAAiB,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;CAUhG"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ProtocolClient } from '../protocol-client.js';
|
|
2
|
+
import { DEFAULT_DIAL_TIMEOUT_MS, withRpcDeadlineDefaults } from '../rpc-deadline.js';
|
|
2
3
|
/**
|
|
3
4
|
* Client for the dispute protocol. Sends challenges to arbitrators
|
|
4
5
|
* and broadcasts resolutions.
|
|
@@ -15,14 +16,22 @@ export class DisputeClient extends ProtocolClient {
|
|
|
15
16
|
/** Send a challenge to an arbitrator and get their vote */
|
|
16
17
|
async sendChallenge(challenge, timeoutMs) {
|
|
17
18
|
const message = { type: 'challenge', challenge };
|
|
19
|
+
// Preserve the existing `timeoutMs`→`signal` contract callers rely on. Post the
|
|
20
|
+
// processMessage response-deadline work, this `signal` now tears down the
|
|
21
|
+
// *response read* (not merely the dial) — the desired "give up on a silent
|
|
22
|
+
// arbitrator" behavior. Also apply the default dial cap so a challenge to an
|
|
23
|
+
// unreachable arbitrator fails the dial fast even when no `timeoutMs` is given;
|
|
24
|
+
// this does not alter the response semantics (still bounded only by the signal).
|
|
18
25
|
const signal = timeoutMs ? AbortSignal.timeout(timeoutMs) : undefined;
|
|
19
|
-
const response = await this.processMessage(message, this.protocol, { signal });
|
|
26
|
+
const response = await this.processMessage(message, this.protocol, { signal, dialTimeoutMs: DEFAULT_DIAL_TIMEOUT_MS });
|
|
20
27
|
return response.vote;
|
|
21
28
|
}
|
|
22
29
|
/** Send a resolution to a peer (broadcast) */
|
|
23
|
-
async sendResolution(resolution) {
|
|
30
|
+
async sendResolution(resolution, options) {
|
|
24
31
|
const message = { type: 'resolution', resolution };
|
|
25
|
-
|
|
32
|
+
// This is a broadcast/ack, so the response cap is what matters: a peer that
|
|
33
|
+
// connects but never acks must not hang the broadcast. Absent keys default.
|
|
34
|
+
await this.processMessage(message, this.protocol, withRpcDeadlineDefaults(options));
|
|
26
35
|
}
|
|
27
36
|
}
|
|
28
37
|
//# sourceMappingURL=client.js.map
|