@optimystic/db-core 0.13.4 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/cluster/structs.d.ts +29 -0
- package/dist/src/cluster/structs.d.ts.map +1 -1
- package/dist/src/cohort-topic/addressing.d.ts +53 -0
- package/dist/src/cohort-topic/addressing.d.ts.map +1 -0
- package/dist/src/cohort-topic/addressing.js +95 -0
- package/dist/src/cohort-topic/addressing.js.map +1 -0
- package/dist/src/cohort-topic/antidos/bootstrap-evidence-envelope.d.ts +105 -0
- package/dist/src/cohort-topic/antidos/bootstrap-evidence-envelope.d.ts.map +1 -0
- package/dist/src/cohort-topic/antidos/bootstrap-evidence-envelope.js +197 -0
- package/dist/src/cohort-topic/antidos/bootstrap-evidence-envelope.js.map +1 -0
- package/dist/src/cohort-topic/antidos/bootstrap-evidence.d.ts +50 -0
- package/dist/src/cohort-topic/antidos/bootstrap-evidence.d.ts.map +1 -0
- package/dist/src/cohort-topic/antidos/bootstrap-evidence.js +62 -0
- package/dist/src/cohort-topic/antidos/bootstrap-evidence.js.map +1 -0
- package/dist/src/cohort-topic/antidos/index.d.ts +6 -0
- package/dist/src/cohort-topic/antidos/index.d.ts.map +1 -0
- package/dist/src/cohort-topic/antidos/index.js +6 -0
- package/dist/src/cohort-topic/antidos/index.js.map +1 -0
- package/dist/src/cohort-topic/antidos/rate-limiter.d.ts +95 -0
- package/dist/src/cohort-topic/antidos/rate-limiter.d.ts.map +1 -0
- package/dist/src/cohort-topic/antidos/rate-limiter.js +146 -0
- package/dist/src/cohort-topic/antidos/rate-limiter.js.map +1 -0
- package/dist/src/cohort-topic/antidos/replay-guard.d.ts +37 -0
- package/dist/src/cohort-topic/antidos/replay-guard.d.ts.map +1 -0
- package/dist/src/cohort-topic/antidos/replay-guard.js +78 -0
- package/dist/src/cohort-topic/antidos/replay-guard.js.map +1 -0
- package/dist/src/cohort-topic/antidos/topic-budget.d.ts +50 -0
- package/dist/src/cohort-topic/antidos/topic-budget.d.ts.map +1 -0
- package/dist/src/cohort-topic/antidos/topic-budget.js +95 -0
- package/dist/src/cohort-topic/antidos/topic-budget.js.map +1 -0
- package/dist/src/cohort-topic/antiflood/index.d.ts +3 -0
- package/dist/src/cohort-topic/antiflood/index.d.ts.map +1 -0
- package/dist/src/cohort-topic/antiflood/index.js +3 -0
- package/dist/src/cohort-topic/antiflood/index.js.map +1 -0
- package/dist/src/cohort-topic/antiflood/invariants.d.ts +70 -0
- package/dist/src/cohort-topic/antiflood/invariants.d.ts.map +1 -0
- package/dist/src/cohort-topic/antiflood/invariants.js +86 -0
- package/dist/src/cohort-topic/antiflood/invariants.js.map +1 -0
- package/dist/src/cohort-topic/antiflood/jitter.d.ts +65 -0
- package/dist/src/cohort-topic/antiflood/jitter.d.ts.map +1 -0
- package/dist/src/cohort-topic/antiflood/jitter.js +75 -0
- package/dist/src/cohort-topic/antiflood/jitter.js.map +1 -0
- package/dist/src/cohort-topic/coldstart.d.ts +117 -0
- package/dist/src/cohort-topic/coldstart.d.ts.map +1 -0
- package/dist/src/cohort-topic/coldstart.js +127 -0
- package/dist/src/cohort-topic/coldstart.js.map +1 -0
- package/dist/src/cohort-topic/dmax.d.ts +44 -0
- package/dist/src/cohort-topic/dmax.d.ts.map +1 -0
- package/dist/src/cohort-topic/dmax.js +70 -0
- package/dist/src/cohort-topic/dmax.js.map +1 -0
- package/dist/src/cohort-topic/gossip/bus.d.ts +85 -0
- package/dist/src/cohort-topic/gossip/bus.d.ts.map +1 -0
- package/dist/src/cohort-topic/gossip/bus.js +146 -0
- package/dist/src/cohort-topic/gossip/bus.js.map +1 -0
- package/dist/src/cohort-topic/gossip/index.d.ts +4 -0
- package/dist/src/cohort-topic/gossip/index.d.ts.map +1 -0
- package/dist/src/cohort-topic/gossip/index.js +4 -0
- package/dist/src/cohort-topic/gossip/index.js.map +1 -0
- package/dist/src/cohort-topic/gossip/records.d.ts +12 -0
- package/dist/src/cohort-topic/gossip/records.d.ts.map +1 -0
- package/dist/src/cohort-topic/gossip/records.js +41 -0
- package/dist/src/cohort-topic/gossip/records.js.map +1 -0
- package/dist/src/cohort-topic/gossip/view.d.ts +39 -0
- package/dist/src/cohort-topic/gossip/view.d.ts.map +1 -0
- package/dist/src/cohort-topic/gossip/view.js +30 -0
- package/dist/src/cohort-topic/gossip/view.js.map +1 -0
- package/dist/src/cohort-topic/index.d.ts +21 -0
- package/dist/src/cohort-topic/index.d.ts.map +1 -0
- package/dist/src/cohort-topic/index.js +21 -0
- package/dist/src/cohort-topic/index.js.map +1 -0
- package/dist/src/cohort-topic/load/barometer.d.ts +78 -0
- package/dist/src/cohort-topic/load/barometer.d.ts.map +1 -0
- package/dist/src/cohort-topic/load/barometer.js +93 -0
- package/dist/src/cohort-topic/load/barometer.js.map +1 -0
- package/dist/src/cohort-topic/load/index.d.ts +2 -0
- package/dist/src/cohort-topic/load/index.d.ts.map +1 -0
- package/dist/src/cohort-topic/load/index.js +2 -0
- package/dist/src/cohort-topic/load/index.js.map +1 -0
- package/dist/src/cohort-topic/member-engine.d.ts +134 -0
- package/dist/src/cohort-topic/member-engine.d.ts.map +1 -0
- package/dist/src/cohort-topic/member-engine.js +264 -0
- package/dist/src/cohort-topic/member-engine.js.map +1 -0
- package/dist/src/cohort-topic/membership/index.d.ts +4 -0
- package/dist/src/cohort-topic/membership/index.d.ts.map +1 -0
- package/dist/src/cohort-topic/membership/index.js +4 -0
- package/dist/src/cohort-topic/membership/index.js.map +1 -0
- package/dist/src/cohort-topic/membership/publisher.d.ts +82 -0
- package/dist/src/cohort-topic/membership/publisher.d.ts.map +1 -0
- package/dist/src/cohort-topic/membership/publisher.js +107 -0
- package/dist/src/cohort-topic/membership/publisher.js.map +1 -0
- package/dist/src/cohort-topic/membership/source.d.ts +31 -0
- package/dist/src/cohort-topic/membership/source.d.ts.map +1 -0
- package/dist/src/cohort-topic/membership/source.js +32 -0
- package/dist/src/cohort-topic/membership/source.js.map +1 -0
- package/dist/src/cohort-topic/membership/verifier.d.ts +96 -0
- package/dist/src/cohort-topic/membership/verifier.d.ts.map +1 -0
- package/dist/src/cohort-topic/membership/verifier.js +250 -0
- package/dist/src/cohort-topic/membership/verifier.js.map +1 -0
- package/dist/src/cohort-topic/ports.d.ts +149 -0
- package/dist/src/cohort-topic/ports.d.ts.map +1 -0
- package/dist/src/cohort-topic/ports.js +25 -0
- package/dist/src/cohort-topic/ports.js.map +1 -0
- package/dist/src/cohort-topic/promotion.d.ts +135 -0
- package/dist/src/cohort-topic/promotion.d.ts.map +1 -0
- package/dist/src/cohort-topic/promotion.js +269 -0
- package/dist/src/cohort-topic/promotion.js.map +1 -0
- package/dist/src/cohort-topic/registration/bytes.d.ts +16 -0
- package/dist/src/cohort-topic/registration/bytes.d.ts.map +1 -0
- package/dist/src/cohort-topic/registration/bytes.js +32 -0
- package/dist/src/cohort-topic/registration/bytes.js.map +1 -0
- package/dist/src/cohort-topic/registration/handoff.d.ts +69 -0
- package/dist/src/cohort-topic/registration/handoff.d.ts.map +1 -0
- package/dist/src/cohort-topic/registration/handoff.js +98 -0
- package/dist/src/cohort-topic/registration/handoff.js.map +1 -0
- package/dist/src/cohort-topic/registration/index.d.ts +7 -0
- package/dist/src/cohort-topic/registration/index.d.ts.map +1 -0
- package/dist/src/cohort-topic/registration/index.js +7 -0
- package/dist/src/cohort-topic/registration/index.js.map +1 -0
- package/dist/src/cohort-topic/registration/renewal.d.ts +115 -0
- package/dist/src/cohort-topic/registration/renewal.d.ts.map +1 -0
- package/dist/src/cohort-topic/registration/renewal.js +306 -0
- package/dist/src/cohort-topic/registration/renewal.js.map +1 -0
- package/dist/src/cohort-topic/registration/sharding.d.ts +31 -0
- package/dist/src/cohort-topic/registration/sharding.d.ts.map +1 -0
- package/dist/src/cohort-topic/registration/sharding.js +48 -0
- package/dist/src/cohort-topic/registration/sharding.js.map +1 -0
- package/dist/src/cohort-topic/registration/store.d.ts +13 -0
- package/dist/src/cohort-topic/registration/store.d.ts.map +1 -0
- package/dist/src/cohort-topic/registration/store.js +72 -0
- package/dist/src/cohort-topic/registration/store.js.map +1 -0
- package/dist/src/cohort-topic/registration/types.d.ts +71 -0
- package/dist/src/cohort-topic/registration/types.d.ts.map +1 -0
- package/dist/src/cohort-topic/registration/types.js +27 -0
- package/dist/src/cohort-topic/registration/types.js.map +1 -0
- package/dist/src/cohort-topic/ring-hash.d.ts +27 -0
- package/dist/src/cohort-topic/ring-hash.d.ts.map +1 -0
- package/dist/src/cohort-topic/ring-hash.js +45 -0
- package/dist/src/cohort-topic/ring-hash.js.map +1 -0
- package/dist/src/cohort-topic/service.d.ts +157 -0
- package/dist/src/cohort-topic/service.d.ts.map +1 -0
- package/dist/src/cohort-topic/service.js +237 -0
- package/dist/src/cohort-topic/service.js.map +1 -0
- package/dist/src/cohort-topic/sig/index.d.ts +3 -0
- package/dist/src/cohort-topic/sig/index.d.ts.map +1 -0
- package/dist/src/cohort-topic/sig/index.js +3 -0
- package/dist/src/cohort-topic/sig/index.js.map +1 -0
- package/dist/src/cohort-topic/sig/payloads.d.ts +25 -0
- package/dist/src/cohort-topic/sig/payloads.d.ts.map +1 -0
- package/dist/src/cohort-topic/sig/payloads.js +25 -0
- package/dist/src/cohort-topic/sig/payloads.js.map +1 -0
- package/dist/src/cohort-topic/sig/threshold.d.ts +33 -0
- package/dist/src/cohort-topic/sig/threshold.d.ts.map +1 -0
- package/dist/src/cohort-topic/sig/threshold.js +51 -0
- package/dist/src/cohort-topic/sig/threshold.js.map +1 -0
- package/dist/src/cohort-topic/tiers.d.ts +58 -0
- package/dist/src/cohort-topic/tiers.d.ts.map +1 -0
- package/dist/src/cohort-topic/tiers.js +49 -0
- package/dist/src/cohort-topic/tiers.js.map +1 -0
- package/dist/src/cohort-topic/traffic.d.ts +90 -0
- package/dist/src/cohort-topic/traffic.d.ts.map +1 -0
- package/dist/src/cohort-topic/traffic.js +146 -0
- package/dist/src/cohort-topic/traffic.js.map +1 -0
- package/dist/src/cohort-topic/walk.d.ts +123 -0
- package/dist/src/cohort-topic/walk.d.ts.map +1 -0
- package/dist/src/cohort-topic/walk.js +150 -0
- package/dist/src/cohort-topic/walk.js.map +1 -0
- package/dist/src/cohort-topic/willingness.d.ts +123 -0
- package/dist/src/cohort-topic/willingness.d.ts.map +1 -0
- package/dist/src/cohort-topic/willingness.js +143 -0
- package/dist/src/cohort-topic/willingness.js.map +1 -0
- package/dist/src/cohort-topic/wire/codec.d.ts +42 -0
- package/dist/src/cohort-topic/wire/codec.d.ts.map +1 -0
- package/dist/src/cohort-topic/wire/codec.js +163 -0
- package/dist/src/cohort-topic/wire/codec.js.map +1 -0
- package/dist/src/cohort-topic/wire/index.d.ts +6 -0
- package/dist/src/cohort-topic/wire/index.d.ts.map +1 -0
- package/dist/src/cohort-topic/wire/index.js +6 -0
- package/dist/src/cohort-topic/wire/index.js.map +1 -0
- package/dist/src/cohort-topic/wire/payloads.d.ts +38 -0
- package/dist/src/cohort-topic/wire/payloads.d.ts.map +1 -0
- package/dist/src/cohort-topic/wire/payloads.js +102 -0
- package/dist/src/cohort-topic/wire/payloads.js.map +1 -0
- package/dist/src/cohort-topic/wire/types.d.ts +304 -0
- package/dist/src/cohort-topic/wire/types.d.ts.map +1 -0
- package/dist/src/cohort-topic/wire/types.js +16 -0
- package/dist/src/cohort-topic/wire/types.js.map +1 -0
- package/dist/src/cohort-topic/wire/validate.d.ts +25 -0
- package/dist/src/cohort-topic/wire/validate.d.ts.map +1 -0
- package/dist/src/cohort-topic/wire/validate.js +427 -0
- package/dist/src/cohort-topic/wire/validate.js.map +1 -0
- package/dist/src/collection/collection.d.ts +58 -1
- package/dist/src/collection/collection.d.ts.map +1 -1
- package/dist/src/collection/collection.js +76 -0
- package/dist/src/collection/collection.js.map +1 -1
- package/dist/src/collections/tree/tree.d.ts +58 -2
- package/dist/src/collections/tree/tree.d.ts.map +1 -1
- package/dist/src/collections/tree/tree.js +59 -2
- package/dist/src/collections/tree/tree.js.map +1 -1
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/log/log.d.ts +42 -4
- package/dist/src/log/log.d.ts.map +1 -1
- package/dist/src/log/log.js +71 -3
- package/dist/src/log/log.js.map +1 -1
- package/dist/src/log/struct.d.ts +122 -2
- package/dist/src/log/struct.d.ts.map +1 -1
- package/dist/src/log/struct.js.map +1 -1
- package/dist/src/matchmaking/capability-filter.d.ts +24 -0
- package/dist/src/matchmaking/capability-filter.d.ts.map +1 -0
- package/dist/src/matchmaking/capability-filter.js +37 -0
- package/dist/src/matchmaking/capability-filter.js.map +1 -0
- package/dist/src/matchmaking/config.d.ts +77 -0
- package/dist/src/matchmaking/config.d.ts.map +1 -0
- package/dist/src/matchmaking/config.js +69 -0
- package/dist/src/matchmaking/config.js.map +1 -0
- package/dist/src/matchmaking/index.d.ts +21 -0
- package/dist/src/matchmaking/index.d.ts.map +1 -0
- package/dist/src/matchmaking/index.js +21 -0
- package/dist/src/matchmaking/index.js.map +1 -0
- package/dist/src/matchmaking/multi-cohort-seeker.d.ts +133 -0
- package/dist/src/matchmaking/multi-cohort-seeker.d.ts.map +1 -0
- package/dist/src/matchmaking/multi-cohort-seeker.js +142 -0
- package/dist/src/matchmaking/multi-cohort-seeker.js.map +1 -0
- package/dist/src/matchmaking/provider.d.ts +70 -0
- package/dist/src/matchmaking/provider.d.ts.map +1 -0
- package/dist/src/matchmaking/provider.js +93 -0
- package/dist/src/matchmaking/provider.js.map +1 -0
- package/dist/src/matchmaking/query-eval.d.ts +53 -0
- package/dist/src/matchmaking/query-eval.d.ts.map +1 -0
- package/dist/src/matchmaking/query-eval.js +69 -0
- package/dist/src/matchmaking/query-eval.js.map +1 -0
- package/dist/src/matchmaking/seeker-walk.d.ts +95 -0
- package/dist/src/matchmaking/seeker-walk.d.ts.map +1 -0
- package/dist/src/matchmaking/seeker-walk.js +75 -0
- package/dist/src/matchmaking/seeker-walk.js.map +1 -0
- package/dist/src/matchmaking/seeker.d.ts +51 -0
- package/dist/src/matchmaking/seeker.d.ts.map +1 -0
- package/dist/src/matchmaking/seeker.js +62 -0
- package/dist/src/matchmaking/seeker.js.map +1 -0
- package/dist/src/matchmaking/topic-anchor.d.ts +54 -0
- package/dist/src/matchmaking/topic-anchor.d.ts.map +1 -0
- package/dist/src/matchmaking/topic-anchor.js +67 -0
- package/dist/src/matchmaking/topic-anchor.js.map +1 -0
- package/dist/src/matchmaking/voting-quorum.d.ts +233 -0
- package/dist/src/matchmaking/voting-quorum.d.ts.map +1 -0
- package/dist/src/matchmaking/voting-quorum.js +238 -0
- package/dist/src/matchmaking/voting-quorum.js.map +1 -0
- package/dist/src/matchmaking/wire.d.ts +259 -0
- package/dist/src/matchmaking/wire.d.ts.map +1 -0
- package/dist/src/matchmaking/wire.js +484 -0
- package/dist/src/matchmaking/wire.js.map +1 -0
- package/dist/src/network/i-repo.d.ts +19 -0
- package/dist/src/network/i-repo.d.ts.map +1 -1
- package/dist/src/network/repo-protocol.d.ts +3 -1
- package/dist/src/network/repo-protocol.d.ts.map +1 -1
- package/dist/src/network/struct.d.ts +23 -1
- package/dist/src/network/struct.d.ts.map +1 -1
- package/dist/src/reactivity/backfill.d.ts +118 -0
- package/dist/src/reactivity/backfill.d.ts.map +1 -0
- package/dist/src/reactivity/backfill.js +137 -0
- package/dist/src/reactivity/backfill.js.map +1 -0
- package/dist/src/reactivity/backpressure.d.ts +99 -0
- package/dist/src/reactivity/backpressure.d.ts.map +1 -0
- package/dist/src/reactivity/backpressure.js +153 -0
- package/dist/src/reactivity/backpressure.js.map +1 -0
- package/dist/src/reactivity/checkpoint.d.ts +165 -0
- package/dist/src/reactivity/checkpoint.d.ts.map +1 -0
- package/dist/src/reactivity/checkpoint.js +232 -0
- package/dist/src/reactivity/checkpoint.js.map +1 -0
- package/dist/src/reactivity/config.d.ts +131 -0
- package/dist/src/reactivity/config.d.ts.map +1 -0
- package/dist/src/reactivity/config.js +135 -0
- package/dist/src/reactivity/config.js.map +1 -0
- package/dist/src/reactivity/dedupe.d.ts +51 -0
- package/dist/src/reactivity/dedupe.d.ts.map +1 -0
- package/dist/src/reactivity/dedupe.js +90 -0
- package/dist/src/reactivity/dedupe.js.map +1 -0
- package/dist/src/reactivity/forwarder.d.ts +50 -0
- package/dist/src/reactivity/forwarder.d.ts.map +1 -0
- package/dist/src/reactivity/forwarder.js +52 -0
- package/dist/src/reactivity/forwarder.js.map +1 -0
- package/dist/src/reactivity/index.d.ts +34 -0
- package/dist/src/reactivity/index.d.ts.map +1 -0
- package/dist/src/reactivity/index.js +34 -0
- package/dist/src/reactivity/index.js.map +1 -0
- package/dist/src/reactivity/notification.d.ts +72 -0
- package/dist/src/reactivity/notification.d.ts.map +1 -0
- package/dist/src/reactivity/notification.js +92 -0
- package/dist/src/reactivity/notification.js.map +1 -0
- package/dist/src/reactivity/policy.d.ts +59 -0
- package/dist/src/reactivity/policy.d.ts.map +1 -0
- package/dist/src/reactivity/policy.js +64 -0
- package/dist/src/reactivity/policy.js.map +1 -0
- package/dist/src/reactivity/push-state.d.ts +140 -0
- package/dist/src/reactivity/push-state.d.ts.map +1 -0
- package/dist/src/reactivity/push-state.js +270 -0
- package/dist/src/reactivity/push-state.js.map +1 -0
- package/dist/src/reactivity/recover.d.ts +75 -0
- package/dist/src/reactivity/recover.d.ts.map +1 -0
- package/dist/src/reactivity/recover.js +105 -0
- package/dist/src/reactivity/recover.js.map +1 -0
- package/dist/src/reactivity/replay-buffer.d.ts +57 -0
- package/dist/src/reactivity/replay-buffer.d.ts.map +1 -0
- package/dist/src/reactivity/replay-buffer.js +88 -0
- package/dist/src/reactivity/replay-buffer.js.map +1 -0
- package/dist/src/reactivity/resume.d.ts +214 -0
- package/dist/src/reactivity/resume.d.ts.map +1 -0
- package/dist/src/reactivity/resume.js +358 -0
- package/dist/src/reactivity/resume.js.map +1 -0
- package/dist/src/reactivity/rotation.d.ts +283 -0
- package/dist/src/reactivity/rotation.d.ts.map +1 -0
- package/dist/src/reactivity/rotation.js +265 -0
- package/dist/src/reactivity/rotation.js.map +1 -0
- package/dist/src/reactivity/subscriber.d.ts +66 -0
- package/dist/src/reactivity/subscriber.d.ts.map +1 -0
- package/dist/src/reactivity/subscriber.js +75 -0
- package/dist/src/reactivity/subscriber.js.map +1 -0
- package/dist/src/reactivity/subscription.d.ts +52 -0
- package/dist/src/reactivity/subscription.d.ts.map +1 -0
- package/dist/src/reactivity/subscription.js +28 -0
- package/dist/src/reactivity/subscription.js.map +1 -0
- package/dist/src/reactivity/topic-anchor.d.ts +46 -0
- package/dist/src/reactivity/topic-anchor.d.ts.map +1 -0
- package/dist/src/reactivity/topic-anchor.js +61 -0
- package/dist/src/reactivity/topic-anchor.js.map +1 -0
- package/dist/src/reactivity/verify.d.ts +41 -0
- package/dist/src/reactivity/verify.d.ts.map +1 -0
- package/dist/src/reactivity/verify.js +48 -0
- package/dist/src/reactivity/verify.js.map +1 -0
- package/dist/src/reactivity/wire-validate.d.ts +28 -0
- package/dist/src/reactivity/wire-validate.d.ts.map +1 -0
- package/dist/src/reactivity/wire-validate.js +79 -0
- package/dist/src/reactivity/wire-validate.js.map +1 -0
- package/dist/src/reactivity/wire.d.ts +102 -0
- package/dist/src/reactivity/wire.d.ts.map +1 -0
- package/dist/src/reactivity/wire.js +129 -0
- package/dist/src/reactivity/wire.js.map +1 -0
- package/dist/src/transaction/coordinator.d.ts +9 -5
- package/dist/src/transaction/coordinator.d.ts.map +1 -1
- package/dist/src/transaction/coordinator.js +48 -25
- package/dist/src/transaction/coordinator.js.map +1 -1
- package/dist/src/transactor/change-notifier.d.ts +74 -0
- package/dist/src/transactor/change-notifier.d.ts.map +1 -0
- package/dist/src/transactor/change-notifier.js +4 -0
- package/dist/src/transactor/change-notifier.js.map +1 -0
- package/dist/src/transactor/index.d.ts +1 -0
- package/dist/src/transactor/index.d.ts.map +1 -1
- package/dist/src/transactor/index.js +1 -0
- package/dist/src/transactor/index.js.map +1 -1
- package/dist/src/transactor/network-transactor.d.ts +44 -2
- package/dist/src/transactor/network-transactor.d.ts.map +1 -1
- package/dist/src/transactor/network-transactor.js +132 -17
- package/dist/src/transactor/network-transactor.js.map +1 -1
- package/package.json +3 -2
- package/src/cluster/structs.ts +86 -57
- package/src/cohort-topic/addressing.ts +112 -0
- package/src/cohort-topic/antidos/bootstrap-evidence-envelope.ts +253 -0
- package/src/cohort-topic/antidos/bootstrap-evidence.ts +94 -0
- package/src/cohort-topic/antidos/index.ts +5 -0
- package/src/cohort-topic/antidos/rate-limiter.ts +210 -0
- package/src/cohort-topic/antidos/replay-guard.ts +109 -0
- package/src/cohort-topic/antidos/topic-budget.ts +145 -0
- package/src/cohort-topic/antiflood/index.ts +2 -0
- package/src/cohort-topic/antiflood/invariants.ts +108 -0
- package/src/cohort-topic/antiflood/jitter.ts +117 -0
- package/src/cohort-topic/coldstart.ts +204 -0
- package/src/cohort-topic/dmax.ts +88 -0
- package/src/cohort-topic/gossip/bus.ts +217 -0
- package/src/cohort-topic/gossip/index.ts +3 -0
- package/src/cohort-topic/gossip/records.ts +45 -0
- package/src/cohort-topic/gossip/view.ts +66 -0
- package/src/cohort-topic/index.ts +20 -0
- package/src/cohort-topic/load/barometer.ts +134 -0
- package/src/cohort-topic/load/index.ts +1 -0
- package/src/cohort-topic/member-engine.ts +409 -0
- package/src/cohort-topic/membership/index.ts +3 -0
- package/src/cohort-topic/membership/publisher.ts +171 -0
- package/src/cohort-topic/membership/source.ts +41 -0
- package/src/cohort-topic/membership/verifier.ts +345 -0
- package/src/cohort-topic/ports.ts +157 -0
- package/src/cohort-topic/promotion.ts +384 -0
- package/src/cohort-topic/registration/bytes.ts +37 -0
- package/src/cohort-topic/registration/handoff.ts +154 -0
- package/src/cohort-topic/registration/index.ts +6 -0
- package/src/cohort-topic/registration/renewal.ts +423 -0
- package/src/cohort-topic/registration/sharding.ts +61 -0
- package/src/cohort-topic/registration/store.ts +81 -0
- package/src/cohort-topic/registration/types.ts +76 -0
- package/src/cohort-topic/ring-hash.ts +50 -0
- package/src/cohort-topic/service.ts +390 -0
- package/src/cohort-topic/sig/index.ts +2 -0
- package/src/cohort-topic/sig/payloads.ts +39 -0
- package/src/cohort-topic/sig/threshold.ts +64 -0
- package/src/cohort-topic/tiers.ts +74 -0
- package/src/cohort-topic/traffic.ts +211 -0
- package/src/cohort-topic/walk.ts +255 -0
- package/src/cohort-topic/willingness.ts +237 -0
- package/src/cohort-topic/wire/codec.ts +204 -0
- package/src/cohort-topic/wire/index.ts +16 -0
- package/src/cohort-topic/wire/payloads.ts +117 -0
- package/src/cohort-topic/wire/types.ts +343 -0
- package/src/cohort-topic/wire/validate.ts +478 -0
- package/src/collection/collection.ts +93 -1
- package/src/collections/tree/tree.ts +84 -3
- package/src/index.ts +3 -0
- package/src/log/log.ts +86 -7
- package/src/log/struct.ts +126 -2
- package/src/matchmaking/capability-filter.ts +45 -0
- package/src/matchmaking/config.ts +98 -0
- package/src/matchmaking/index.ts +21 -0
- package/src/matchmaking/multi-cohort-seeker.ts +234 -0
- package/src/matchmaking/provider.ts +123 -0
- package/src/matchmaking/query-eval.ts +105 -0
- package/src/matchmaking/seeker-walk.ts +127 -0
- package/src/matchmaking/seeker.ts +86 -0
- package/src/matchmaking/topic-anchor.ts +90 -0
- package/src/matchmaking/voting-quorum.ts +394 -0
- package/src/matchmaking/wire.ts +680 -0
- package/src/network/i-repo.ts +19 -0
- package/src/network/repo-protocol.ts +3 -2
- package/src/network/struct.ts +24 -1
- package/src/reactivity/backfill.ts +220 -0
- package/src/reactivity/backpressure.ts +191 -0
- package/src/reactivity/checkpoint.ts +308 -0
- package/src/reactivity/config.ts +172 -0
- package/src/reactivity/dedupe.ts +132 -0
- package/src/reactivity/forwarder.ts +87 -0
- package/src/reactivity/index.ts +34 -0
- package/src/reactivity/notification.ts +123 -0
- package/src/reactivity/policy.ts +79 -0
- package/src/reactivity/push-state.ts +343 -0
- package/src/reactivity/recover.ts +153 -0
- package/src/reactivity/replay-buffer.ts +141 -0
- package/src/reactivity/resume.ts +549 -0
- package/src/reactivity/rotation.ts +415 -0
- package/src/reactivity/subscriber.ts +132 -0
- package/src/reactivity/subscription.ts +66 -0
- package/src/reactivity/topic-anchor.ts +71 -0
- package/src/reactivity/verify.ts +73 -0
- package/src/reactivity/wire-validate.ts +87 -0
- package/src/reactivity/wire.ts +224 -0
- package/src/transaction/coordinator.ts +53 -27
- package/src/transactor/change-notifier.ts +80 -0
- package/src/transactor/index.ts +1 -0
- package/src/transactor/network-transactor.ts +162 -19
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { sha256 } from '@noble/hashes/sha2.js';
|
|
2
|
+
/**
|
|
3
|
+
* Default ring width in bits. 256 = the full SHA-256 digest, which lines up byte-for-byte with
|
|
4
|
+
* FRET's coordinate type (FRET hashes ring keys with SHA-256). Override only when targeting a
|
|
5
|
+
* DHT with a narrower ring.
|
|
6
|
+
*/
|
|
7
|
+
export const RING_BITS = 256;
|
|
8
|
+
/**
|
|
9
|
+
* db-core's {@link IRingHash}, backed by its own SHA-256 (the same digest db-core already uses
|
|
10
|
+
* for logs and block ids) — **not** an import of any FRET hash module. This keeps db-core
|
|
11
|
+
* FRET-free while guaranteeing on-the-wire coord compatibility: at the default `ringBits = 256`,
|
|
12
|
+
* `H(bytes)` is the full SHA-256 digest, identical to what FRET produces for the same input.
|
|
13
|
+
*
|
|
14
|
+
* For ring widths that are not a whole number of bytes, the digest is truncated to
|
|
15
|
+
* `ceil(ringBits / 8)` bytes and the trailing partial byte's unused low bits are zeroed, so two
|
|
16
|
+
* inputs whose digests share the first `ringBits` bits yield byte-identical coords.
|
|
17
|
+
*/
|
|
18
|
+
export class RingHash {
|
|
19
|
+
ringBits;
|
|
20
|
+
nBytes;
|
|
21
|
+
tailMask;
|
|
22
|
+
constructor(ringBits = RING_BITS) {
|
|
23
|
+
if (!Number.isInteger(ringBits) || ringBits <= 0 || ringBits > 256) {
|
|
24
|
+
throw new RangeError(`ringBits must be an integer in [1, 256], got ${ringBits}`);
|
|
25
|
+
}
|
|
26
|
+
this.ringBits = ringBits;
|
|
27
|
+
this.nBytes = Math.ceil(ringBits / 8);
|
|
28
|
+
const remBits = ringBits - (this.nBytes - 1) * 8;
|
|
29
|
+
this.tailMask = remBits === 8 ? 0xff : (0xff << (8 - remBits)) & 0xff;
|
|
30
|
+
}
|
|
31
|
+
H(bytes) {
|
|
32
|
+
const digest = sha256(bytes);
|
|
33
|
+
if (this.nBytes === digest.length && this.tailMask === 0xff) {
|
|
34
|
+
return digest;
|
|
35
|
+
}
|
|
36
|
+
const coord = digest.slice(0, this.nBytes);
|
|
37
|
+
coord[this.nBytes - 1] = coord[this.nBytes - 1] & this.tailMask;
|
|
38
|
+
return coord;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Convenience factory mirroring the db-p2p adapter construction style. */
|
|
42
|
+
export function createRingHash(ringBits = RING_BITS) {
|
|
43
|
+
return new RingHash(ringBits);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=ring-hash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ring-hash.js","sourceRoot":"","sources":["../../../src/cohort-topic/ring-hash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAG/C;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,CAAC;AAE7B;;;;;;;;;GASG;AACH,MAAM,OAAO,QAAQ;IACJ,QAAQ,CAAS;IAChB,MAAM,CAAS;IACf,QAAQ,CAAS;IAElC,YAAY,WAAmB,SAAS;QACvC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,QAAQ,IAAI,CAAC,IAAI,QAAQ,GAAG,GAAG,EAAE,CAAC;YACpE,MAAM,IAAI,UAAU,CAAC,gDAAgD,QAAQ,EAAE,CAAC,CAAC;QAClF,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;QACtC,MAAM,OAAO,GAAG,QAAQ,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QACjD,IAAI,CAAC,QAAQ,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IACvE,CAAC;IAED,CAAC,CAAC,KAAiB;QAClB,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7B,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;YAC7D,OAAO,MAAM,CAAC;QACf,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3C,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAE,GAAG,IAAI,CAAC,QAAQ,CAAC;QACjE,OAAO,KAAK,CAAC;IACd,CAAC;CACD;AAED,2EAA2E;AAC3E,MAAM,UAAU,cAAc,CAAC,WAAmB,SAAS;IAC1D,OAAO,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cohort-topic substrate — participant-facing service composition.
|
|
3
|
+
*
|
|
4
|
+
* This is the substrate's public contract to applications (`docs/cohort-topic.md` §Application
|
|
5
|
+
* policies): given a `topicId` and a `tier`, reliably find a willing primary (or fail with a clear
|
|
6
|
+
* back-off), keep a registration alive within its TTL, and verify cohort identity/membership. It is
|
|
7
|
+
* the participant half of the substrate; the cohort half is {@link import("./member-engine.js").CohortMemberEngine}.
|
|
8
|
+
*
|
|
9
|
+
* The service is FRET-free: it drives the {@link ITopicRouter} (walk / register / direct-dial) and the
|
|
10
|
+
* other db-core ports by injection. db-p2p binds those ports to FRET + libp2p and constructs the
|
|
11
|
+
* service on the same node it runs the member engine on, so a node is simultaneously a participant and
|
|
12
|
+
* a cohort member (`docs/cohort-topic.md` §FRET integration — all four protocols on one node).
|
|
13
|
+
*
|
|
14
|
+
* Composition wired here: {@link WalkEngine} (lookup / register), the `d_max` computer + tier
|
|
15
|
+
* addressing, the participant-side {@link RenewalParticipant} (the `ttl/3` ping with crash-failover),
|
|
16
|
+
* and the application integration hooks ({@link CohortGossipBus}, {@link MembershipVerifier}). The
|
|
17
|
+
* cohort-side modules (willingness, promotion, traffic, store, membership publisher, anti-DoS) are
|
|
18
|
+
* assembled by the member engine the FRET host wires into the `RouteAndMaybeAct` activity callback.
|
|
19
|
+
*/
|
|
20
|
+
import type { ISizeEstimator, ITopicRouter, IRingHash } from "./ports.js";
|
|
21
|
+
import { type RenewalParticipant, type UnsignedRenew } from "./registration/renewal.js";
|
|
22
|
+
import type { CohortGossipBus } from "./gossip/bus.js";
|
|
23
|
+
import type { MembershipVerifier } from "./membership/verifier.js";
|
|
24
|
+
import type { Tier } from "./tiers.js";
|
|
25
|
+
import type { RegisterV1, TopicTrafficV1 } from "./wire/types.js";
|
|
26
|
+
import type { CollectionChangeEvent, CommitCert } from "../transactor/change-notifier.js";
|
|
27
|
+
/** A resolved cohort for a topic/tier — the return of {@link CohortTopicService.lookup}. */
|
|
28
|
+
export interface CohortHint {
|
|
29
|
+
readonly topicId: Uint8Array;
|
|
30
|
+
readonly tier: Tier;
|
|
31
|
+
/** Serving cohort member. */
|
|
32
|
+
readonly primary: Uint8Array;
|
|
33
|
+
/** Warm-failover cohort members (1..2). */
|
|
34
|
+
readonly backups: Uint8Array[];
|
|
35
|
+
readonly cohortEpoch: Uint8Array;
|
|
36
|
+
/** Full cohort member set, for client-side caching. */
|
|
37
|
+
readonly cohortMembers: Uint8Array[];
|
|
38
|
+
/** Coarse traffic barometer, when the cohort attached one. */
|
|
39
|
+
readonly topicTraffic?: TopicTrafficV1;
|
|
40
|
+
}
|
|
41
|
+
/** A live registration: a {@link CohortHint} plus the participant-side renewal handle behind it. */
|
|
42
|
+
export interface RegistrationHandle extends CohortHint {
|
|
43
|
+
/** Internal renewal driver (the `ttl/3` ping loop). Opaque to applications. */
|
|
44
|
+
readonly renewal: RenewalParticipant;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The substrate's **origination hook**: a commit that lands on a node which is a cohort member for the
|
|
48
|
+
* collection's reactivity topic is delivered here by the local change-notifier bridge
|
|
49
|
+
* (`local-change-notifier-bridge`), carrying the raw {@link CollectionChangeEvent} and the
|
|
50
|
+
* pass-through {@link CommitCert} (extracted from cluster consensus, forwarded UNCHANGED). Reactivity
|
|
51
|
+
* (and later matchmaking) set this hook to fan the event out — reusing `commitCert.thresholdSig`
|
|
52
|
+
* directly, never re-signing. The bridge swallows + logs any throw so origination can never break the
|
|
53
|
+
* commit.
|
|
54
|
+
*/
|
|
55
|
+
export type LocalChangeHook = (event: CollectionChangeEvent, commitCert: CommitCert) => void;
|
|
56
|
+
/** Thrown when the substrate cannot place a registration right now; carries the back-off delay. */
|
|
57
|
+
export declare class CohortBackoffError extends Error {
|
|
58
|
+
readonly afterMs: number;
|
|
59
|
+
constructor(afterMs: number);
|
|
60
|
+
}
|
|
61
|
+
/** A registration request (`docs/cohort-topic.md` §Application policies). */
|
|
62
|
+
export interface RegisterRequest {
|
|
63
|
+
readonly topicId: Uint8Array;
|
|
64
|
+
readonly tier: Tier;
|
|
65
|
+
/** Opaque application slot (reactivity / matchmaking define the contents). */
|
|
66
|
+
readonly appPayload?: Uint8Array;
|
|
67
|
+
/** Registration TTL (ms); defaults to the tier default. */
|
|
68
|
+
readonly ttl?: number;
|
|
69
|
+
/** Mark this a cold-root bootstrap request. */
|
|
70
|
+
readonly bootstrap?: boolean;
|
|
71
|
+
}
|
|
72
|
+
/** The substrate's participant-facing contract. */
|
|
73
|
+
export interface CohortTopicService {
|
|
74
|
+
/** Walk → register for `topicId` at `tier`; resolves a live {@link RegistrationHandle} or throws {@link CohortBackoffError}. */
|
|
75
|
+
register(req: RegisterRequest): Promise<RegistrationHandle>;
|
|
76
|
+
/** Run one `ttl/3` renewal cycle for `handle` (handles `primary_moved` + crash-failover). */
|
|
77
|
+
renew(handle: RegistrationHandle): Promise<void>;
|
|
78
|
+
/** Resolve the cohort for `topicId` at `tier` without keeping a live registration. */
|
|
79
|
+
lookup(topicId: Uint8Array, tier: Tier): Promise<CohortHint>;
|
|
80
|
+
/** Stop renewing `handle` and send a best-effort signed withdraw tombstone so the cohort frees the
|
|
81
|
+
* record immediately (TTL expiry remains the fallback if the primary is unreachable). */
|
|
82
|
+
withdraw(handle: RegistrationHandle): Promise<void>;
|
|
83
|
+
/** Origination hook the change-notifier bridge invokes per local member commit; see {@link LocalChangeHook}. */
|
|
84
|
+
onLocalCommit?: LocalChangeHook;
|
|
85
|
+
/** Cohort gossip bus — applications fold app state into the existing gossip. */
|
|
86
|
+
cohortGossip(): CohortGossipBus;
|
|
87
|
+
/** Membership verifier — applications verify threshold-signed app messages. */
|
|
88
|
+
verifier(): MembershipVerifier;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Signs the participant's outbound `RegisterV1` / `RenewV1` bodies (db-p2p supplies the peer key).
|
|
92
|
+
*
|
|
93
|
+
* Async because the underlying libp2p `PrivateKey.sign` is async; both call sites already `await`
|
|
94
|
+
* (`messageFactory.build` and the renewal `sign` hook). The signature is over the canonical body
|
|
95
|
+
* image ({@link import("./wire/payloads.js").registerSigningPayload} /
|
|
96
|
+
* {@link import("./wire/payloads.js").renewSigningPayload}) so a cohort member can recompute and
|
|
97
|
+
* verify it against the participant's peer key.
|
|
98
|
+
*/
|
|
99
|
+
export interface ParticipantSigner {
|
|
100
|
+
/** Sign a `RegisterV1` (minus its signature); resolves the base64url signature. */
|
|
101
|
+
signRegister(body: Omit<RegisterV1, "signature">): Promise<string>;
|
|
102
|
+
/** Sign a `RenewV1` (minus its signature); resolves the base64url signature. */
|
|
103
|
+
signRenew(body: UnsignedRenew): Promise<string>;
|
|
104
|
+
}
|
|
105
|
+
/** Per-service tunables (cohort size, threshold, fan-out, TTL); all optional. */
|
|
106
|
+
export interface CohortServiceConfig {
|
|
107
|
+
/** Fan-out per tier `F`. Default {@link DEFAULT_FANOUT}. */
|
|
108
|
+
readonly fanout?: number;
|
|
109
|
+
/** Requested cohort size `wantK`. Default 16. */
|
|
110
|
+
readonly wantK?: number;
|
|
111
|
+
/** Threshold signers `minSigs = k − x`. Default 14. */
|
|
112
|
+
readonly minSigs?: number;
|
|
113
|
+
/** Default registration TTL (ms). Default {@link DEFAULT_TTL_MS}. */
|
|
114
|
+
readonly ttl?: number;
|
|
115
|
+
/** Frame ceiling for encode/decode. Defaults to the codec default. */
|
|
116
|
+
readonly maxMessageBytes?: number;
|
|
117
|
+
}
|
|
118
|
+
export interface CohortTopicServiceDeps {
|
|
119
|
+
/** This participant's peer id (the `P` in `coord_d(P, topicId)`). */
|
|
120
|
+
readonly self: Uint8Array;
|
|
121
|
+
/** Hash + ring math (db-core's own SHA-256). */
|
|
122
|
+
readonly hash: IRingHash;
|
|
123
|
+
/** FRET-backed router (walk / register / direct-dial). */
|
|
124
|
+
readonly router: ITopicRouter;
|
|
125
|
+
/** FRET-backed network-size estimator feeding `d_max`. */
|
|
126
|
+
readonly sizeEstimator: ISizeEstimator;
|
|
127
|
+
/** Participant body signer. */
|
|
128
|
+
readonly signer: ParticipantSigner;
|
|
129
|
+
/** Cohort gossip bus (the host constructs it for this node's cohort). */
|
|
130
|
+
readonly gossipBus: CohortGossipBus;
|
|
131
|
+
/** Participant-side membership verifier. */
|
|
132
|
+
readonly verifier: MembershipVerifier;
|
|
133
|
+
/** Monotonic-ish wall clock (unix ms); injectable for tests. Default `Date.now`. */
|
|
134
|
+
readonly clock?: () => number;
|
|
135
|
+
/**
|
|
136
|
+
* Optional cold-start bootstrap-evidence builder (db-p2p supplies it). Invoked **only** on the
|
|
137
|
+
* bootstrap re-issue (when the walk sets `bootstrap: true`), with the register's own canonical
|
|
138
|
+
* fields — the same `(topicId, tier, participantCoord, timestamp)` tuple a verifier binds via
|
|
139
|
+
* `bootstrapBoundImage`. It returns the **raw** envelope JSON bytes — `utf8(JSON.stringify(env))`,
|
|
140
|
+
* NOT the already-base64url string from `serializeBootstrapEvidenceEnvelope` — or `undefined` to
|
|
141
|
+
* attach none; the service base64url-encodes those bytes into `RegisterV1.bootstrapEvidence`
|
|
142
|
+
* **before** the body is signed, so the participant signature covers them and a MITM cannot strip or
|
|
143
|
+
* swap the proof. (Returning the `serialize()` string's bytes would double-encode the field.)
|
|
144
|
+
* Absent (default) → no evidence is attached, exactly today's behavior. The minting logic (PoW
|
|
145
|
+
* search, reputation/parent-ref signing) is the db-p2p follow-on.
|
|
146
|
+
*/
|
|
147
|
+
readonly buildBootstrapEvidence?: (params: {
|
|
148
|
+
readonly topicId: string;
|
|
149
|
+
readonly tier: number;
|
|
150
|
+
readonly participantCoord: string;
|
|
151
|
+
readonly timestamp: number;
|
|
152
|
+
}) => Promise<Uint8Array | undefined>;
|
|
153
|
+
readonly config?: CohortServiceConfig;
|
|
154
|
+
}
|
|
155
|
+
/** Build the participant-facing {@link CohortTopicService} over the injected ports. */
|
|
156
|
+
export declare function createCohortTopicService(deps: CohortTopicServiceDeps): CohortTopicService;
|
|
157
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/cohort-topic/service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,SAAS,EAAa,MAAM,YAAY,CAAC;AAErF,OAAO,EAA4B,KAAK,kBAAkB,EAAoC,KAAK,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAIpJ,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,KAAK,EAAmB,UAAU,EAAgB,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjG,OAAO,KAAK,EAAE,qBAAqB,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAE1F,4FAA4F;AAC5F,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,6BAA6B;IAC7B,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,2CAA2C;IAC3C,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,UAAU,CAAC;IACjC,uDAAuD;IACvD,QAAQ,CAAC,aAAa,EAAE,UAAU,EAAE,CAAC;IACrC,8DAA8D;IAC9D,QAAQ,CAAC,YAAY,CAAC,EAAE,cAAc,CAAC;CACvC;AAED,oGAAoG;AACpG,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACrD,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;CACrC;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,qBAAqB,EAAE,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;AAE7F,mGAAmG;AACnG,qBAAa,kBAAmB,SAAQ,KAAK;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM;gBAAf,OAAO,EAAE,MAAM;CAIpC;AAED,6EAA6E;AAC7E,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;IACjC,2DAA2D;IAC3D,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,+CAA+C;IAC/C,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,mDAAmD;AACnD,MAAM,WAAW,kBAAkB;IAClC,gIAAgI;IAChI,QAAQ,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC5D,6FAA6F;IAC7F,KAAK,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,sFAAsF;IACtF,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC7D;6FACyF;IACzF,QAAQ,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,gHAAgH;IAChH,aAAa,CAAC,EAAE,eAAe,CAAC;IAChC,gFAAgF;IAChF,YAAY,IAAI,eAAe,CAAC;IAChC,+EAA+E;IAC/E,QAAQ,IAAI,kBAAkB,CAAC;CAC/B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IACjC,mFAAmF;IACnF,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACnE,gFAAgF;IAChF,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAChD;AAED,iFAAiF;AACjF,MAAM,WAAW,mBAAmB;IACnC,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,iDAAiD;IACjD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,uDAAuD;IACvD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,qEAAqE;IACrE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,sEAAsE;IACtE,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,sBAAsB;IACtC,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,gDAAgD;IAChD,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,0DAA0D;IAC1D,QAAQ,CAAC,aAAa,EAAE,cAAc,CAAC;IACvC,+BAA+B;IAC/B,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,yEAAyE;IACzE,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,4CAA4C;IAC5C,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IACtC,oFAAoF;IACpF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;IAC9B;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,sBAAsB,CAAC,EAAE,CAAC,MAAM,EAAE;QAC1C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;QAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;KAC3B,KAAK,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,mBAAmB,CAAC;CACtC;AAoND,uFAAuF;AACvF,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,sBAAsB,GAAG,kBAAkB,CAEzF"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cohort-topic substrate — participant-facing service composition.
|
|
3
|
+
*
|
|
4
|
+
* This is the substrate's public contract to applications (`docs/cohort-topic.md` §Application
|
|
5
|
+
* policies): given a `topicId` and a `tier`, reliably find a willing primary (or fail with a clear
|
|
6
|
+
* back-off), keep a registration alive within its TTL, and verify cohort identity/membership. It is
|
|
7
|
+
* the participant half of the substrate; the cohort half is {@link import("./member-engine.js").CohortMemberEngine}.
|
|
8
|
+
*
|
|
9
|
+
* The service is FRET-free: it drives the {@link ITopicRouter} (walk / register / direct-dial) and the
|
|
10
|
+
* other db-core ports by injection. db-p2p binds those ports to FRET + libp2p and constructs the
|
|
11
|
+
* service on the same node it runs the member engine on, so a node is simultaneously a participant and
|
|
12
|
+
* a cohort member (`docs/cohort-topic.md` §FRET integration — all four protocols on one node).
|
|
13
|
+
*
|
|
14
|
+
* Composition wired here: {@link WalkEngine} (lookup / register), the `d_max` computer + tier
|
|
15
|
+
* addressing, the participant-side {@link RenewalParticipant} (the `ttl/3` ping with crash-failover),
|
|
16
|
+
* and the application integration hooks ({@link CohortGossipBus}, {@link MembershipVerifier}). The
|
|
17
|
+
* cohort-side modules (willingness, promotion, traffic, store, membership publisher, anti-DoS) are
|
|
18
|
+
* assembled by the member engine the FRET host wires into the `RouteAndMaybeAct` activity callback.
|
|
19
|
+
*/
|
|
20
|
+
import { randomBytes } from "@noble/hashes/utils.js";
|
|
21
|
+
import { createTierAddressing } from "./addressing.js";
|
|
22
|
+
import { makeDMaxComputer } from "./dmax.js";
|
|
23
|
+
import { DEFAULT_FANOUT } from "./addressing.js";
|
|
24
|
+
import { createWalkEngine } from "./walk.js";
|
|
25
|
+
import { createRenewalParticipant } from "./registration/renewal.js";
|
|
26
|
+
import { DEFAULT_TTL_MS } from "./registration/types.js";
|
|
27
|
+
import { recordKey } from "./registration/bytes.js";
|
|
28
|
+
import { bytesToB64url, b64urlToBytes, decodeRenewReplyV1, encodeCohortMessage } from "./wire/codec.js";
|
|
29
|
+
/** Thrown when the substrate cannot place a registration right now; carries the back-off delay. */
|
|
30
|
+
export class CohortBackoffError extends Error {
|
|
31
|
+
afterMs;
|
|
32
|
+
constructor(afterMs) {
|
|
33
|
+
super(`cohort-topic: no willing primary right now; retry after ${afterMs}ms`);
|
|
34
|
+
this.afterMs = afterMs;
|
|
35
|
+
this.name = "CohortBackoffError";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
class WalkRegisterService {
|
|
39
|
+
deps;
|
|
40
|
+
onLocalCommit;
|
|
41
|
+
addressing;
|
|
42
|
+
dmax;
|
|
43
|
+
walk;
|
|
44
|
+
clock;
|
|
45
|
+
ttl;
|
|
46
|
+
maxMessageBytes;
|
|
47
|
+
/** Live renewal drivers, keyed by `(topicId, participantId)` so renew/withdraw find their handle. */
|
|
48
|
+
renewals = new Map();
|
|
49
|
+
participantId;
|
|
50
|
+
constructor(deps) {
|
|
51
|
+
this.deps = deps;
|
|
52
|
+
const cfg = deps.config ?? {};
|
|
53
|
+
const fanout = cfg.fanout ?? DEFAULT_FANOUT;
|
|
54
|
+
this.clock = deps.clock ?? (() => Date.now());
|
|
55
|
+
this.ttl = cfg.ttl ?? DEFAULT_TTL_MS;
|
|
56
|
+
this.maxMessageBytes = cfg.maxMessageBytes;
|
|
57
|
+
// The participant identity carried on the wire (`participantCoord` on register, `participantId`
|
|
58
|
+
// on renew) IS `self` — the dialable peer id db-p2p supplies via its peer-codec. It is the
|
|
59
|
+
// record key the cohort stores AND the signer id its peer-key signature verifies against, so it
|
|
60
|
+
// must round-trip back to a peer id rather than being re-hashed here (§Tier addressing names the
|
|
61
|
+
// routing coord `P = self` directly; slot assignment hashes it internally for uniformity).
|
|
62
|
+
this.participantId = deps.self;
|
|
63
|
+
this.addressing = createTierAddressing(deps.hash, fanout);
|
|
64
|
+
this.dmax = makeDMaxComputer({ estimator: deps.sizeEstimator, F: fanout });
|
|
65
|
+
this.walk = createWalkEngine({
|
|
66
|
+
router: deps.router,
|
|
67
|
+
addressing: this.addressing,
|
|
68
|
+
dmax: this.dmax,
|
|
69
|
+
self: deps.self,
|
|
70
|
+
factory: this.messageFactory(),
|
|
71
|
+
config: { wantK: cfg.wantK, minSigs: cfg.minSigs, maxMessageBytes: cfg.maxMessageBytes },
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
async register(req) {
|
|
75
|
+
const outcome = await this.walk.register(req.topicId, req.tier, req.appPayload);
|
|
76
|
+
return this.handleFromOutcome(req, outcome);
|
|
77
|
+
}
|
|
78
|
+
async lookup(topicId, tier) {
|
|
79
|
+
// A read-only probe: it walks to the responsible cohort exactly as a register would and returns the
|
|
80
|
+
// same cohort snapshot, but admits NOTHING — no soft-state record, no arrival, no promotion trigger,
|
|
81
|
+
// no topic-budget touch, and never a cold-start instantiation. A topic served nowhere resolves to a
|
|
82
|
+
// `CohortBackoffError` (the probe never bootstraps a cold root), so a lookup leaves no throwaway
|
|
83
|
+
// registration behind to TTL-expire (§Application policies; the lookup-as-register interim is gone).
|
|
84
|
+
const outcome = await this.walk.register(topicId, tier, undefined, { probe: true });
|
|
85
|
+
if (outcome.kind !== "accepted") {
|
|
86
|
+
throw new CohortBackoffError(outcome.kind === "retry_later" ? outcome.afterMs : 0);
|
|
87
|
+
}
|
|
88
|
+
return this.hintFromReply(topicId, tier, outcome.reply);
|
|
89
|
+
}
|
|
90
|
+
async renew(handle) {
|
|
91
|
+
// Withdrawn handles drop out of the live set; renewing one is a no-op so withdraw() actually
|
|
92
|
+
// stops the local ping loop (rather than the app silently continuing to refresh it).
|
|
93
|
+
if (!this.renewals.has(recordKey(handle.topicId, this.participantId))) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
await handle.renewal.pingLoop();
|
|
97
|
+
this.syncHandle(handle);
|
|
98
|
+
}
|
|
99
|
+
async withdraw(handle) {
|
|
100
|
+
// Two halves: (1) drop the handle from the live set so further renew() pings no-op (see renew()),
|
|
101
|
+
// stopping the local ping loop; (2) fire a best-effort signed withdraw tombstone to the current
|
|
102
|
+
// primary so the cohort frees the record immediately instead of holding it for up to a full TTL.
|
|
103
|
+
// The delete happens FIRST so a concurrent renew() already no-ops before the tombstone is sent. If
|
|
104
|
+
// the tombstone send fails (primary unreachable), the cohort soft-state TTL-expires as the
|
|
105
|
+
// fallback — withdraw never throws on a transport failure. Idempotent: a second withdraw finds
|
|
106
|
+
// `renewal === undefined` and no-ops.
|
|
107
|
+
const key = recordKey(handle.topicId, this.participantId);
|
|
108
|
+
const renewal = this.renewals.get(key);
|
|
109
|
+
this.renewals.delete(key);
|
|
110
|
+
await renewal?.withdraw();
|
|
111
|
+
}
|
|
112
|
+
cohortGossip() {
|
|
113
|
+
return this.deps.gossipBus;
|
|
114
|
+
}
|
|
115
|
+
verifier() {
|
|
116
|
+
return this.deps.verifier;
|
|
117
|
+
}
|
|
118
|
+
// --- internals ---
|
|
119
|
+
handleFromOutcome(req, outcome) {
|
|
120
|
+
if (outcome.kind !== "accepted") {
|
|
121
|
+
throw new CohortBackoffError(outcome.kind === "retry_later" ? outcome.afterMs : 0);
|
|
122
|
+
}
|
|
123
|
+
const hint = this.hintFromReply(req.topicId, req.tier, outcome.reply);
|
|
124
|
+
const renewal = this.startRenewal(req, hint, outcome.reply);
|
|
125
|
+
return { ...hint, renewal };
|
|
126
|
+
}
|
|
127
|
+
startRenewal(req, hint, reply) {
|
|
128
|
+
const ttl = req.ttl ?? this.ttl;
|
|
129
|
+
const initial = {
|
|
130
|
+
topicId: req.topicId,
|
|
131
|
+
participantId: this.participantId,
|
|
132
|
+
tier: req.tier,
|
|
133
|
+
primary: hint.primary,
|
|
134
|
+
backups: hint.backups,
|
|
135
|
+
attachedAt: this.clock(),
|
|
136
|
+
lastPing: this.clock(),
|
|
137
|
+
ttl,
|
|
138
|
+
appState: req.appPayload,
|
|
139
|
+
};
|
|
140
|
+
const transport = this.renewalTransport(req);
|
|
141
|
+
const renewal = createRenewalParticipant(initial, {
|
|
142
|
+
transport,
|
|
143
|
+
clock: this.clock,
|
|
144
|
+
sign: (body) => this.deps.signer.signRenew(body),
|
|
145
|
+
correlationId: reply.cohortEpoch ?? bytesToB64url(this.participantId),
|
|
146
|
+
initialCohortEpoch: hint.cohortEpoch,
|
|
147
|
+
});
|
|
148
|
+
this.renewals.set(recordKey(req.topicId, this.participantId), renewal);
|
|
149
|
+
return renewal;
|
|
150
|
+
}
|
|
151
|
+
/** Renewal transport: dial the cached primary directly; a full failure re-runs the register walk. */
|
|
152
|
+
renewalTransport(req) {
|
|
153
|
+
return {
|
|
154
|
+
send: async (target, msg) => {
|
|
155
|
+
const raw = await this.deps.router.dialMember({ id: target }, encodeCohortMessage(msg, this.maxMessageBytes));
|
|
156
|
+
return decodeRenewReplyV1(raw, this.maxMessageBytes);
|
|
157
|
+
},
|
|
158
|
+
relookup: async () => {
|
|
159
|
+
await this.walk.register(req.topicId, req.tier, req.appPayload);
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
hintFromReply(topicId, tier, reply) {
|
|
164
|
+
if (reply.primary === undefined || reply.cohortEpoch === undefined) {
|
|
165
|
+
throw new CohortBackoffError(0);
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
topicId,
|
|
169
|
+
tier,
|
|
170
|
+
primary: b64urlToBytes(reply.primary),
|
|
171
|
+
backups: (reply.backups ?? []).map(b64urlToBytes),
|
|
172
|
+
cohortEpoch: b64urlToBytes(reply.cohortEpoch),
|
|
173
|
+
cohortMembers: (reply.cohortMembers ?? []).map(b64urlToBytes),
|
|
174
|
+
topicTraffic: reply.topicTraffic,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
syncHandle(handle) {
|
|
178
|
+
const rec = handle.renewal.record;
|
|
179
|
+
handle.primary = rec.primary;
|
|
180
|
+
handle.backups = [...rec.backups];
|
|
181
|
+
const epoch = handle.renewal.cohortEpochHint;
|
|
182
|
+
if (epoch !== undefined) {
|
|
183
|
+
handle.cohortEpoch = epoch;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/** The per-probe `RegisterV1` builder: stamps participant coord/ttl/correlation and signs. */
|
|
187
|
+
messageFactory() {
|
|
188
|
+
const participantCoord = bytesToB64url(this.participantId);
|
|
189
|
+
return {
|
|
190
|
+
build: async (params) => {
|
|
191
|
+
const body = {
|
|
192
|
+
v: 1,
|
|
193
|
+
topicId: bytesToB64url(params.topicId),
|
|
194
|
+
tier: params.tier,
|
|
195
|
+
treeTier: params.treeTier,
|
|
196
|
+
participantCoord,
|
|
197
|
+
ttl: this.ttl,
|
|
198
|
+
timestamp: this.clock(),
|
|
199
|
+
correlationId: this.freshCorrelationId(),
|
|
200
|
+
};
|
|
201
|
+
if (params.probe) {
|
|
202
|
+
// A read-only lookup probe. Mutually exclusive with bootstrap (the walk never sets
|
|
203
|
+
// `bootstrap` on a probe), so the cold-start-evidence branch below cannot run for a probe.
|
|
204
|
+
body.probe = true;
|
|
205
|
+
}
|
|
206
|
+
if (params.bootstrap) {
|
|
207
|
+
body.bootstrap = true;
|
|
208
|
+
// Attach cold-start evidence BEFORE signing (so the signature covers it). Bind the
|
|
209
|
+
// builder to the body's own canonical fields — the exact tuple a verifier reconstructs.
|
|
210
|
+
const evidence = await this.deps.buildBootstrapEvidence?.({
|
|
211
|
+
topicId: body.topicId,
|
|
212
|
+
tier: body.tier,
|
|
213
|
+
participantCoord: body.participantCoord,
|
|
214
|
+
timestamp: body.timestamp,
|
|
215
|
+
});
|
|
216
|
+
if (evidence !== undefined && evidence.length > 0) {
|
|
217
|
+
body.bootstrapEvidence = bytesToB64url(evidence);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (params.appPayload !== undefined) {
|
|
221
|
+
body.appPayload = bytesToB64url(params.appPayload);
|
|
222
|
+
}
|
|
223
|
+
return { ...body, signature: await this.deps.signer.signRegister(body) };
|
|
224
|
+
},
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
/** 16 fresh CSPRNG bytes, base64url. A correlation id must be unique per probe — the replay guard
|
|
228
|
+
* keys on it — so it cannot be derived from the clock (two probes in the same ms would collide). */
|
|
229
|
+
freshCorrelationId() {
|
|
230
|
+
return bytesToB64url(randomBytes(16));
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/** Build the participant-facing {@link CohortTopicService} over the injected ports. */
|
|
234
|
+
export function createCohortTopicService(deps) {
|
|
235
|
+
return new WalkRegisterService(deps);
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/cohort-topic/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/cohort-topic/sig/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/cohort-topic/sig/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cohort-topic substrate — canonical threshold-signature payloads.
|
|
3
|
+
*
|
|
4
|
+
* A threshold signature is only verifiable if signer and verifier agree on the exact bytes signed.
|
|
5
|
+
* These builders produce that deterministic byte image for each threshold-signed message
|
|
6
|
+
* (`MembershipCertV1`, `PromotionNoticeV1`, `DemotionNoticeV1`), covering exactly the semantic
|
|
7
|
+
* fields per `docs/cohort-topic.md` §Wire formats — never the `thresholdSig`/`signers` envelope.
|
|
8
|
+
*
|
|
9
|
+
* Determinism comes from encoding an explicitly-ordered JSON array (array order is stable, unlike
|
|
10
|
+
* object key order) as UTF-8. The publisher signs this image; the verifier recomputes and checks it.
|
|
11
|
+
*/
|
|
12
|
+
import type { DemotionNoticeV1, MembershipCertV1, PromotionNoticeV1 } from "../wire/types.js";
|
|
13
|
+
/** Fields of a `MembershipCertV1` covered by its threshold signature (doc: cohortCoord, cohortEpoch, members, stabilizedAt). */
|
|
14
|
+
export type MembershipCertSignable = Pick<MembershipCertV1, "cohortCoord" | "cohortEpoch" | "members" | "stabilizedAt">;
|
|
15
|
+
/** Canonical signed byte image of a membership certificate. */
|
|
16
|
+
export declare function membershipCertSigningPayload(cert: MembershipCertSignable): Uint8Array;
|
|
17
|
+
/** Fields of a `PromotionNoticeV1` covered by its threshold signature. */
|
|
18
|
+
export type PromotionSignable = Pick<PromotionNoticeV1, "topicId" | "fromTier" | "toTier" | "effectiveAt" | "cohortEpoch">;
|
|
19
|
+
/** Canonical signed byte image of a promotion notice. */
|
|
20
|
+
export declare function promotionNoticeSigningPayload(n: PromotionSignable): Uint8Array;
|
|
21
|
+
/** Fields of a `DemotionNoticeV1` covered by its threshold signature. */
|
|
22
|
+
export type DemotionSignable = Pick<DemotionNoticeV1, "topicId" | "tier" | "parentCohortCoord" | "effectiveAt" | "cohortEpoch">;
|
|
23
|
+
/** Canonical signed byte image of a demotion notice. */
|
|
24
|
+
export declare function demotionNoticeSigningPayload(n: DemotionSignable): Uint8Array;
|
|
25
|
+
//# sourceMappingURL=payloads.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payloads.d.ts","sourceRoot":"","sources":["../../../../src/cohort-topic/sig/payloads.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAI9F,gIAAgI;AAChI,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,gBAAgB,EAAE,aAAa,GAAG,aAAa,GAAG,SAAS,GAAG,cAAc,CAAC,CAAC;AAExH,+DAA+D;AAC/D,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,sBAAsB,GAAG,UAAU,CAErF;AAED,0EAA0E;AAC1E,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,EAAE,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;AAE3H,yDAAyD;AACzD,wBAAgB,6BAA6B,CAAC,CAAC,EAAE,iBAAiB,GAAG,UAAU,CAE9E;AAED,yEAAyE;AACzE,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,EAAE,SAAS,GAAG,MAAM,GAAG,mBAAmB,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;AAEhI,wDAAwD;AACxD,wBAAgB,4BAA4B,CAAC,CAAC,EAAE,gBAAgB,GAAG,UAAU,CAE5E"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cohort-topic substrate — canonical threshold-signature payloads.
|
|
3
|
+
*
|
|
4
|
+
* A threshold signature is only verifiable if signer and verifier agree on the exact bytes signed.
|
|
5
|
+
* These builders produce that deterministic byte image for each threshold-signed message
|
|
6
|
+
* (`MembershipCertV1`, `PromotionNoticeV1`, `DemotionNoticeV1`), covering exactly the semantic
|
|
7
|
+
* fields per `docs/cohort-topic.md` §Wire formats — never the `thresholdSig`/`signers` envelope.
|
|
8
|
+
*
|
|
9
|
+
* Determinism comes from encoding an explicitly-ordered JSON array (array order is stable, unlike
|
|
10
|
+
* object key order) as UTF-8. The publisher signs this image; the verifier recomputes and checks it.
|
|
11
|
+
*/
|
|
12
|
+
const utf8 = new TextEncoder();
|
|
13
|
+
/** Canonical signed byte image of a membership certificate. */
|
|
14
|
+
export function membershipCertSigningPayload(cert) {
|
|
15
|
+
return utf8.encode(JSON.stringify(["MembershipCertV1", cert.cohortCoord, cert.cohortEpoch, cert.members, cert.stabilizedAt]));
|
|
16
|
+
}
|
|
17
|
+
/** Canonical signed byte image of a promotion notice. */
|
|
18
|
+
export function promotionNoticeSigningPayload(n) {
|
|
19
|
+
return utf8.encode(JSON.stringify(["PromotionNoticeV1", n.topicId, n.fromTier, n.toTier, n.effectiveAt, n.cohortEpoch]));
|
|
20
|
+
}
|
|
21
|
+
/** Canonical signed byte image of a demotion notice. */
|
|
22
|
+
export function demotionNoticeSigningPayload(n) {
|
|
23
|
+
return utf8.encode(JSON.stringify(["DemotionNoticeV1", n.topicId, n.tier, n.parentCohortCoord, n.effectiveAt, n.cohortEpoch]));
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=payloads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payloads.js","sourceRoot":"","sources":["../../../../src/cohort-topic/sig/payloads.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC;AAK/B,+DAA+D;AAC/D,MAAM,UAAU,4BAA4B,CAAC,IAA4B;IACxE,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,kBAAkB,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AAC/H,CAAC;AAKD,yDAAyD;AACzD,MAAM,UAAU,6BAA6B,CAAC,CAAoB;IACjE,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,mBAAmB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC1H,CAAC;AAKD,wDAAwD;AACxD,MAAM,UAAU,4BAA4B,CAAC,CAAmB;IAC/D,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,kBAAkB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAChI,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cohort-topic substrate — `k − x` threshold signing and verification.
|
|
3
|
+
*
|
|
4
|
+
* Per `docs/cohort-topic.md` §FRET integration (L659) and §Membership snapshots: the cohort
|
|
5
|
+
* threshold-signs `PromotionNoticeV1` / `DemotionNoticeV1` / `MembershipCertV1` with `minSigs`
|
|
6
|
+
* (= `k − x`, default 14) signers. This module is db-core logic over the {@link ICohortThresholdCrypto}
|
|
7
|
+
* port; db-p2p binds the port to FRET's `minSigs` cohort-signature assembly — db-core never imports
|
|
8
|
+
* FRET, and the underlying scheme is reused unchanged.
|
|
9
|
+
*
|
|
10
|
+
* {@link CohortSigner.verifyThreshold} layers the membership check db-core owns on top of the raw
|
|
11
|
+
* crypto: the `signers` must be a distinct `≥ minSigs` subset of the certificate's `members`, *and*
|
|
12
|
+
* the signature must verify against the payload. Either failure → not verified.
|
|
13
|
+
*/
|
|
14
|
+
import type { ICohortThresholdCrypto } from "../ports.js";
|
|
15
|
+
import type { MembershipCertV1 } from "../wire/types.js";
|
|
16
|
+
/** Default cohort-signature threshold, `k − x` (see §Configuration). */
|
|
17
|
+
export declare const DEFAULT_MIN_SIGS = 14;
|
|
18
|
+
/** Threshold signer/verifier over the injected cohort crypto. Peer ids are raw bytes. */
|
|
19
|
+
export interface CohortSigner {
|
|
20
|
+
/** Assemble a cohort threshold signature over `payload` (collects `minSigs` signers). */
|
|
21
|
+
thresholdSign(payload: Uint8Array): Promise<{
|
|
22
|
+
thresholdSig: Uint8Array;
|
|
23
|
+
signers: Uint8Array[];
|
|
24
|
+
}>;
|
|
25
|
+
/**
|
|
26
|
+
* Verify a threshold-signed message: `signers` are a distinct `≥ minSigs` subset of
|
|
27
|
+
* `cert.members` and `sig` is a valid cohort signature over `payload`.
|
|
28
|
+
*/
|
|
29
|
+
verifyThreshold(payload: Uint8Array, sig: Uint8Array, signers: readonly Uint8Array[], cert: MembershipCertV1, minSigs: number): boolean;
|
|
30
|
+
}
|
|
31
|
+
/** Build a {@link CohortSigner} over the FRET-backed (in db-p2p) threshold crypto. */
|
|
32
|
+
export declare function createCohortSigner(crypto: ICohortThresholdCrypto, minSigs?: number): CohortSigner;
|
|
33
|
+
//# sourceMappingURL=threshold.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"threshold.d.ts","sourceRoot":"","sources":["../../../../src/cohort-topic/sig/threshold.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,wEAAwE;AACxE,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC,yFAAyF;AACzF,MAAM,WAAW,YAAY;IAC5B,yFAAyF;IACzF,aAAa,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC;QAAE,YAAY,EAAE,UAAU,CAAC;QAAC,OAAO,EAAE,UAAU,EAAE,CAAA;KAAE,CAAC,CAAC;IACjG;;;OAGG;IACH,eAAe,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,UAAU,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACxI;AA8BD,sFAAsF;AACtF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,sBAAsB,EAAE,OAAO,GAAE,MAAyB,GAAG,YAAY,CAEnH"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cohort-topic substrate — `k − x` threshold signing and verification.
|
|
3
|
+
*
|
|
4
|
+
* Per `docs/cohort-topic.md` §FRET integration (L659) and §Membership snapshots: the cohort
|
|
5
|
+
* threshold-signs `PromotionNoticeV1` / `DemotionNoticeV1` / `MembershipCertV1` with `minSigs`
|
|
6
|
+
* (= `k − x`, default 14) signers. This module is db-core logic over the {@link ICohortThresholdCrypto}
|
|
7
|
+
* port; db-p2p binds the port to FRET's `minSigs` cohort-signature assembly — db-core never imports
|
|
8
|
+
* FRET, and the underlying scheme is reused unchanged.
|
|
9
|
+
*
|
|
10
|
+
* {@link CohortSigner.verifyThreshold} layers the membership check db-core owns on top of the raw
|
|
11
|
+
* crypto: the `signers` must be a distinct `≥ minSigs` subset of the certificate's `members`, *and*
|
|
12
|
+
* the signature must verify against the payload. Either failure → not verified.
|
|
13
|
+
*/
|
|
14
|
+
import { bytesToB64url } from "../wire/codec.js";
|
|
15
|
+
/** Default cohort-signature threshold, `k − x` (see §Configuration). */
|
|
16
|
+
export const DEFAULT_MIN_SIGS = 14;
|
|
17
|
+
class CryptoCohortSigner {
|
|
18
|
+
crypto;
|
|
19
|
+
minSigs;
|
|
20
|
+
constructor(crypto, minSigs) {
|
|
21
|
+
this.crypto = crypto;
|
|
22
|
+
this.minSigs = minSigs;
|
|
23
|
+
}
|
|
24
|
+
thresholdSign(payload) {
|
|
25
|
+
return this.crypto.assemble(payload, this.minSigs);
|
|
26
|
+
}
|
|
27
|
+
verifyThreshold(payload, sig, signers, cert, minSigs) {
|
|
28
|
+
if (signers.length < minSigs) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
// Members are base64url on the wire; compare signers in that same canonical form.
|
|
32
|
+
const memberSet = new Set(cert.members);
|
|
33
|
+
const seen = new Set();
|
|
34
|
+
for (const signer of signers) {
|
|
35
|
+
const key = bytesToB64url(signer);
|
|
36
|
+
if (seen.has(key)) {
|
|
37
|
+
return false; // a duplicated signer cannot pad the count toward minSigs
|
|
38
|
+
}
|
|
39
|
+
seen.add(key);
|
|
40
|
+
if (!memberSet.has(key)) {
|
|
41
|
+
return false; // signer is not a member of the attested cohort
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return this.crypto.verify(payload, sig, signers);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** Build a {@link CohortSigner} over the FRET-backed (in db-p2p) threshold crypto. */
|
|
48
|
+
export function createCohortSigner(crypto, minSigs = DEFAULT_MIN_SIGS) {
|
|
49
|
+
return new CryptoCohortSigner(crypto, minSigs);
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=threshold.js.map
|