@optimystic/db-p2p 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.
Files changed (352) hide show
  1. package/README.md +6 -6
  2. package/dist/src/cluster/block-transfer-service.d.ts +67 -8
  3. package/dist/src/cluster/block-transfer-service.d.ts.map +1 -1
  4. package/dist/src/cluster/block-transfer-service.js +101 -62
  5. package/dist/src/cluster/block-transfer-service.js.map +1 -1
  6. package/dist/src/cluster/client.d.ts +18 -1
  7. package/dist/src/cluster/client.d.ts.map +1 -1
  8. package/dist/src/cluster/client.js +55 -39
  9. package/dist/src/cluster/client.js.map +1 -1
  10. package/dist/src/cluster/cluster-error.d.ts +38 -0
  11. package/dist/src/cluster/cluster-error.d.ts.map +1 -0
  12. package/dist/src/cluster/cluster-error.js +51 -0
  13. package/dist/src/cluster/cluster-error.js.map +1 -0
  14. package/dist/src/cluster/cluster-repo.d.ts +135 -3
  15. package/dist/src/cluster/cluster-repo.d.ts.map +1 -1
  16. package/dist/src/cluster/cluster-repo.js +333 -58
  17. package/dist/src/cluster/cluster-repo.js.map +1 -1
  18. package/dist/src/cluster/commit-cert.d.ts +63 -0
  19. package/dist/src/cluster/commit-cert.d.ts.map +1 -0
  20. package/dist/src/cluster/commit-cert.js +108 -0
  21. package/dist/src/cluster/commit-cert.js.map +1 -0
  22. package/dist/src/cluster/service.d.ts +46 -11
  23. package/dist/src/cluster/service.d.ts.map +1 -1
  24. package/dist/src/cluster/service.js +97 -33
  25. package/dist/src/cluster/service.js.map +1 -1
  26. package/dist/src/cluster/spread-on-churn.d.ts +13 -0
  27. package/dist/src/cluster/spread-on-churn.d.ts.map +1 -1
  28. package/dist/src/cluster/spread-on-churn.js +34 -4
  29. package/dist/src/cluster/spread-on-churn.js.map +1 -1
  30. package/dist/src/cohort-topic/bootstrap-evidence-builder.d.ts +59 -0
  31. package/dist/src/cohort-topic/bootstrap-evidence-builder.d.ts.map +1 -0
  32. package/dist/src/cohort-topic/bootstrap-evidence-builder.js +79 -0
  33. package/dist/src/cohort-topic/bootstrap-evidence-builder.js.map +1 -0
  34. package/dist/src/cohort-topic/bootstrap-evidence-verifiers.d.ts +81 -0
  35. package/dist/src/cohort-topic/bootstrap-evidence-verifiers.d.ts.map +1 -0
  36. package/dist/src/cohort-topic/bootstrap-evidence-verifiers.js +93 -0
  37. package/dist/src/cohort-topic/bootstrap-evidence-verifiers.js.map +1 -0
  38. package/dist/src/cohort-topic/bootstrap-parent-reference.d.ts +108 -0
  39. package/dist/src/cohort-topic/bootstrap-parent-reference.d.ts.map +1 -0
  40. package/dist/src/cohort-topic/bootstrap-parent-reference.js +108 -0
  41. package/dist/src/cohort-topic/bootstrap-parent-reference.js.map +1 -0
  42. package/dist/src/cohort-topic/change-bridge.d.ts +65 -0
  43. package/dist/src/cohort-topic/change-bridge.d.ts.map +1 -0
  44. package/dist/src/cohort-topic/change-bridge.js +76 -0
  45. package/dist/src/cohort-topic/change-bridge.js.map +1 -0
  46. package/dist/src/cohort-topic/cohort-gossip-driver.d.ts +74 -0
  47. package/dist/src/cohort-topic/cohort-gossip-driver.d.ts.map +1 -0
  48. package/dist/src/cohort-topic/cohort-gossip-driver.js +87 -0
  49. package/dist/src/cohort-topic/cohort-gossip-driver.js.map +1 -0
  50. package/dist/src/cohort-topic/cohort-gossip-transport.d.ts +42 -0
  51. package/dist/src/cohort-topic/cohort-gossip-transport.d.ts.map +1 -0
  52. package/dist/src/cohort-topic/cohort-gossip-transport.js +57 -0
  53. package/dist/src/cohort-topic/cohort-gossip-transport.js.map +1 -0
  54. package/dist/src/cohort-topic/fret-trust-anchor.d.ts +100 -0
  55. package/dist/src/cohort-topic/fret-trust-anchor.d.ts.map +1 -0
  56. package/dist/src/cohort-topic/fret-trust-anchor.js +115 -0
  57. package/dist/src/cohort-topic/fret-trust-anchor.js.map +1 -0
  58. package/dist/src/cohort-topic/host.d.ts +573 -0
  59. package/dist/src/cohort-topic/host.d.ts.map +1 -0
  60. package/dist/src/cohort-topic/host.js +1460 -0
  61. package/dist/src/cohort-topic/host.js.map +1 -0
  62. package/dist/src/cohort-topic/index.d.ts +14 -0
  63. package/dist/src/cohort-topic/index.d.ts.map +1 -0
  64. package/dist/src/cohort-topic/index.js +14 -0
  65. package/dist/src/cohort-topic/index.js.map +1 -0
  66. package/dist/src/cohort-topic/membership-publish-sink.d.ts +14 -0
  67. package/dist/src/cohort-topic/membership-publish-sink.d.ts.map +1 -0
  68. package/dist/src/cohort-topic/membership-publish-sink.js +17 -0
  69. package/dist/src/cohort-topic/membership-publish-sink.js.map +1 -0
  70. package/dist/src/cohort-topic/membership-source.d.ts +36 -0
  71. package/dist/src/cohort-topic/membership-source.d.ts.map +1 -0
  72. package/dist/src/cohort-topic/membership-source.js +58 -0
  73. package/dist/src/cohort-topic/membership-source.js.map +1 -0
  74. package/dist/src/cohort-topic/peer-codec.d.ts +18 -0
  75. package/dist/src/cohort-topic/peer-codec.d.ts.map +1 -0
  76. package/dist/src/cohort-topic/peer-codec.js +26 -0
  77. package/dist/src/cohort-topic/peer-codec.js.map +1 -0
  78. package/dist/src/cohort-topic/peer-sig.d.ts +52 -0
  79. package/dist/src/cohort-topic/peer-sig.d.ts.map +1 -0
  80. package/dist/src/cohort-topic/peer-sig.js +83 -0
  81. package/dist/src/cohort-topic/peer-sig.js.map +1 -0
  82. package/dist/src/cohort-topic/protocols.d.ts +49 -0
  83. package/dist/src/cohort-topic/protocols.d.ts.map +1 -0
  84. package/dist/src/cohort-topic/protocols.js +58 -0
  85. package/dist/src/cohort-topic/protocols.js.map +1 -0
  86. package/dist/src/cohort-topic/reactivity-membership-gate.d.ts +49 -0
  87. package/dist/src/cohort-topic/reactivity-membership-gate.d.ts.map +1 -0
  88. package/dist/src/cohort-topic/reactivity-membership-gate.js +42 -0
  89. package/dist/src/cohort-topic/reactivity-membership-gate.js.map +1 -0
  90. package/dist/src/cohort-topic/size-estimator.d.ts +16 -0
  91. package/dist/src/cohort-topic/size-estimator.d.ts.map +1 -0
  92. package/dist/src/cohort-topic/size-estimator.js +16 -0
  93. package/dist/src/cohort-topic/size-estimator.js.map +1 -0
  94. package/dist/src/cohort-topic/stream-util.d.ts +19 -0
  95. package/dist/src/cohort-topic/stream-util.d.ts.map +1 -0
  96. package/dist/src/cohort-topic/stream-util.js +76 -0
  97. package/dist/src/cohort-topic/stream-util.js.map +1 -0
  98. package/dist/src/cohort-topic/threshold-crypto.d.ts +94 -0
  99. package/dist/src/cohort-topic/threshold-crypto.d.ts.map +1 -0
  100. package/dist/src/cohort-topic/threshold-crypto.js +178 -0
  101. package/dist/src/cohort-topic/threshold-crypto.js.map +1 -0
  102. package/dist/src/cohort-topic/topic-router.d.ts +41 -0
  103. package/dist/src/cohort-topic/topic-router.d.ts.map +1 -0
  104. package/dist/src/cohort-topic/topic-router.js +63 -0
  105. package/dist/src/cohort-topic/topic-router.js.map +1 -0
  106. package/dist/src/dispute/cascade.d.ts +179 -0
  107. package/dist/src/dispute/cascade.d.ts.map +1 -0
  108. package/dist/src/dispute/cascade.js +315 -0
  109. package/dist/src/dispute/cascade.js.map +1 -0
  110. package/dist/src/dispute/client.d.ts +2 -1
  111. package/dist/src/dispute/client.d.ts.map +1 -1
  112. package/dist/src/dispute/client.js +12 -3
  113. package/dist/src/dispute/client.js.map +1 -1
  114. package/dist/src/dispute/dispute-service.d.ts +41 -1
  115. package/dist/src/dispute/dispute-service.d.ts.map +1 -1
  116. package/dist/src/dispute/dispute-service.js +147 -21
  117. package/dist/src/dispute/dispute-service.js.map +1 -1
  118. package/dist/src/dispute/index.d.ts +2 -0
  119. package/dist/src/dispute/index.d.ts.map +1 -1
  120. package/dist/src/dispute/index.js +2 -0
  121. package/dist/src/dispute/index.js.map +1 -1
  122. package/dist/src/dispute/invalidation.d.ts +266 -0
  123. package/dist/src/dispute/invalidation.d.ts.map +1 -0
  124. package/dist/src/dispute/invalidation.js +405 -0
  125. package/dist/src/dispute/invalidation.js.map +1 -0
  126. package/dist/src/dispute/types.d.ts +14 -0
  127. package/dist/src/dispute/types.d.ts.map +1 -1
  128. package/dist/src/dispute/types.js.map +1 -1
  129. package/dist/src/index.d.ts +4 -0
  130. package/dist/src/index.d.ts.map +1 -1
  131. package/dist/src/index.js +4 -0
  132. package/dist/src/index.js.map +1 -1
  133. package/dist/src/libp2p-key-network.d.ts +8 -1
  134. package/dist/src/libp2p-key-network.d.ts.map +1 -1
  135. package/dist/src/libp2p-key-network.js +67 -8
  136. package/dist/src/libp2p-key-network.js.map +1 -1
  137. package/dist/src/libp2p-node-base.d.ts +57 -3
  138. package/dist/src/libp2p-node-base.d.ts.map +1 -1
  139. package/dist/src/libp2p-node-base.js +523 -6
  140. package/dist/src/libp2p-node-base.js.map +1 -1
  141. package/dist/src/matchmaking/aggregate-counts.d.ts +67 -0
  142. package/dist/src/matchmaking/aggregate-counts.d.ts.map +1 -0
  143. package/dist/src/matchmaking/aggregate-counts.js +60 -0
  144. package/dist/src/matchmaking/aggregate-counts.js.map +1 -0
  145. package/dist/src/matchmaking/index.d.ts +20 -0
  146. package/dist/src/matchmaking/index.d.ts.map +1 -0
  147. package/dist/src/matchmaking/index.js +20 -0
  148. package/dist/src/matchmaking/index.js.map +1 -0
  149. package/dist/src/matchmaking/module.d.ts +181 -0
  150. package/dist/src/matchmaking/module.d.ts.map +1 -0
  151. package/dist/src/matchmaking/module.js +221 -0
  152. package/dist/src/matchmaking/module.js.map +1 -0
  153. package/dist/src/matchmaking/protocols.d.ts +37 -0
  154. package/dist/src/matchmaking/protocols.d.ts.map +1 -0
  155. package/dist/src/matchmaking/protocols.js +42 -0
  156. package/dist/src/matchmaking/protocols.js.map +1 -0
  157. package/dist/src/matchmaking/provider-manager.d.ts +52 -0
  158. package/dist/src/matchmaking/provider-manager.d.ts.map +1 -0
  159. package/dist/src/matchmaking/provider-manager.js +74 -0
  160. package/dist/src/matchmaking/provider-manager.js.map +1 -0
  161. package/dist/src/matchmaking/query-handler.d.ts +34 -0
  162. package/dist/src/matchmaking/query-handler.d.ts.map +1 -0
  163. package/dist/src/matchmaking/query-handler.js +62 -0
  164. package/dist/src/matchmaking/query-handler.js.map +1 -0
  165. package/dist/src/matchmaking/query-transport.d.ts +180 -0
  166. package/dist/src/matchmaking/query-transport.d.ts.map +1 -0
  167. package/dist/src/matchmaking/query-transport.js +315 -0
  168. package/dist/src/matchmaking/query-transport.js.map +1 -0
  169. package/dist/src/matchmaking/seeker-manager.d.ts +39 -0
  170. package/dist/src/matchmaking/seeker-manager.d.ts.map +1 -0
  171. package/dist/src/matchmaking/seeker-manager.js +49 -0
  172. package/dist/src/matchmaking/seeker-manager.js.map +1 -0
  173. package/dist/src/matchmaking/seeker-walk-client.d.ts +127 -0
  174. package/dist/src/matchmaking/seeker-walk-client.d.ts.map +1 -0
  175. package/dist/src/matchmaking/seeker-walk-client.js +189 -0
  176. package/dist/src/matchmaking/seeker-walk-client.js.map +1 -0
  177. package/dist/src/matchmaking/traffic-validation.d.ts +128 -0
  178. package/dist/src/matchmaking/traffic-validation.d.ts.map +1 -0
  179. package/dist/src/matchmaking/traffic-validation.js +105 -0
  180. package/dist/src/matchmaking/traffic-validation.js.map +1 -0
  181. package/dist/src/network/network-manager-service.d.ts +4 -2
  182. package/dist/src/network/network-manager-service.d.ts.map +1 -1
  183. package/dist/src/network/network-manager-service.js +9 -3
  184. package/dist/src/network/network-manager-service.js.map +1 -1
  185. package/dist/src/protocol-client.d.ts +25 -0
  186. package/dist/src/protocol-client.d.ts.map +1 -1
  187. package/dist/src/protocol-client.js +126 -4
  188. package/dist/src/protocol-client.js.map +1 -1
  189. package/dist/src/reactivity/forwarder-host.d.ts +198 -0
  190. package/dist/src/reactivity/forwarder-host.d.ts.map +1 -0
  191. package/dist/src/reactivity/forwarder-host.js +355 -0
  192. package/dist/src/reactivity/forwarder-host.js.map +1 -0
  193. package/dist/src/reactivity/index.d.ts +19 -0
  194. package/dist/src/reactivity/index.d.ts.map +1 -0
  195. package/dist/src/reactivity/index.js +19 -0
  196. package/dist/src/reactivity/index.js.map +1 -0
  197. package/dist/src/reactivity/notify-transport.d.ts +70 -0
  198. package/dist/src/reactivity/notify-transport.d.ts.map +1 -0
  199. package/dist/src/reactivity/notify-transport.js +111 -0
  200. package/dist/src/reactivity/notify-transport.js.map +1 -0
  201. package/dist/src/reactivity/origination-manager.d.ts +110 -0
  202. package/dist/src/reactivity/origination-manager.d.ts.map +1 -0
  203. package/dist/src/reactivity/origination-manager.js +129 -0
  204. package/dist/src/reactivity/origination-manager.js.map +1 -0
  205. package/dist/src/reactivity/protocols.d.ts +43 -0
  206. package/dist/src/reactivity/protocols.d.ts.map +1 -0
  207. package/dist/src/reactivity/protocols.js +50 -0
  208. package/dist/src/reactivity/protocols.js.map +1 -0
  209. package/dist/src/reactivity/push-state-gossip.d.ts +132 -0
  210. package/dist/src/reactivity/push-state-gossip.d.ts.map +1 -0
  211. package/dist/src/reactivity/push-state-gossip.js +231 -0
  212. package/dist/src/reactivity/push-state-gossip.js.map +1 -0
  213. package/dist/src/reactivity/recover-transport.d.ts +167 -0
  214. package/dist/src/reactivity/recover-transport.d.ts.map +1 -0
  215. package/dist/src/reactivity/recover-transport.js +308 -0
  216. package/dist/src/reactivity/recover-transport.js.map +1 -0
  217. package/dist/src/reactivity/rotation-rereg-scheduler.d.ts +142 -0
  218. package/dist/src/reactivity/rotation-rereg-scheduler.d.ts.map +1 -0
  219. package/dist/src/reactivity/rotation-rereg-scheduler.js +223 -0
  220. package/dist/src/reactivity/rotation-rereg-scheduler.js.map +1 -0
  221. package/dist/src/reactivity/subscriber-registry.d.ts +47 -0
  222. package/dist/src/reactivity/subscriber-registry.d.ts.map +1 -0
  223. package/dist/src/reactivity/subscriber-registry.js +87 -0
  224. package/dist/src/reactivity/subscriber-registry.js.map +1 -0
  225. package/dist/src/reactivity/subscription-manager.d.ts +221 -0
  226. package/dist/src/reactivity/subscription-manager.d.ts.map +1 -0
  227. package/dist/src/reactivity/subscription-manager.js +302 -0
  228. package/dist/src/reactivity/subscription-manager.js.map +1 -0
  229. package/dist/src/reactivity/topic-bytes.d.ts +32 -0
  230. package/dist/src/reactivity/topic-bytes.d.ts.map +1 -0
  231. package/dist/src/reactivity/topic-bytes.js +34 -0
  232. package/dist/src/reactivity/topic-bytes.js.map +1 -0
  233. package/dist/src/repo/client.d.ts.map +1 -1
  234. package/dist/src/repo/client.js +51 -19
  235. package/dist/src/repo/client.js.map +1 -1
  236. package/dist/src/repo/cluster-coordinator.d.ts +9 -0
  237. package/dist/src/repo/cluster-coordinator.d.ts.map +1 -1
  238. package/dist/src/repo/cluster-coordinator.js +65 -22
  239. package/dist/src/repo/cluster-coordinator.js.map +1 -1
  240. package/dist/src/repo/coordinator-repo.d.ts +20 -0
  241. package/dist/src/repo/coordinator-repo.d.ts.map +1 -1
  242. package/dist/src/repo/coordinator-repo.js +101 -16
  243. package/dist/src/repo/coordinator-repo.js.map +1 -1
  244. package/dist/src/repo/service.d.ts +46 -1
  245. package/dist/src/repo/service.d.ts.map +1 -1
  246. package/dist/src/repo/service.js +79 -45
  247. package/dist/src/repo/service.js.map +1 -1
  248. package/dist/src/rpc-deadline.d.ts +37 -0
  249. package/dist/src/rpc-deadline.d.ts.map +1 -0
  250. package/dist/src/rpc-deadline.js +31 -0
  251. package/dist/src/rpc-deadline.js.map +1 -0
  252. package/dist/src/storage/block-storage.d.ts +2 -0
  253. package/dist/src/storage/block-storage.d.ts.map +1 -1
  254. package/dist/src/storage/block-storage.js +95 -2
  255. package/dist/src/storage/block-storage.js.map +1 -1
  256. package/dist/src/storage/i-block-storage.d.ts +25 -0
  257. package/dist/src/storage/i-block-storage.d.ts.map +1 -1
  258. package/dist/src/storage/storage-repo.d.ts +53 -2
  259. package/dist/src/storage/storage-repo.d.ts.map +1 -1
  260. package/dist/src/storage/storage-repo.js +193 -9
  261. package/dist/src/storage/storage-repo.js.map +1 -1
  262. package/dist/src/sync/client.d.ts +4 -1
  263. package/dist/src/sync/client.d.ts.map +1 -1
  264. package/dist/src/sync/client.js +5 -2
  265. package/dist/src/sync/client.js.map +1 -1
  266. package/dist/src/testing/cohort-topic-mesh-harness.d.ts +219 -0
  267. package/dist/src/testing/cohort-topic-mesh-harness.d.ts.map +1 -0
  268. package/dist/src/testing/cohort-topic-mesh-harness.js +467 -0
  269. package/dist/src/testing/cohort-topic-mesh-harness.js.map +1 -0
  270. package/dist/src/testing/matchmaking-mesh-harness.d.ts +187 -0
  271. package/dist/src/testing/matchmaking-mesh-harness.d.ts.map +1 -0
  272. package/dist/src/testing/matchmaking-mesh-harness.js +358 -0
  273. package/dist/src/testing/matchmaking-mesh-harness.js.map +1 -0
  274. package/dist/src/testing/mesh-harness.d.ts.map +1 -1
  275. package/dist/src/testing/mesh-harness.js +23 -1
  276. package/dist/src/testing/mesh-harness.js.map +1 -1
  277. package/dist/src/testing/reactivity-mesh-harness.d.ts +298 -0
  278. package/dist/src/testing/reactivity-mesh-harness.d.ts.map +1 -0
  279. package/dist/src/testing/reactivity-mesh-harness.js +663 -0
  280. package/dist/src/testing/reactivity-mesh-harness.js.map +1 -0
  281. package/package.json +7 -4
  282. package/src/cluster/block-transfer-service.ts +133 -68
  283. package/src/cluster/client.ts +64 -45
  284. package/src/cluster/cluster-error.ts +64 -0
  285. package/src/cluster/cluster-repo.ts +405 -55
  286. package/src/cluster/commit-cert.ts +139 -0
  287. package/src/cluster/service.ts +116 -44
  288. package/src/cluster/spread-on-churn.ts +328 -285
  289. package/src/cohort-topic/bootstrap-evidence-builder.ts +122 -0
  290. package/src/cohort-topic/bootstrap-evidence-verifiers.ts +132 -0
  291. package/src/cohort-topic/bootstrap-parent-reference.ts +159 -0
  292. package/src/cohort-topic/change-bridge.ts +109 -0
  293. package/src/cohort-topic/cohort-gossip-driver.ts +144 -0
  294. package/src/cohort-topic/cohort-gossip-transport.ts +74 -0
  295. package/src/cohort-topic/fret-trust-anchor.ts +153 -0
  296. package/src/cohort-topic/host.ts +2175 -0
  297. package/src/cohort-topic/index.ts +13 -0
  298. package/src/cohort-topic/membership-publish-sink.ts +20 -0
  299. package/src/cohort-topic/membership-source.ts +68 -0
  300. package/src/cohort-topic/peer-codec.ts +31 -0
  301. package/src/cohort-topic/peer-sig.ts +86 -0
  302. package/src/cohort-topic/protocols.ts +71 -0
  303. package/src/cohort-topic/reactivity-membership-gate.ts +77 -0
  304. package/src/cohort-topic/size-estimator.ts +16 -0
  305. package/src/cohort-topic/stream-util.ts +87 -0
  306. package/src/cohort-topic/threshold-crypto.ts +239 -0
  307. package/src/cohort-topic/topic-router.ts +77 -0
  308. package/src/dispute/cascade.ts +517 -0
  309. package/src/dispute/client.ts +12 -2
  310. package/src/dispute/dispute-service.ts +171 -24
  311. package/src/dispute/index.ts +42 -0
  312. package/src/dispute/invalidation.ts +587 -0
  313. package/src/dispute/types.ts +14 -0
  314. package/src/index.ts +4 -0
  315. package/src/libp2p-key-network.ts +67 -9
  316. package/src/libp2p-node-base.ts +633 -14
  317. package/src/matchmaking/aggregate-counts.ts +104 -0
  318. package/src/matchmaking/index.ts +20 -0
  319. package/src/matchmaking/module.ts +363 -0
  320. package/src/matchmaking/protocols.ts +51 -0
  321. package/src/matchmaking/provider-manager.ts +95 -0
  322. package/src/matchmaking/query-handler.ts +88 -0
  323. package/src/matchmaking/query-transport.ts +483 -0
  324. package/src/matchmaking/seeker-manager.ts +64 -0
  325. package/src/matchmaking/seeker-walk-client.ts +293 -0
  326. package/src/matchmaking/traffic-validation.ts +195 -0
  327. package/src/network/network-manager-service.ts +9 -2
  328. package/src/protocol-client.ts +119 -5
  329. package/src/reactivity/forwarder-host.ts +438 -0
  330. package/src/reactivity/index.ts +19 -0
  331. package/src/reactivity/notify-transport.ts +144 -0
  332. package/src/reactivity/origination-manager.ts +192 -0
  333. package/src/reactivity/protocols.ts +61 -0
  334. package/src/reactivity/push-state-gossip.ts +291 -0
  335. package/src/reactivity/recover-transport.ts +408 -0
  336. package/src/reactivity/rotation-rereg-scheduler.ts +256 -0
  337. package/src/reactivity/subscriber-registry.ts +96 -0
  338. package/src/reactivity/subscription-manager.ts +450 -0
  339. package/src/reactivity/topic-bytes.ts +37 -0
  340. package/src/repo/client.ts +54 -19
  341. package/src/repo/cluster-coordinator.ts +66 -26
  342. package/src/repo/coordinator-repo.ts +99 -15
  343. package/src/repo/service.ts +90 -42
  344. package/src/rpc-deadline.ts +45 -0
  345. package/src/storage/block-storage.ts +106 -3
  346. package/src/storage/i-block-storage.ts +27 -0
  347. package/src/storage/storage-repo.ts +209 -13
  348. package/src/sync/client.ts +5 -2
  349. package/src/testing/cohort-topic-mesh-harness.ts +613 -0
  350. package/src/testing/matchmaking-mesh-harness.ts +475 -0
  351. package/src/testing/mesh-harness.ts +22 -2
  352. package/src/testing/reactivity-mesh-harness.ts +922 -0
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Reactivity origination membership gate (`docs/reactivity.md` §Anchor, `docs/internals.md`
3
+ * §Cohort-Topic Origination Bridge).
4
+ *
5
+ * Builds the `selfIsCohortMember(event)` predicate the change-notifier bridge gates each member commit
6
+ * on: this node is responsible for a collection's reactivity-topic fan-out iff it sits in the FRET
7
+ * cohort around `coord_0(H(currentTailId ‖ "reactivity"))`. The tail comes from `event.tailId` (the seam
8
+ * ticket put the committed `CommitRequest.tailId` on the change event), so the decision is synchronous —
9
+ * no async storage read, no per-collection registry. A tail-less event (a read-driven promotion) is
10
+ * never a member; those never originate and are cert-gated out downstream anyway.
11
+ *
12
+ * Extracted from the node assembly so the encoding + coord derivation are unit-testable in isolation and
13
+ * reusable by the future reactivity origination wiring.
14
+ */
15
+ import { type ReactivityTopicAnchor, type TierAddressing, type CollectionChangeEvent } from "@optimystic/db-core";
16
+ import type { FretService } from "p2p-fret";
17
+ export { reactivityTailBytes } from "../reactivity/topic-bytes.js";
18
+ /** Construction inputs for {@link createReactivitySelfMembershipGate}. */
19
+ export interface ReactivitySelfMembershipGateDeps {
20
+ /** FRET membership read — the cohort assembler around a served coord (returns peer-id strings). */
21
+ readonly fret: Pick<FretService, "assembleCohort">;
22
+ /** This node's peer-id string, compared against the assembled cohort. */
23
+ readonly selfPeerId: string;
24
+ /**
25
+ * Requested cohort size `wantK`. MUST equal the cohort-topic host's `wantK`, so the gate checks the
26
+ * exact cohort the host serves; a mismatch silently breaks origination.
27
+ */
28
+ readonly wantK: number;
29
+ /**
30
+ * Reactivity topic anchor. Default db-core's {@link createReactivityTopicAnchor} (256-bit SHA-256),
31
+ * byte-identical to the host's internal `new RingHash()` and the subscriber-side anchor.
32
+ */
33
+ readonly anchor?: ReactivityTopicAnchor;
34
+ /**
35
+ * Tier addressing. Default `createTierAddressing(createRingHash())`. `coord_0` is fan-out independent
36
+ * (`H(0x00 ‖ topicId)`), so the default fan-out is irrelevant to the tier-0 reactivity coord.
37
+ */
38
+ readonly addressing?: TierAddressing;
39
+ }
40
+ /**
41
+ * Build the synchronous `selfIsCohortMember(event)` gate for {@link attachCohortChangeBridge}.
42
+ *
43
+ * Returns `false` for a tail-less event; otherwise resolves `coord_0(H(event.tailId ‖ "reactivity"))`
44
+ * via the shared anchor + tier addressing and returns whether `fret.assembleCohort(coord, wantK)`
45
+ * includes this node's peer id. Pure aside from the live FRET read; membership churn between commits is
46
+ * fine because reactivity is hint-only.
47
+ */
48
+ export declare function createReactivitySelfMembershipGate(deps: ReactivitySelfMembershipGateDeps): (event: CollectionChangeEvent) => boolean;
49
+ //# sourceMappingURL=reactivity-membership-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reactivity-membership-gate.d.ts","sourceRoot":"","sources":["../../../src/cohort-topic/reactivity-membership-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAIN,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAM5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAGnE,0EAA0E;AAC1E,MAAM,WAAW,gCAAgC;IAChD,mGAAmG;IACnG,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;IACnD,yEAAyE;IACzE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,qBAAqB,CAAC;IACxC;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,CAAC;CACrC;AAED;;;;;;;GAOG;AACH,wBAAgB,kCAAkC,CACjD,IAAI,EAAE,gCAAgC,GACpC,CAAC,KAAK,EAAE,qBAAqB,KAAK,OAAO,CAW3C"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Reactivity origination membership gate (`docs/reactivity.md` §Anchor, `docs/internals.md`
3
+ * §Cohort-Topic Origination Bridge).
4
+ *
5
+ * Builds the `selfIsCohortMember(event)` predicate the change-notifier bridge gates each member commit
6
+ * on: this node is responsible for a collection's reactivity-topic fan-out iff it sits in the FRET
7
+ * cohort around `coord_0(H(currentTailId ‖ "reactivity"))`. The tail comes from `event.tailId` (the seam
8
+ * ticket put the committed `CommitRequest.tailId` on the change event), so the decision is synchronous —
9
+ * no async storage read, no per-collection registry. A tail-less event (a read-driven promotion) is
10
+ * never a member; those never originate and are cert-gated out downstream anyway.
11
+ *
12
+ * Extracted from the node assembly so the encoding + coord derivation are unit-testable in isolation and
13
+ * reusable by the future reactivity origination wiring.
14
+ */
15
+ import { createReactivityTopicAnchor, createTierAddressing, createRingHash, } from "@optimystic/db-core";
16
+ // The pinned `BlockId` → raw tail-bytes encoding now lives in the reactivity surface so the origination
17
+ // gate (here) and the subscriber-side subscribe factory import the SAME function — see `reactivity/
18
+ // topic-bytes.ts` for the load-bearing rationale. Re-exported so this module's existing callers (tests,
19
+ // node wiring) keep importing `reactivityTailBytes` from the gate.
20
+ export { reactivityTailBytes } from "../reactivity/topic-bytes.js";
21
+ import { reactivityTailBytes } from "../reactivity/topic-bytes.js";
22
+ /**
23
+ * Build the synchronous `selfIsCohortMember(event)` gate for {@link attachCohortChangeBridge}.
24
+ *
25
+ * Returns `false` for a tail-less event; otherwise resolves `coord_0(H(event.tailId ‖ "reactivity"))`
26
+ * via the shared anchor + tier addressing and returns whether `fret.assembleCohort(coord, wantK)`
27
+ * includes this node's peer id. Pure aside from the live FRET read; membership churn between commits is
28
+ * fine because reactivity is hint-only.
29
+ */
30
+ export function createReactivitySelfMembershipGate(deps) {
31
+ const anchor = deps.anchor ?? createReactivityTopicAnchor();
32
+ const addressing = deps.addressing ?? createTierAddressing(createRingHash());
33
+ return (event) => {
34
+ if (event.tailId === undefined) {
35
+ return false; // promotion / tail-less event never originates
36
+ }
37
+ const topicId = anchor.topicId(reactivityTailBytes(event.tailId));
38
+ const coord = addressing.coord0(topicId);
39
+ return deps.fret.assembleCohort(coord, deps.wantK).includes(deps.selfPeerId);
40
+ };
41
+ }
42
+ //# sourceMappingURL=reactivity-membership-gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reactivity-membership-gate.js","sourceRoot":"","sources":["../../../src/cohort-topic/reactivity-membership-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACN,2BAA2B,EAC3B,oBAAoB,EACpB,cAAc,GAId,MAAM,qBAAqB,CAAC;AAG7B,wGAAwG;AACxG,oGAAoG;AACpG,wGAAwG;AACxG,mEAAmE;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAyBnE;;;;;;;GAOG;AACH,MAAM,UAAU,kCAAkC,CACjD,IAAsC;IAEtC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,2BAA2B,EAAE,CAAC;IAC5D,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,oBAAoB,CAAC,cAAc,EAAE,CAAC,CAAC;IAC7E,OAAO,CAAC,KAA4B,EAAW,EAAE;QAChD,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAChC,OAAO,KAAK,CAAC,CAAC,+CAA+C;QAC9D,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;QAClE,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACzC,OAAO,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC9E,CAAC,CAAC;AACH,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { ISizeEstimator } from "@optimystic/db-core";
2
+ import type { FretService } from "p2p-fret";
3
+ /**
4
+ * FRET-backed {@link ISizeEstimator}: feeds `d_max` from FRET's network-size estimate
5
+ * (`FretService.getNetworkSizeEstimate`). A clean, total binding — db-core's `d_max` computer applies
6
+ * the low-confidence clamp itself, so this adapter only forwards FRET's `(size_estimate, confidence)`.
7
+ */
8
+ export declare class FretSizeEstimator implements ISizeEstimator {
9
+ private readonly fret;
10
+ constructor(fret: FretService);
11
+ estimate(): {
12
+ nEst: number;
13
+ confidence: number;
14
+ };
15
+ }
16
+ //# sourceMappingURL=size-estimator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"size-estimator.d.ts","sourceRoot":"","sources":["../../../src/cohort-topic/size-estimator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C;;;;GAIG;AACH,qBAAa,iBAAkB,YAAW,cAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,WAAW;IAE9C,QAAQ,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE;CAIhD"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * FRET-backed {@link ISizeEstimator}: feeds `d_max` from FRET's network-size estimate
3
+ * (`FretService.getNetworkSizeEstimate`). A clean, total binding — db-core's `d_max` computer applies
4
+ * the low-confidence clamp itself, so this adapter only forwards FRET's `(size_estimate, confidence)`.
5
+ */
6
+ export class FretSizeEstimator {
7
+ fret;
8
+ constructor(fret) {
9
+ this.fret = fret;
10
+ }
11
+ estimate() {
12
+ const { size_estimate, confidence } = this.fret.getNetworkSizeEstimate();
13
+ return { nEst: size_estimate, confidence };
14
+ }
15
+ }
16
+ //# sourceMappingURL=size-estimator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"size-estimator.js","sourceRoot":"","sources":["../../../src/cohort-topic/size-estimator.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,MAAM,OAAO,iBAAiB;IACA;IAA7B,YAA6B,IAAiB;QAAjB,SAAI,GAAJ,IAAI,CAAa;IAAG,CAAC;IAElD,QAAQ;QACP,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE,CAAC;QACzE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC;IAC5C,CAAC;CACD"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Cohort-topic libp2p stream helpers.
3
+ *
4
+ * The cohort-topic protocols exchange a single self-delimiting cohort frame each way (the db-core wire
5
+ * codec already length-prefixes the body), so request/response is one `send` + one bounded read. This
6
+ * mirrors FRET's `rpc/maybe-act.ts` exactly and reuses FRET's exported `readAllBounded`, keeping the
7
+ * stream lifecycle (open → send → close-write → read → close) consistent across both protocol families.
8
+ */
9
+ import type { Libp2p } from "libp2p";
10
+ import type { PeerId } from "@libp2p/interface";
11
+ /** Default per-frame ceiling — matches FRET's 512 KiB maybe-act bound. */
12
+ export declare const DEFAULT_STREAM_MAX_BYTES: number;
13
+ /** Open `protocol` to `peer`, send `frame`, and read the bounded reply frame. */
14
+ export declare function requestResponse(node: Libp2p, peer: PeerId, protocol: string, frame: Uint8Array, maxBytes?: number): Promise<Uint8Array>;
15
+ /** Open `protocol` to `peer` and send `frame` without awaiting a reply (fire-and-forget gossip). */
16
+ export declare function sendOneWay(node: Libp2p, peer: PeerId, protocol: string, frame: Uint8Array): Promise<void>;
17
+ /** Register a request/response handler for `protocol`: read one bounded frame, reply with one frame. */
18
+ export declare function handleRequestResponse(node: Libp2p, protocol: string, handle: (frame: Uint8Array, from: PeerId) => Promise<Uint8Array | undefined>, maxBytes?: number): void;
19
+ //# sourceMappingURL=stream-util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-util.d.ts","sourceRoot":"","sources":["../../../src/cohort-topic/stream-util.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EAAc,MAAM,EAAU,MAAM,mBAAmB,CAAC;AAGpE,0EAA0E;AAC1E,eAAO,MAAM,wBAAwB,QAAa,CAAC;AAEnD,iFAAiF;AACjF,wBAAsB,eAAe,CACpC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,UAAU,EACjB,QAAQ,SAA2B,GACjC,OAAO,CAAC,UAAU,CAAC,CAiBrB;AAED,oGAAoG;AACpG,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB/G;AAED,wGAAwG;AACxG,wBAAgB,qBAAqB,CACpC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,EAC5E,QAAQ,SAA2B,GACjC,IAAI,CAmBN"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Cohort-topic libp2p stream helpers.
3
+ *
4
+ * The cohort-topic protocols exchange a single self-delimiting cohort frame each way (the db-core wire
5
+ * codec already length-prefixes the body), so request/response is one `send` + one bounded read. This
6
+ * mirrors FRET's `rpc/maybe-act.ts` exactly and reuses FRET's exported `readAllBounded`, keeping the
7
+ * stream lifecycle (open → send → close-write → read → close) consistent across both protocol families.
8
+ */
9
+ import { readAllBounded } from "p2p-fret";
10
+ /** Default per-frame ceiling — matches FRET's 512 KiB maybe-act bound. */
11
+ export const DEFAULT_STREAM_MAX_BYTES = 512 * 1024;
12
+ /** Open `protocol` to `peer`, send `frame`, and read the bounded reply frame. */
13
+ export async function requestResponse(node, peer, protocol, frame, maxBytes = DEFAULT_STREAM_MAX_BYTES) {
14
+ const conns = node.getConnections(peer);
15
+ let stream;
16
+ try {
17
+ stream = conns.length > 0 ? await conns[0].newStream([protocol]) : await node.dialProtocol(peer, [protocol]);
18
+ stream.send(frame);
19
+ await stream.close();
20
+ return await readAllBounded(stream, maxBytes);
21
+ }
22
+ finally {
23
+ if (stream != null) {
24
+ try {
25
+ await stream.close();
26
+ }
27
+ catch {
28
+ /* already closed */
29
+ }
30
+ }
31
+ }
32
+ }
33
+ /** Open `protocol` to `peer` and send `frame` without awaiting a reply (fire-and-forget gossip). */
34
+ export async function sendOneWay(node, peer, protocol, frame) {
35
+ const conns = node.getConnections(peer);
36
+ let stream;
37
+ try {
38
+ stream = conns.length > 0 ? await conns[0].newStream([protocol]) : await node.dialProtocol(peer, [protocol]);
39
+ stream.send(frame);
40
+ await stream.close();
41
+ }
42
+ finally {
43
+ if (stream != null) {
44
+ try {
45
+ await stream.close();
46
+ }
47
+ catch {
48
+ /* already closed */
49
+ }
50
+ }
51
+ }
52
+ }
53
+ /** Register a request/response handler for `protocol`: read one bounded frame, reply with one frame. */
54
+ export function handleRequestResponse(node, protocol, handle, maxBytes = DEFAULT_STREAM_MAX_BYTES) {
55
+ void node.handle(protocol, (stream, connection) => {
56
+ void (async () => {
57
+ try {
58
+ const frame = await readAllBounded(stream, maxBytes);
59
+ const reply = await handle(frame, connection.remotePeer);
60
+ if (reply !== undefined) {
61
+ stream.send(reply);
62
+ }
63
+ await stream.close();
64
+ }
65
+ catch {
66
+ try {
67
+ stream.abort(new Error("cohort-topic stream handler error"));
68
+ }
69
+ catch {
70
+ /* already aborted */
71
+ }
72
+ }
73
+ })();
74
+ });
75
+ }
76
+ //# sourceMappingURL=stream-util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-util.js","sourceRoot":"","sources":["../../../src/cohort-topic/stream-util.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Cohort-topic `k − x` threshold-signature crypto — real collected Ed25519 multi-signature.
3
+ *
4
+ * Closes gap 1 (the interim single-signer `sha256(payload)` digest, which could never satisfy
5
+ * `CohortSigner.verifyThreshold`'s `≥ minSigs` distinct-member rule at `minSigs = 14`). The scheme is
6
+ * a **collected multisig**: `thresholdSig` is the aligned concatenation of fixed-width 64-byte Ed25519
7
+ * signatures, one per `signers[i]`, each produced by that member's libp2p peer key over the *exact*
8
+ * canonical payload. It needs **no trusted setup, no new crypto dependency, and no aggregation round**
9
+ * (unlike BLS or FROST), maps directly onto the existing `(thresholdSig, signers)` contract, and reuses
10
+ * the per-member peer-key signing primitive (`peer-sig.ts`) the codebase already uses for cluster-repo
11
+ * commit signatures. Size is O(k) (≤ ~14 × 64 = 896 bytes at production `minSigs`) — negligible for
12
+ * k ≤ 16; if size ever matters at larger k the scheme can be swapped behind the unchanged
13
+ * {@link ICohortThresholdCrypto} port.
14
+ *
15
+ * **Coord-scoped.** `assemble(payload, minSigs)` carries no coord, so the adapter is constructed per
16
+ * served coord (one per {@link import("./host.js").CoordEngine}): it knows the cohort around its coord,
17
+ * the node's peer key (to add self's own signature without an RPC), and a `dialSign` seam over the
18
+ * `/sign` protocol to collect the other members' endorsements.
19
+ *
20
+ * **Verify is synchronous** — `ICohortThresholdCrypto.verify` is called from the sync
21
+ * `CohortSigner.verifyThreshold` on the participant path. {@link verifyCollectedMultisig} splits the
22
+ * blob into `signers.length` 64-byte chunks and {@link verifyPeerSig}-checks each against the
23
+ * corresponding signer's embedded Ed25519 key (noble, sync). Do not make it async.
24
+ */
25
+ import type { PrivateKey } from "@libp2p/interface";
26
+ import type { ICohortThresholdCrypto, RingCoord, SignKind, SignReplyV1, SignRequestV1 } from "@optimystic/db-core";
27
+ /** Width of an Ed25519 signature in bytes — the fixed stride of the concatenated `thresholdSig`. */
28
+ export declare const ED25519_SIG_BYTES = 64;
29
+ /** Default per-round deadline for collecting cohort endorsements (ms). */
30
+ export declare const DEFAULT_SIGN_COLLECT_TIMEOUT_MS = 5000;
31
+ /**
32
+ * Verify a collected Ed25519 multi-signature: `thresholdSig` must be exactly `signers.length × 64`
33
+ * bytes, and chunk `i` must be a valid peer-key signature by `signers[i]` over `payload`. Pure and
34
+ * synchronous; total (returns `false`, never throws). The db-core `CohortSigner.verifyThreshold` layer
35
+ * adds the distinct-signer / `signers ⊆ cert.members` / `≥ minSigs` checks on top of this.
36
+ */
37
+ export declare function verifyCollectedMultisig(payload: Uint8Array, thresholdSig: Uint8Array, signers: readonly Uint8Array[]): boolean;
38
+ /**
39
+ * Dependencies for a coord-scoped {@link FretCohortThresholdCrypto}. The host supplies these per
40
+ * {@link import("./host.js").CoordEngine}; the `kind` selects the endorsement policy the dialed
41
+ * members apply (membership cert vs promotion / demotion notice).
42
+ */
43
+ export interface CohortThresholdCryptoDeps {
44
+ /** What this signer assembles — sent in each {@link SignRequestV1} so members apply the right policy. */
45
+ readonly kind: SignKind;
46
+ /** The node's libp2p Ed25519 private key — signs self's own chunk locally (no RPC to self). */
47
+ readonly privateKey: PrivateKey;
48
+ /** Self's dialable member id (UTF-8 of the peer-id string); self is always a signer. */
49
+ readonly selfMember: Uint8Array;
50
+ /** The served coord whose cohort threshold-signs. */
51
+ readonly coord: () => RingCoord;
52
+ /** Current cohort epoch (raw bytes) for {@link coord}. */
53
+ readonly cohortEpoch: () => Uint8Array;
54
+ /** Current cohort member peer-id strings around {@link coord} (self may be included; excluded internally). */
55
+ readonly cohortMembers: () => string[];
56
+ /** Dial one cohort member's `/sign` RPC and return its reply. */
57
+ readonly dialSign: (peerIdStr: string, request: SignRequestV1) => Promise<SignReplyV1>;
58
+ /** Per-round collection deadline (ms). Default {@link DEFAULT_SIGN_COLLECT_TIMEOUT_MS}. */
59
+ readonly collectTimeoutMs?: number;
60
+ /**
61
+ * Whether self may contribute its own signature to this assembly. Default `true` (self is always a
62
+ * member of the cohort it signs over). The **rotation** producer scopes the assembly to the
63
+ * *predecessor* cohort (`cohortMembers` = the prior epoch's members); when self was not a member of
64
+ * that prior cohort it must NOT self-sign — its chunk would be dropped by the verifier (a signer not in
65
+ * the predecessor cert's `members`), desyncing the count from what the verifier accepts. Returning
66
+ * `false` then makes the quorum genuinely the outgoing cohort. See `cohort-topic-trust-anchor-rotation-production`.
67
+ */
68
+ readonly selfEligible?: () => boolean;
69
+ }
70
+ /**
71
+ * Real coord-scoped {@link ICohortThresholdCrypto}. `assemble` signs locally, concurrently dials the
72
+ * rest of the cohort over the `/sign` protocol, verifies each returned signature before counting it,
73
+ * and concatenates `≥ minSigs` distinct signatures into the threshold blob — or throws if a quorum is
74
+ * unreachable (it must **never** fabricate a single-signer sig, the interim bug). `verify` is the pure
75
+ * split-and-check.
76
+ */
77
+ export declare class FretCohortThresholdCrypto implements ICohortThresholdCrypto {
78
+ private readonly deps;
79
+ constructor(deps: CohortThresholdCryptoDeps);
80
+ assemble(payload: Uint8Array, minSigs: number): Promise<{
81
+ thresholdSig: Uint8Array;
82
+ signers: Uint8Array[];
83
+ }>;
84
+ verify(payload: Uint8Array, thresholdSig: Uint8Array, signers: readonly Uint8Array[]): boolean;
85
+ /** Dial one member, verify-before-count its endorsement, and add it to `collected` (dropping bad/dupe). */
86
+ private collectFrom;
87
+ }
88
+ /**
89
+ * A verify-only {@link ICohortThresholdCrypto} for the participant-side verifier, which never assembles
90
+ * (it only checks inbound threshold-signed messages). `assemble` rejects so a misuse surfaces loudly
91
+ * rather than fabricating a signature.
92
+ */
93
+ export declare function createVerifyOnlyThresholdCrypto(): ICohortThresholdCrypto;
94
+ //# sourceMappingURL=threshold-crypto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threshold-crypto.d.ts","sourceRoot":"","sources":["../../../src/cohort-topic/threshold-crypto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,sBAAsB,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAKnH,oGAAoG;AACpG,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAEpC,0EAA0E;AAC1E,eAAO,MAAM,+BAA+B,OAAQ,CAAC;AAErD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,UAAU,EAAE,GAAG,OAAO,CAc9H;AAED;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACzC,yGAAyG;IACzG,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,+FAA+F;IAC/F,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,wFAAwF;IACxF,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,qDAAqD;IACrD,QAAQ,CAAC,KAAK,EAAE,MAAM,SAAS,CAAC;IAChC,0DAA0D;IAC1D,QAAQ,CAAC,WAAW,EAAE,MAAM,UAAU,CAAC;IACvC,8GAA8G;IAC9G,QAAQ,CAAC,aAAa,EAAE,MAAM,MAAM,EAAE,CAAC;IACvC,iEAAiE;IACjE,QAAQ,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IACvF,2FAA2F;IAC3F,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC;;;;;;;OAOG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC;CACtC;AAQD;;;;;;GAMG;AACH,qBAAa,yBAA0B,YAAW,sBAAsB;IAC3D,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,yBAAyB;IAEtD,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,YAAY,EAAE,UAAU,CAAC;QAAC,OAAO,EAAE,UAAU,EAAE,CAAA;KAAE,CAAC;IA4ClH,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,UAAU,EAAE,GAAG,OAAO;IAI9F,2GAA2G;YAC7F,WAAW;CA8BzB;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,IAAI,sBAAsB,CAMxE"}
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Cohort-topic `k − x` threshold-signature crypto — real collected Ed25519 multi-signature.
3
+ *
4
+ * Closes gap 1 (the interim single-signer `sha256(payload)` digest, which could never satisfy
5
+ * `CohortSigner.verifyThreshold`'s `≥ minSigs` distinct-member rule at `minSigs = 14`). The scheme is
6
+ * a **collected multisig**: `thresholdSig` is the aligned concatenation of fixed-width 64-byte Ed25519
7
+ * signatures, one per `signers[i]`, each produced by that member's libp2p peer key over the *exact*
8
+ * canonical payload. It needs **no trusted setup, no new crypto dependency, and no aggregation round**
9
+ * (unlike BLS or FROST), maps directly onto the existing `(thresholdSig, signers)` contract, and reuses
10
+ * the per-member peer-key signing primitive (`peer-sig.ts`) the codebase already uses for cluster-repo
11
+ * commit signatures. Size is O(k) (≤ ~14 × 64 = 896 bytes at production `minSigs`) — negligible for
12
+ * k ≤ 16; if size ever matters at larger k the scheme can be swapped behind the unchanged
13
+ * {@link ICohortThresholdCrypto} port.
14
+ *
15
+ * **Coord-scoped.** `assemble(payload, minSigs)` carries no coord, so the adapter is constructed per
16
+ * served coord (one per {@link import("./host.js").CoordEngine}): it knows the cohort around its coord,
17
+ * the node's peer key (to add self's own signature without an RPC), and a `dialSign` seam over the
18
+ * `/sign` protocol to collect the other members' endorsements.
19
+ *
20
+ * **Verify is synchronous** — `ICohortThresholdCrypto.verify` is called from the sync
21
+ * `CohortSigner.verifyThreshold` on the participant path. {@link verifyCollectedMultisig} splits the
22
+ * blob into `signers.length` 64-byte chunks and {@link verifyPeerSig}-checks each against the
23
+ * corresponding signer's embedded Ed25519 key (noble, sync). Do not make it async.
24
+ */
25
+ import { bytesToB64url, b64urlToBytes, compareBytes } from "@optimystic/db-core";
26
+ import { signPeer, verifyPeerSig } from "./peer-sig.js";
27
+ import { bytesToPeerIdString } from "./peer-codec.js";
28
+ /** Width of an Ed25519 signature in bytes — the fixed stride of the concatenated `thresholdSig`. */
29
+ export const ED25519_SIG_BYTES = 64;
30
+ /** Default per-round deadline for collecting cohort endorsements (ms). */
31
+ export const DEFAULT_SIGN_COLLECT_TIMEOUT_MS = 5_000;
32
+ /**
33
+ * Verify a collected Ed25519 multi-signature: `thresholdSig` must be exactly `signers.length × 64`
34
+ * bytes, and chunk `i` must be a valid peer-key signature by `signers[i]` over `payload`. Pure and
35
+ * synchronous; total (returns `false`, never throws). The db-core `CohortSigner.verifyThreshold` layer
36
+ * adds the distinct-signer / `signers ⊆ cert.members` / `≥ minSigs` checks on top of this.
37
+ */
38
+ export function verifyCollectedMultisig(payload, thresholdSig, signers) {
39
+ if (signers.length === 0) {
40
+ return false;
41
+ }
42
+ if (thresholdSig.length !== signers.length * ED25519_SIG_BYTES) {
43
+ return false;
44
+ }
45
+ for (let i = 0; i < signers.length; i++) {
46
+ const chunk = thresholdSig.subarray(i * ED25519_SIG_BYTES, (i + 1) * ED25519_SIG_BYTES);
47
+ if (!verifyPeerSig(signers[i], payload, chunk)) {
48
+ return false;
49
+ }
50
+ }
51
+ return true;
52
+ }
53
+ /**
54
+ * Real coord-scoped {@link ICohortThresholdCrypto}. `assemble` signs locally, concurrently dials the
55
+ * rest of the cohort over the `/sign` protocol, verifies each returned signature before counting it,
56
+ * and concatenates `≥ minSigs` distinct signatures into the threshold blob — or throws if a quorum is
57
+ * unreachable (it must **never** fabricate a single-signer sig, the interim bug). `verify` is the pure
58
+ * split-and-check.
59
+ */
60
+ export class FretCohortThresholdCrypto {
61
+ deps;
62
+ constructor(deps) {
63
+ this.deps = deps;
64
+ }
65
+ async assemble(payload, minSigs) {
66
+ const collected = new Map();
67
+ const selfStr = bytesToPeerIdString(this.deps.selfMember);
68
+ // Self is normally a signer — it is the acting member, even if a stale table omits it from its own
69
+ // assembly. Sign locally (no RPC to self). A rotation producer that was NOT in the predecessor cohort
70
+ // (`selfEligible` → false) skips this: its chunk would be dropped by the verifier (signer ∉ predecessor
71
+ // cert members), so it must collect a quorum purely from the outgoing cohort instead.
72
+ if (this.deps.selfEligible?.() ?? true) {
73
+ const selfSig = await signPeer(this.deps.privateKey, payload);
74
+ if (selfSig.length !== ED25519_SIG_BYTES) {
75
+ throw new Error(`cohort threshold sign: self produced a ${selfSig.length}-byte signature (expected ${ED25519_SIG_BYTES}); non-Ed25519 identity?`);
76
+ }
77
+ collected.set(bytesToB64url(this.deps.selfMember), { signer: this.deps.selfMember, sig: selfSig });
78
+ }
79
+ // Concurrently collect endorsements from the rest of the cohort, up to the deadline.
80
+ const others = this.deps.cohortMembers().filter((m) => m !== selfStr);
81
+ if (others.length > 0 && collected.size < minSigs) {
82
+ const request = {
83
+ v: 1,
84
+ kind: this.deps.kind,
85
+ coord: bytesToB64url(this.deps.coord()),
86
+ cohortEpoch: bytesToB64url(this.deps.cohortEpoch()),
87
+ payload: bytesToB64url(payload),
88
+ };
89
+ const timeoutMs = this.deps.collectTimeoutMs ?? DEFAULT_SIGN_COLLECT_TIMEOUT_MS;
90
+ await Promise.all(others.map((peerStr) => this.collectFrom(peerStr, request, payload, collected, timeoutMs)));
91
+ }
92
+ if (collected.size < minSigs) {
93
+ // Quorum unreachable / unwilling: no notice this round. The promotion / cert path re-fires next
94
+ // tick. NEVER fabricate a single-signer sig — that is exactly the interim bug this replaces.
95
+ throw new Error(`cohort threshold sign: gathered ${collected.size} of ${minSigs} required signatures`);
96
+ }
97
+ // Deterministic order (ascending by signer id) so the concatenation is reproducible and aligns
98
+ // signers[i] ↔ chunk i for the verifier.
99
+ const ordered = [...collected.values()].sort((a, b) => compareBytes(a.signer, b.signer));
100
+ const signers = ordered.map((e) => e.signer);
101
+ const thresholdSig = concatSigs(ordered.map((e) => e.sig));
102
+ return { thresholdSig, signers };
103
+ }
104
+ verify(payload, thresholdSig, signers) {
105
+ return verifyCollectedMultisig(payload, thresholdSig, signers);
106
+ }
107
+ /** Dial one member, verify-before-count its endorsement, and add it to `collected` (dropping bad/dupe). */
108
+ async collectFrom(peerStr, request, payload, collected, timeoutMs) {
109
+ try {
110
+ const reply = await withTimeout(this.deps.dialSign(peerStr, request), timeoutMs);
111
+ if (reply === undefined || "refused" in reply) {
112
+ return; // unreachable (timed out) or the member declined to endorse
113
+ }
114
+ const signerBytes = b64urlToBytes(reply.signer);
115
+ const sigBytes = b64urlToBytes(reply.signature);
116
+ if (sigBytes.length !== ED25519_SIG_BYTES) {
117
+ return; // a malformed chunk would desync the fixed-stride concatenation
118
+ }
119
+ // Verify before counting: a member must not be able to poison the blob with a bad signature.
120
+ if (!verifyPeerSig(signerBytes, payload, sigBytes)) {
121
+ return;
122
+ }
123
+ const key = bytesToB64url(signerBytes);
124
+ if (collected.has(key)) {
125
+ return; // a duplicate signer cannot pad the count toward minSigs
126
+ }
127
+ collected.set(key, { signer: signerBytes, sig: sigBytes });
128
+ }
129
+ catch {
130
+ // Unreachable member or malformed reply — drop it; collection continues with the rest.
131
+ }
132
+ }
133
+ }
134
+ /**
135
+ * A verify-only {@link ICohortThresholdCrypto} for the participant-side verifier, which never assembles
136
+ * (it only checks inbound threshold-signed messages). `assemble` rejects so a misuse surfaces loudly
137
+ * rather than fabricating a signature.
138
+ */
139
+ export function createVerifyOnlyThresholdCrypto() {
140
+ return {
141
+ assemble: () => Promise.reject(new Error("verify-only cohort threshold crypto cannot assemble signatures")),
142
+ verify: verifyCollectedMultisig,
143
+ };
144
+ }
145
+ /** Concatenate equal-width signature chunks into one fixed-stride blob aligned with the signer order. */
146
+ function concatSigs(sigs) {
147
+ const out = new Uint8Array(sigs.length * ED25519_SIG_BYTES);
148
+ for (let i = 0; i < sigs.length; i++) {
149
+ out.set(sigs[i], i * ED25519_SIG_BYTES);
150
+ }
151
+ return out;
152
+ }
153
+ /** Resolve `p`, or `undefined` if `timeoutMs` elapses first (bounds wall-clock against an unreachable peer). */
154
+ function withTimeout(p, timeoutMs) {
155
+ return new Promise((resolve) => {
156
+ let settled = false;
157
+ const timer = setTimeout(() => {
158
+ if (!settled) {
159
+ settled = true;
160
+ resolve(undefined);
161
+ }
162
+ }, timeoutMs);
163
+ void p.then((value) => {
164
+ if (!settled) {
165
+ settled = true;
166
+ clearTimeout(timer);
167
+ resolve(value);
168
+ }
169
+ }, () => {
170
+ if (!settled) {
171
+ settled = true;
172
+ clearTimeout(timer);
173
+ resolve(undefined);
174
+ }
175
+ });
176
+ });
177
+ }
178
+ //# sourceMappingURL=threshold-crypto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threshold-crypto.js","sourceRoot":"","sources":["../../../src/cohort-topic/threshold-crypto.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import type { ITopicRouter, PeerRef, RingCoord } from "@optimystic/db-core";
2
+ import type { Libp2p } from "libp2p";
3
+ import type { FretService } from "p2p-fret";
4
+ export interface FretTopicRouterOptions {
5
+ /** The `/register` protocol id (defaults to the canonical one). */
6
+ readonly registerProtocol?: string;
7
+ /** RPC TTL hops for `RouteAndMaybeAct`. Default 16. */
8
+ readonly ttl?: number;
9
+ /** Per-frame ceiling. Default {@link DEFAULT_STREAM_MAX_BYTES}. */
10
+ readonly maxBytes?: number;
11
+ /** Monotonic clock (unix ms); injectable for tests. Default `Date.now`. */
12
+ readonly clock?: () => number;
13
+ }
14
+ /**
15
+ * FRET-backed {@link ITopicRouter}.
16
+ *
17
+ * `routeAndAct` maps onto FRET's `RouteAndMaybeAct` (`FretService.routeAct`): the `RegisterV1` frame
18
+ * rides the `activity` field (base64url), routed to the cohort owning `key = coord_d(self, topicId)`,
19
+ * collecting `want_k = k` participants and `min_sigs = k − x`. The cohort's activity callback (set by
20
+ * the host) runs the willingness / cold-start / admission decision and returns the encoded
21
+ * `RegisterReplyV1` as the `commitCertificate`; this adapter decodes it back to bytes. A bare
22
+ * `NearAnchorV1` (no in-cluster activity ran) is surfaced to the walk as `no_state`.
23
+ *
24
+ * `dialMember` is the post-registration direct path: a libp2p dial of the `/register` protocol to the
25
+ * cached primary, used by the renewal ping (`docs/cohort-topic.md` §FRET integration L457-460).
26
+ */
27
+ export declare class FretTopicRouter implements ITopicRouter {
28
+ private readonly node;
29
+ private readonly fret;
30
+ private readonly registerProtocol;
31
+ private readonly ttl;
32
+ private readonly maxBytes;
33
+ private readonly clock;
34
+ constructor(node: Libp2p, fret: FretService, options?: FretTopicRouterOptions);
35
+ routeAndAct(key: RingCoord, activity: Uint8Array, opts: {
36
+ wantK: number;
37
+ minSigs: number;
38
+ }): Promise<Uint8Array>;
39
+ dialMember(member: PeerRef, activity: Uint8Array): Promise<Uint8Array>;
40
+ }
41
+ //# sourceMappingURL=topic-router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topic-router.d.ts","sourceRoot":"","sources":["../../../src/cohort-topic/topic-router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAE5E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EAAE,WAAW,EAAoC,MAAM,UAAU,CAAC;AAU9E,MAAM,WAAW,sBAAsB;IACtC,mEAAmE;IACnE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,uDAAuD;IACvD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;CAC9B;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,eAAgB,YAAW,YAAY;IAMvC,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAU,OAAO,CAAC,QAAQ,CAAC,IAAI;IALhE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;gBAER,IAAI,EAAE,MAAM,EAAmB,IAAI,EAAE,WAAW,EAAE,OAAO,GAAE,sBAA2B;IAO7G,WAAW,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAsBhH,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;CAI5E"}