@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,59 @@
1
+ /**
2
+ * Cohort-topic substrate — participant-side bootstrap-evidence builder (db-p2p side of the `buildBootstrapEvidence` seam).
3
+ *
4
+ * Implements the db-core `CohortTopicServiceDeps.buildBootstrapEvidence` seam for the node's participant
5
+ * role: on a cold-start `bootstrap: true` re-issue the service calls this with the register's own
6
+ * canonical `(topicId, tier, participantCoord, timestamp)` tuple (base64url wire strings) and attaches the
7
+ * returned bytes — **before** signing — into `RegisterV1.bootstrapEvidence`.
8
+ *
9
+ * - **Tier ≤ maxNoPowTier (T0/T1):** proof-of-work is not the expected evidence. With an `endorse`
10
+ * capability (a key-ful node) we mint a *self-vouch reputation endorsement* over the bound image so a
11
+ * configured cohort's referee verifier admits it; without one we return `undefined` (parent-reference
12
+ * origination is the follow-on `cohort-topic-bootstrap-parent-reference`). A T0/T1 bootstrap with no
13
+ * evidence is denied by a configured cohort until that lands — but the single-tier-0 milestone's
14
+ * cohort-side tests construct evidence directly, so this does not block them.
15
+ * - **Tier ≥ maxNoPowTier+1 (T2/T3):** mint a proof-of-work — loop nonces until
16
+ * `meetsDifficulty(hash.H(powPreimage(reg, nonce)), bits)`. Bound work ≈ `2^bits` hashes (default 20 ≈
17
+ * ~1 M, sub-second). The loop is capped ({@link DEFAULT_POW_MAX_ITERATIONS}); on cap-exceeded it returns
18
+ * `undefined` so the register proceeds without evidence rather than ever hanging the register path.
19
+ *
20
+ * Returns the **raw** envelope JSON bytes (`utf8(JSON.stringify(env))`), NOT the already-base64url string
21
+ * from `serializeBootstrapEvidenceEnvelope` — the service base64url-encodes them itself (returning the
22
+ * serialized string's bytes would double-encode the field). We obtain the raw bytes by decoding the
23
+ * canonical serializer output once, so the byte layout matches exactly what a verifier reconstructs.
24
+ */
25
+ import { type IRingHash, type BootstrapBoundFields, type ReputationEvidenceV1 } from "@optimystic/db-core";
26
+ /**
27
+ * Defensive cap on the PoW nonce search (~16.7 M hashes). Comfortably above the ~`2^bits` expected for
28
+ * the default 20-bit difficulty (~1 M), so a real miner solves long before the cap; hitting it (a
29
+ * mis-set, very-high `bits`) returns `undefined` rather than hanging the register path.
30
+ */
31
+ export declare const DEFAULT_POW_MAX_ITERATIONS: number;
32
+ /** The bound tuple the service hands the builder — the same shape a verifier binds via {@link bootstrapBoundImage}. */
33
+ export type BootstrapEvidenceBuildParams = BootstrapBoundFields;
34
+ /** Inputs to {@link createBootstrapEvidenceBuilder}. */
35
+ export interface BootstrapEvidenceBuilderDeps {
36
+ /** The node's ring hash (SHA-256) — the same `H` the PoW verifier checks against. */
37
+ readonly hash: IRingHash;
38
+ /** Difficulty bits to mint at. Default {@link DEFAULT_POW_DIFFICULTY_BITS}. `0` solves on the first nonce (test). */
39
+ readonly bits?: number;
40
+ /** Highest tier exempt from PoW (T0/T1 → 1). Default {@link DEFAULT_MAX_NO_POW_TIER}. */
41
+ readonly maxNoPowTier?: number;
42
+ /** Nonce-search cap. Default {@link DEFAULT_POW_MAX_ITERATIONS}. */
43
+ readonly maxIterations?: number;
44
+ /**
45
+ * Optional self-vouch endorsement capability for a key-ful node: signs the bound image with the node's
46
+ * peer key and returns the referee (= self) + signature. Supplied → T0/T1 mints a reputation
47
+ * endorsement (the interim T0/T1 path until parent-reference origination lands); absent → T0/T1 carries
48
+ * no evidence.
49
+ */
50
+ readonly endorse?: (boundImage: Uint8Array) => Promise<ReputationEvidenceV1>;
51
+ }
52
+ /**
53
+ * Build the {@link import("@optimystic/db-core").CohortTopicServiceDeps.buildBootstrapEvidence} seam:
54
+ * a `(params) => Promise<Uint8Array | undefined>` that mints the cold-start evidence for the node's own
55
+ * register. PoW for T2/T3; a self-vouch reputation endorsement (when `endorse` is supplied) or nothing
56
+ * for T0/T1. Never throws and never hangs (the nonce loop is capped).
57
+ */
58
+ export declare function createBootstrapEvidenceBuilder(deps: BootstrapEvidenceBuilderDeps): (params: BootstrapEvidenceBuildParams) => Promise<Uint8Array | undefined>;
59
+ //# sourceMappingURL=bootstrap-evidence-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap-evidence-builder.d.ts","sourceRoot":"","sources":["../../../src/cohort-topic/bootstrap-evidence-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EASN,KAAK,SAAS,EACd,KAAK,oBAAoB,EAEzB,KAAK,oBAAoB,EACzB,MAAM,qBAAqB,CAAC;AAG7B;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,QAAU,CAAC;AAElD,uHAAuH;AACvH,MAAM,MAAM,4BAA4B,GAAG,oBAAoB,CAAC;AAEhE,wDAAwD;AACxD,MAAM,WAAW,4BAA4B;IAC5C,qFAAqF;IACrF,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,qHAAqH;IACrH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,yFAAyF;IACzF,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,oEAAoE;IACpE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAC7E;AAED;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC7C,IAAI,EAAE,4BAA4B,GAChC,CAAC,MAAM,EAAE,4BAA4B,KAAK,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAiC3E"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Cohort-topic substrate — participant-side bootstrap-evidence builder (db-p2p side of the `buildBootstrapEvidence` seam).
3
+ *
4
+ * Implements the db-core `CohortTopicServiceDeps.buildBootstrapEvidence` seam for the node's participant
5
+ * role: on a cold-start `bootstrap: true` re-issue the service calls this with the register's own
6
+ * canonical `(topicId, tier, participantCoord, timestamp)` tuple (base64url wire strings) and attaches the
7
+ * returned bytes — **before** signing — into `RegisterV1.bootstrapEvidence`.
8
+ *
9
+ * - **Tier ≤ maxNoPowTier (T0/T1):** proof-of-work is not the expected evidence. With an `endorse`
10
+ * capability (a key-ful node) we mint a *self-vouch reputation endorsement* over the bound image so a
11
+ * configured cohort's referee verifier admits it; without one we return `undefined` (parent-reference
12
+ * origination is the follow-on `cohort-topic-bootstrap-parent-reference`). A T0/T1 bootstrap with no
13
+ * evidence is denied by a configured cohort until that lands — but the single-tier-0 milestone's
14
+ * cohort-side tests construct evidence directly, so this does not block them.
15
+ * - **Tier ≥ maxNoPowTier+1 (T2/T3):** mint a proof-of-work — loop nonces until
16
+ * `meetsDifficulty(hash.H(powPreimage(reg, nonce)), bits)`. Bound work ≈ `2^bits` hashes (default 20 ≈
17
+ * ~1 M, sub-second). The loop is capped ({@link DEFAULT_POW_MAX_ITERATIONS}); on cap-exceeded it returns
18
+ * `undefined` so the register proceeds without evidence rather than ever hanging the register path.
19
+ *
20
+ * Returns the **raw** envelope JSON bytes (`utf8(JSON.stringify(env))`), NOT the already-base64url string
21
+ * from `serializeBootstrapEvidenceEnvelope` — the service base64url-encodes them itself (returning the
22
+ * serialized string's bytes would double-encode the field). We obtain the raw bytes by decoding the
23
+ * canonical serializer output once, so the byte layout matches exactly what a verifier reconstructs.
24
+ */
25
+ import { serializeBootstrapEvidenceEnvelope, bootstrapBoundImage, powPreimage, meetsDifficulty, DEFAULT_POW_DIFFICULTY_BITS, DEFAULT_MAX_NO_POW_TIER, bytesToB64url, b64urlToBytes, } from "@optimystic/db-core";
26
+ import { randomBytes } from "@libp2p/crypto";
27
+ /**
28
+ * Defensive cap on the PoW nonce search (~16.7 M hashes). Comfortably above the ~`2^bits` expected for
29
+ * the default 20-bit difficulty (~1 M), so a real miner solves long before the cap; hitting it (a
30
+ * mis-set, very-high `bits`) returns `undefined` rather than hanging the register path.
31
+ */
32
+ export const DEFAULT_POW_MAX_ITERATIONS = 1 << 24;
33
+ /**
34
+ * Build the {@link import("@optimystic/db-core").CohortTopicServiceDeps.buildBootstrapEvidence} seam:
35
+ * a `(params) => Promise<Uint8Array | undefined>` that mints the cold-start evidence for the node's own
36
+ * register. PoW for T2/T3; a self-vouch reputation endorsement (when `endorse` is supplied) or nothing
37
+ * for T0/T1. Never throws and never hangs (the nonce loop is capped).
38
+ */
39
+ export function createBootstrapEvidenceBuilder(deps) {
40
+ const bits = deps.bits ?? DEFAULT_POW_DIFFICULTY_BITS;
41
+ const maxNoPowTier = deps.maxNoPowTier ?? DEFAULT_MAX_NO_POW_TIER;
42
+ const maxIterations = deps.maxIterations ?? DEFAULT_POW_MAX_ITERATIONS;
43
+ return async (params) => {
44
+ const bound = {
45
+ topicId: params.topicId,
46
+ tier: params.tier,
47
+ participantCoord: params.participantCoord,
48
+ timestamp: params.timestamp,
49
+ };
50
+ if (params.tier <= maxNoPowTier) {
51
+ // T0/T1: PoW is not the expected evidence. A key-ful node self-vouches; otherwise no evidence
52
+ // (the parent-reference path is the follow-on ticket — documented deferral).
53
+ if (deps.endorse === undefined) {
54
+ return undefined;
55
+ }
56
+ const reputation = await deps.endorse(bootstrapBoundImage(bound));
57
+ return rawEnvelopeBytes({ v: 1, reputation });
58
+ }
59
+ // T2/T3: mint a proof-of-work — search nonces until the digest meets the difficulty target.
60
+ for (let i = 0; i < maxIterations; i++) {
61
+ const nonce = randomBytes(16); // CSPRNG nonce — bound to the register tuple via the preimage
62
+ if (meetsDifficulty(deps.hash.H(powPreimage(bound, nonce)), bits)) {
63
+ return rawEnvelopeBytes({ v: 1, pow: { nonce: bytesToB64url(nonce) } });
64
+ }
65
+ }
66
+ // Cap exceeded (mis-set difficulty): attach nothing rather than hang. A configured cohort denies it.
67
+ return undefined;
68
+ };
69
+ }
70
+ /**
71
+ * The raw envelope JSON bytes the service expects (`utf8(JSON.stringify(env))`). Reuses the db-core
72
+ * canonical serializer (fixed field order, deterministic JSON) and decodes its base64url output back to
73
+ * the underlying bytes — so the layout is byte-identical to what a verifier reconstructs, with zero
74
+ * duplicated canonicalization here.
75
+ */
76
+ function rawEnvelopeBytes(env) {
77
+ return b64urlToBytes(serializeBootstrapEvidenceEnvelope(env));
78
+ }
79
+ //# sourceMappingURL=bootstrap-evidence-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap-evidence-builder.js","sourceRoot":"","sources":["../../../src/cohort-topic/bootstrap-evidence-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EACN,kCAAkC,EAClC,mBAAmB,EACnB,WAAW,EACX,eAAe,EACf,2BAA2B,EAC3B,uBAAuB,EACvB,aAAa,EACb,aAAa,GAKb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C;;;;GAIG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,IAAI,EAAE,CAAC;AAwBlD;;;;;GAKG;AACH,MAAM,UAAU,8BAA8B,CAC7C,IAAkC;IAElC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,2BAA2B,CAAC;IACtD,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,uBAAuB,CAAC;IAClE,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,0BAA0B,CAAC;IAEvE,OAAO,KAAK,EAAE,MAAoC,EAAmC,EAAE;QACtF,MAAM,KAAK,GAAyB;YACnC,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;YACzC,SAAS,EAAE,MAAM,CAAC,SAAS;SAC3B,CAAC;QAEF,IAAI,MAAM,CAAC,IAAI,IAAI,YAAY,EAAE,CAAC;YACjC,8FAA8F;YAC9F,6EAA6E;YAC7E,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;gBAChC,OAAO,SAAS,CAAC;YAClB,CAAC;YACD,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC;YAClE,OAAO,gBAAgB,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC;QAC/C,CAAC;QAED,4FAA4F;QAC5F,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,EAAE,CAAC,EAAE,EAAE,CAAC;YACxC,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,8DAA8D;YAC7F,IAAI,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC;gBACnE,OAAO,gBAAgB,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;YACzE,CAAC;QACF,CAAC;QACD,qGAAqG;QACrG,OAAO,SAAS,CAAC;IAClB,CAAC,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,GAAgC;IACzD,OAAO,aAAa,CAAC,kCAAkC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/D,CAAC"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Cohort-topic substrate — real bootstrap-evidence verifiers (db-p2p side of the anti-DoS gate).
3
+ *
4
+ * db-core owns the *policy* (which evidence kinds satisfy which tier) and the crypto-free envelope /
5
+ * bound-image / PoW-preimage helpers (`antidos/bootstrap-evidence-envelope.ts`); it deliberately embeds
6
+ * no specific PoW or reputation scheme. This module supplies the **self-contained cryptographic checks**
7
+ * the host injects into `createBootstrapEvidence`, binding the node's `RingHash` (the same SHA-256 the
8
+ * addressing uses) and the cohort-topic peer-key `verifyPeerSig` — no new crypto dependency.
9
+ *
10
+ * Both verifiers are **synchronous** (one hash, or one signature verify + two reputation-map reads) and
11
+ * **total** — any parse / decode / verify failure on attacker-supplied input yields `false`, never a
12
+ * throw — because `BootstrapEvidence.verify` runs inside `member-engine.ts`'s `runGuards` on every
13
+ * register and must do no network I/O (that would itself be a DoS amplifier).
14
+ */
15
+ import { type IRingHash, type RegisterV1 } from "@optimystic/db-core";
16
+ /**
17
+ * The slice of a peer-reputation service the bootstrap-evidence referee verifier consults — a subset of
18
+ * {@link import("../reputation/types.js").IPeerReputation} that `PeerReputationService` satisfies
19
+ * directly. "Sufficient reputation" is **stronger than mere non-ban**: the referee must be *both* not
20
+ * banned *and* below the deprioritize threshold.
21
+ */
22
+ export interface BootstrapReputationView {
23
+ /** True when `peerId` (a peer-id string) is banned / excluded from operations. */
24
+ isBanned(peerId: string): boolean;
25
+ /** Effective reputation score for `peerId` (0 = a clean, unseen peer). Lower is better. */
26
+ getScore(peerId: string): number;
27
+ }
28
+ /**
29
+ * The default "sufficient reputation" cutoff: a referee with `score < deprioritize` is reputable enough
30
+ * to endorse a bootstrap. Mirrors the reputation service's default `deprioritize` threshold (20) so a
31
+ * default-configured node and the gate agree on "sufficient". Strict `<`, so a referee *at* the
32
+ * threshold is not sufficient.
33
+ */
34
+ export declare const DEFAULT_DEPRIORITIZE_THRESHOLD: number;
35
+ /** Inputs to {@link createPoWVerifier}. */
36
+ export interface PoWVerifierDeps {
37
+ /** The node's ring hash (SHA-256) — the same `H` the addressing uses; hashes the PoW preimage. */
38
+ readonly hash: IRingHash;
39
+ /** Required leading-zero bits. Default {@link DEFAULT_POW_DIFFICULTY_BITS}. `0` admits any nonce (test). */
40
+ readonly bits?: number;
41
+ }
42
+ /**
43
+ * A real proof-of-work verifier for the T2/T3 evidence path. Self-contained — no subsystem, one hash.
44
+ *
45
+ * ```
46
+ * env = parseBootstrapEvidenceEnvelope(reg); if (!env?.pow) return false
47
+ * h = hash.H(powPreimage(reg, b64urlToBytes(env.pow.nonce)))
48
+ * return meetsDifficulty(h, bits)
49
+ * ```
50
+ *
51
+ * The preimage binds `(topicId, tier, participantCoord, timestamp)` (via {@link bootstrapBoundImage}),
52
+ * so a PoW minted for one topic / peer / time cannot bootstrap another. Any absent `pow`, malformed
53
+ * envelope, or non-base64url nonce → `false` (fails closed).
54
+ */
55
+ export declare function createPoWVerifier(deps: PoWVerifierDeps): (reg: RegisterV1) => boolean;
56
+ /** Inputs to {@link createReputationVerifier}. */
57
+ export interface ReputationVerifierDeps {
58
+ /** Local reputation view the referee is scored against (not banned + below the threshold). */
59
+ readonly reputation: BootstrapReputationView;
60
+ /** Strict "sufficient reputation" cutoff. Default {@link DEFAULT_DEPRIORITIZE_THRESHOLD}. */
61
+ readonly deprioritizeThreshold?: number;
62
+ }
63
+ /**
64
+ * A real reputation-endorsement verifier: a *referee* peer endorses the bootstrap by peer-key-signing
65
+ * the {@link bootstrapBoundImage}, and the cohort checks the signature **and** that the referee is
66
+ * sufficiently reputable in the **local** reputation view.
67
+ *
68
+ * ```
69
+ * env = parseBootstrapEvidenceEnvelope(reg); if (!env?.reputation) return false
70
+ * refereeBytes = b64urlToBytes(env.reputation.referee)
71
+ * if (!verifyPeerSig(refereeBytes, bootstrapBoundImage(reg), b64urlToBytes(env.reputation.sig))) return false
72
+ * refereeId = bytesToPeerIdString(refereeBytes)
73
+ * return !reputation.isBanned(refereeId) && reputation.getScore(refereeId) < deprioritizeThreshold
74
+ * ```
75
+ *
76
+ * The `referee` MAY equal the participant (a reputable participant self-vouches with its own peer key).
77
+ * An unknown referee scores `0` (a clean, unseen peer) and so is sufficient; a referee exactly *at* the
78
+ * threshold is not (strict `<`). Bad sig / banned / over-threshold / malformed → `false` (fails closed).
79
+ */
80
+ export declare function createReputationVerifier(deps: ReputationVerifierDeps): (reg: RegisterV1) => boolean;
81
+ //# sourceMappingURL=bootstrap-evidence-verifiers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap-evidence-verifiers.d.ts","sourceRoot":"","sources":["../../../src/cohort-topic/bootstrap-evidence-verifiers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAON,KAAK,SAAS,EACd,KAAK,UAAU,EACf,MAAM,qBAAqB,CAAC;AAK7B;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACvC,kFAAkF;IAClF,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAClC,2FAA2F;IAC3F,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CACjC;AAED;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,QAAkC,CAAC;AAE9E,2CAA2C;AAC3C,MAAM,WAAW,eAAe;IAC/B,kGAAkG;IAClG,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,4GAA4G;IAC5G,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,GAAG,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,CAcrF;AAED,kDAAkD;AAClD,MAAM,WAAW,sBAAsB;IACtC,8FAA8F;IAC9F,QAAQ,CAAC,UAAU,EAAE,uBAAuB,CAAC;IAC7C,6FAA6F;IAC7F,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;CACxC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,sBAAsB,GAAG,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,CAmBnG"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Cohort-topic substrate — real bootstrap-evidence verifiers (db-p2p side of the anti-DoS gate).
3
+ *
4
+ * db-core owns the *policy* (which evidence kinds satisfy which tier) and the crypto-free envelope /
5
+ * bound-image / PoW-preimage helpers (`antidos/bootstrap-evidence-envelope.ts`); it deliberately embeds
6
+ * no specific PoW or reputation scheme. This module supplies the **self-contained cryptographic checks**
7
+ * the host injects into `createBootstrapEvidence`, binding the node's `RingHash` (the same SHA-256 the
8
+ * addressing uses) and the cohort-topic peer-key `verifyPeerSig` — no new crypto dependency.
9
+ *
10
+ * Both verifiers are **synchronous** (one hash, or one signature verify + two reputation-map reads) and
11
+ * **total** — any parse / decode / verify failure on attacker-supplied input yields `false`, never a
12
+ * throw — because `BootstrapEvidence.verify` runs inside `member-engine.ts`'s `runGuards` on every
13
+ * register and must do no network I/O (that would itself be a DoS amplifier).
14
+ */
15
+ import { parseBootstrapEvidenceEnvelope, powPreimage, bootstrapBoundImage, meetsDifficulty, DEFAULT_POW_DIFFICULTY_BITS, b64urlToBytes, } from "@optimystic/db-core";
16
+ import { DEFAULT_THRESHOLDS } from "../reputation/types.js";
17
+ import { verifyPeerSig } from "./peer-sig.js";
18
+ import { bytesToPeerIdString } from "./peer-codec.js";
19
+ /**
20
+ * The default "sufficient reputation" cutoff: a referee with `score < deprioritize` is reputable enough
21
+ * to endorse a bootstrap. Mirrors the reputation service's default `deprioritize` threshold (20) so a
22
+ * default-configured node and the gate agree on "sufficient". Strict `<`, so a referee *at* the
23
+ * threshold is not sufficient.
24
+ */
25
+ export const DEFAULT_DEPRIORITIZE_THRESHOLD = DEFAULT_THRESHOLDS.deprioritize;
26
+ /**
27
+ * A real proof-of-work verifier for the T2/T3 evidence path. Self-contained — no subsystem, one hash.
28
+ *
29
+ * ```
30
+ * env = parseBootstrapEvidenceEnvelope(reg); if (!env?.pow) return false
31
+ * h = hash.H(powPreimage(reg, b64urlToBytes(env.pow.nonce)))
32
+ * return meetsDifficulty(h, bits)
33
+ * ```
34
+ *
35
+ * The preimage binds `(topicId, tier, participantCoord, timestamp)` (via {@link bootstrapBoundImage}),
36
+ * so a PoW minted for one topic / peer / time cannot bootstrap another. Any absent `pow`, malformed
37
+ * envelope, or non-base64url nonce → `false` (fails closed).
38
+ */
39
+ export function createPoWVerifier(deps) {
40
+ const bits = deps.bits ?? DEFAULT_POW_DIFFICULTY_BITS;
41
+ return (reg) => {
42
+ try {
43
+ const env = parseBootstrapEvidenceEnvelope(reg);
44
+ if (env?.pow === undefined) {
45
+ return false; // not offered / not a PoW envelope
46
+ }
47
+ const nonce = b64urlToBytes(env.pow.nonce);
48
+ return meetsDifficulty(deps.hash.H(powPreimage(reg, nonce)), bits);
49
+ }
50
+ catch {
51
+ return false; // any decode / hash failure on attacker input → fail closed
52
+ }
53
+ };
54
+ }
55
+ /**
56
+ * A real reputation-endorsement verifier: a *referee* peer endorses the bootstrap by peer-key-signing
57
+ * the {@link bootstrapBoundImage}, and the cohort checks the signature **and** that the referee is
58
+ * sufficiently reputable in the **local** reputation view.
59
+ *
60
+ * ```
61
+ * env = parseBootstrapEvidenceEnvelope(reg); if (!env?.reputation) return false
62
+ * refereeBytes = b64urlToBytes(env.reputation.referee)
63
+ * if (!verifyPeerSig(refereeBytes, bootstrapBoundImage(reg), b64urlToBytes(env.reputation.sig))) return false
64
+ * refereeId = bytesToPeerIdString(refereeBytes)
65
+ * return !reputation.isBanned(refereeId) && reputation.getScore(refereeId) < deprioritizeThreshold
66
+ * ```
67
+ *
68
+ * The `referee` MAY equal the participant (a reputable participant self-vouches with its own peer key).
69
+ * An unknown referee scores `0` (a clean, unseen peer) and so is sufficient; a referee exactly *at* the
70
+ * threshold is not (strict `<`). Bad sig / banned / over-threshold / malformed → `false` (fails closed).
71
+ */
72
+ export function createReputationVerifier(deps) {
73
+ const threshold = deps.deprioritizeThreshold ?? DEFAULT_DEPRIORITIZE_THRESHOLD;
74
+ return (reg) => {
75
+ try {
76
+ const env = parseBootstrapEvidenceEnvelope(reg);
77
+ if (env?.reputation === undefined) {
78
+ return false; // not offered / not a reputation envelope
79
+ }
80
+ const refereeBytes = b64urlToBytes(env.reputation.referee);
81
+ const sig = b64urlToBytes(env.reputation.sig);
82
+ if (!verifyPeerSig(refereeBytes, bootstrapBoundImage(reg), sig)) {
83
+ return false; // signature does not bind this register's tuple to the referee key
84
+ }
85
+ const refereeId = bytesToPeerIdString(refereeBytes);
86
+ return !deps.reputation.isBanned(refereeId) && deps.reputation.getScore(refereeId) < threshold;
87
+ }
88
+ catch {
89
+ return false; // any decode / verify failure on attacker input → fail closed
90
+ }
91
+ };
92
+ }
93
+ //# sourceMappingURL=bootstrap-evidence-verifiers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap-evidence-verifiers.js","sourceRoot":"","sources":["../../../src/cohort-topic/bootstrap-evidence-verifiers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACN,8BAA8B,EAC9B,WAAW,EACX,mBAAmB,EACnB,eAAe,EACf,2BAA2B,EAC3B,aAAa,GAGb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAetD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,kBAAkB,CAAC,YAAY,CAAC;AAU9E;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAqB;IACtD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,2BAA2B,CAAC;IACtD,OAAO,CAAC,GAAe,EAAW,EAAE;QACnC,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,8BAA8B,CAAC,GAAG,CAAC,CAAC;YAChD,IAAI,GAAG,EAAE,GAAG,KAAK,SAAS,EAAE,CAAC;gBAC5B,OAAO,KAAK,CAAC,CAAC,mCAAmC;YAClD,CAAC;YACD,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAC3C,OAAO,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACpE,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,KAAK,CAAC,CAAC,4DAA4D;QAC3E,CAAC;IACF,CAAC,CAAC;AACH,CAAC;AAUD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAA4B;IACpE,MAAM,SAAS,GAAG,IAAI,CAAC,qBAAqB,IAAI,8BAA8B,CAAC;IAC/E,OAAO,CAAC,GAAe,EAAW,EAAE;QACnC,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,8BAA8B,CAAC,GAAG,CAAC,CAAC;YAChD,IAAI,GAAG,EAAE,UAAU,KAAK,SAAS,EAAE,CAAC;gBACnC,OAAO,KAAK,CAAC,CAAC,0CAA0C;YACzD,CAAC;YACD,MAAM,YAAY,GAAG,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YAC3D,MAAM,GAAG,GAAG,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YAC9C,IAAI,CAAC,aAAa,CAAC,YAAY,EAAE,mBAAmB,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;gBACjE,OAAO,KAAK,CAAC,CAAC,mEAAmE;YAClF,CAAC;YACD,MAAM,SAAS,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAC;YACpD,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC;QAChG,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,KAAK,CAAC,CAAC,8DAA8D;QAC7E,CAAC;IACF,CAAC,CAAC;AACH,CAAC"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Cohort-topic substrate — real signed-parent-reference bootstrap-evidence verifier (db-p2p side).
3
+ *
4
+ * The committed-work proxy for the no-proof-of-work path: a `bootstrap: true` register carries a **signed
5
+ * reference to a parent topic that actually exists**, and the cohort admits it only after confirming the
6
+ * parent topic exists in locally-available committed / membership state. This is the *only* accepted
7
+ * evidence for the committed tiers (T0/T1) and the third option for T2/T3 (`PoW || reputation || parent-ref`).
8
+ *
9
+ * It replaces the interim reputation stand-in for `verifyParentReference` that
10
+ * `cohort-topic-bootstrap-evidence-verifiers` left in `host.ts`.
11
+ *
12
+ * The verifier is **synchronous** (it runs in `member-engine.ts`'s `runGuards` on every register) and
13
+ * **total** (any parse / decode / verify failure on attacker input yields `false`, never a throw). The
14
+ * existence check therefore consults a **synchronous local view** — never a network fetch, which inside an
15
+ * admission gate would itself be a DoS amplifier.
16
+ *
17
+ * Two independent checks, both must pass (`docs/cohort-topic.md` §Anti-DoS bullet 4):
18
+ *
19
+ * 1. **Signed reference (anti-replay).** The participant peer-key-signs the {@link parentRefSigningImage}
20
+ * — the bound tuple extended with `parentTopicId` — so a reference minted for one
21
+ * `(topic, tier, peer, time, parent)` cannot be lifted onto another register. Verified against the
22
+ * participant's own peer key, so it stands alone even in key-less mode (where the outer register
23
+ * signature is absent).
24
+ * 2. **Existence.** The referenced parent topic must exist in locally-available committed / membership
25
+ * state, via the injectable synchronous {@link BootstrapParentTopicView}.
26
+ *
27
+ * A node only admits a parent-ref bootstrap for a parent topic it has *locally cached* a cert/commit for
28
+ * (fail-closed when unknown). That is acceptable for an admission gate: a participant whose parent the node
29
+ * does not know retries / uses PoW (T2/T3); a genuinely-new committed (T0/T1) topic is bootstrapped by
30
+ * nodes that already serve the parent's committed work, which hold its cert. A *richer* check — that the
31
+ * parent's commit certificate names *this* child topic — is the follow-on
32
+ * `cohort-topic-parent-ref-tx-log-content`, not this module.
33
+ */
34
+ import { type RegisterV1, type RingCoord } from "@optimystic/db-core";
35
+ /**
36
+ * A synchronous local view answering "does this node locally know parent topic `parentTopicId` exists?".
37
+ * Backed (in the host default) by the committed / FRET membership state the node already holds — never a
38
+ * network lookup (a round-trip inside an admission gate is a DoS amplifier).
39
+ */
40
+ export interface BootstrapParentTopicView {
41
+ /**
42
+ * True iff the node locally knows parent topic `parentTopicId` exists (a committed cohort serves it /
43
+ * its membership cert is cached) for a cohort at `tier`. `tier` is the registering child's tier and
44
+ * routes the lookup to the committed (T0/T1) or FRET (T2/T3) backing, mirroring the membership source.
45
+ */
46
+ exists(parentTopicId: Uint8Array, tier: number): boolean;
47
+ }
48
+ /** Inputs to {@link createParentReferenceVerifier}. */
49
+ export interface ParentReferenceVerifierDeps {
50
+ /** The synchronous local existence view the verifier consults (no network I/O). */
51
+ readonly parentTopicView: BootstrapParentTopicView;
52
+ }
53
+ /**
54
+ * The real, all-tiers `verifyParentReference(reg) => boolean`. Total and synchronous:
55
+ *
56
+ * ```
57
+ * env = parseBootstrapEvidenceEnvelope(reg); if (!env?.parentRef) return false
58
+ * if (parentRef.parentTopicId === reg.topicId) return false // a topic cannot vouch for itself
59
+ * if (!verifyPeerSig(participantCoord, parentRefSigningImage(reg, parentTopicId), parentRef.sig)) return false
60
+ * return parentTopicView.exists(parentTopicId, reg.tier)
61
+ * ```
62
+ *
63
+ * - Absent `parentRef`, a malformed envelope, a bad/non-base64url signature, or an unknown parent → `false`
64
+ * (fails closed → `unwilling_cohort`).
65
+ * - The self-referential guard rejects `parentTopicId === reg.topicId`: a topic cannot reference itself to
66
+ * prove its own existence (a circular bootstrap).
67
+ */
68
+ export declare function createParentReferenceVerifier(deps: ParentReferenceVerifierDeps): (reg: RegisterV1) => boolean;
69
+ /** A synchronous local "is a cohort cached for this coord?" read — the {@link FretMembershipSource} cache shape. */
70
+ export interface LocalCohortExistence {
71
+ /** True iff a `MembershipCertV1` is locally cached for `coord`. */
72
+ has(coord: RingCoord): boolean;
73
+ }
74
+ /** Inputs to {@link createDefaultParentTopicView}. */
75
+ export interface DefaultParentTopicViewDeps {
76
+ /** The FRET membership cache (T2/T3 backing): a cached cert means a cohort genuinely serves the parent. */
77
+ readonly membershipSource: LocalCohortExistence;
78
+ /** Tier addressing — supplies `coord0(parentTopicId)`, the parent topic's root cohort coordinate. */
79
+ readonly addressing: {
80
+ coord0(topicId: Uint8Array): RingCoord;
81
+ };
82
+ /**
83
+ * Optional committed-state backing for the committed tiers (T0/T1). Reads `coord_0(parentTopicId)`. When
84
+ * **omitted the committed tiers fail closed** (return `false`) — a FRET-cached cert (T2/T3 membership)
85
+ * must NOT vouch for committed-tier parent existence (committed-tier integrity). A node supplies a real
86
+ * committed-by-coord reader (e.g. a future tx-log / commit-cert index) here when one is available.
87
+ */
88
+ readonly committedReader?: (coord: RingCoord) => boolean;
89
+ /** Highest tier exempt from PoW / served by committed work (T0/T1 → 1). Default {@link DEFAULT_MAX_NO_POW_TIER}. */
90
+ readonly maxNoPowTier?: number;
91
+ }
92
+ /**
93
+ * The host-default {@link BootstrapParentTopicView}, tier-routed exactly like the membership source
94
+ * (`docs/cohort-topic.md` §Membership source):
95
+ *
96
+ * - **T0/T1 (committed tiers):** consult `committedReader` — the committed-state backing. Absent → `false`
97
+ * (fail closed). A FRET-cached cert never satisfies a committed-tier existence check, so committed-tier
98
+ * integrity holds: a parent known only as a FRET (T2/T3) cohort cannot back a committed parent reference.
99
+ * - **T2/T3:** `membershipSource.has(coord_0(parentTopicId))` — a cached `MembershipCertV1` means a cohort
100
+ * is genuinely serving the parent topic.
101
+ *
102
+ * **Known limitation (interim).** No coord-keyed committed-membership index exists yet (the transaction-log
103
+ * commit certificate is keyed by action, not by `coord_0`), so a node typically wires no `committedReader`
104
+ * and T0/T1 parent-ref existence fails closed. T2/T3 parent-ref is fully real today. The dedicated committed
105
+ * backing is the follow-on `cohort-topic-parent-ref-tx-log-content`.
106
+ */
107
+ export declare function createDefaultParentTopicView(deps: DefaultParentTopicViewDeps): BootstrapParentTopicView;
108
+ //# sourceMappingURL=bootstrap-parent-reference.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap-parent-reference.d.ts","sourceRoot":"","sources":["../../../src/cohort-topic/bootstrap-parent-reference.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EAKN,KAAK,UAAU,EACf,KAAK,SAAS,EACd,MAAM,qBAAqB,CAAC;AAG7B;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACxC;;;;OAIG;IACH,MAAM,CAAC,aAAa,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CACzD;AAED,uDAAuD;AACvD,MAAM,WAAW,2BAA2B;IAC3C,mFAAmF;IACnF,QAAQ,CAAC,eAAe,EAAE,wBAAwB,CAAC;CACnD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,2BAA2B,GAAG,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,CAwB7G;AAED,oHAAoH;AACpH,MAAM,WAAW,oBAAoB;IACpC,mEAAmE;IACnE,GAAG,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC;CAC/B;AAED,sDAAsD;AACtD,MAAM,WAAW,0BAA0B;IAC1C,2GAA2G;IAC3G,QAAQ,CAAC,gBAAgB,EAAE,oBAAoB,CAAC;IAChD,qGAAqG;IACrG,QAAQ,CAAC,UAAU,EAAE;QAAE,MAAM,CAAC,OAAO,EAAE,UAAU,GAAG,SAAS,CAAA;KAAE,CAAC;IAChE;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC;IACzD,oHAAoH;IACpH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,0BAA0B,GAAG,wBAAwB,CAevG"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Cohort-topic substrate — real signed-parent-reference bootstrap-evidence verifier (db-p2p side).
3
+ *
4
+ * The committed-work proxy for the no-proof-of-work path: a `bootstrap: true` register carries a **signed
5
+ * reference to a parent topic that actually exists**, and the cohort admits it only after confirming the
6
+ * parent topic exists in locally-available committed / membership state. This is the *only* accepted
7
+ * evidence for the committed tiers (T0/T1) and the third option for T2/T3 (`PoW || reputation || parent-ref`).
8
+ *
9
+ * It replaces the interim reputation stand-in for `verifyParentReference` that
10
+ * `cohort-topic-bootstrap-evidence-verifiers` left in `host.ts`.
11
+ *
12
+ * The verifier is **synchronous** (it runs in `member-engine.ts`'s `runGuards` on every register) and
13
+ * **total** (any parse / decode / verify failure on attacker input yields `false`, never a throw). The
14
+ * existence check therefore consults a **synchronous local view** — never a network fetch, which inside an
15
+ * admission gate would itself be a DoS amplifier.
16
+ *
17
+ * Two independent checks, both must pass (`docs/cohort-topic.md` §Anti-DoS bullet 4):
18
+ *
19
+ * 1. **Signed reference (anti-replay).** The participant peer-key-signs the {@link parentRefSigningImage}
20
+ * — the bound tuple extended with `parentTopicId` — so a reference minted for one
21
+ * `(topic, tier, peer, time, parent)` cannot be lifted onto another register. Verified against the
22
+ * participant's own peer key, so it stands alone even in key-less mode (where the outer register
23
+ * signature is absent).
24
+ * 2. **Existence.** The referenced parent topic must exist in locally-available committed / membership
25
+ * state, via the injectable synchronous {@link BootstrapParentTopicView}.
26
+ *
27
+ * A node only admits a parent-ref bootstrap for a parent topic it has *locally cached* a cert/commit for
28
+ * (fail-closed when unknown). That is acceptable for an admission gate: a participant whose parent the node
29
+ * does not know retries / uses PoW (T2/T3); a genuinely-new committed (T0/T1) topic is bootstrapped by
30
+ * nodes that already serve the parent's committed work, which hold its cert. A *richer* check — that the
31
+ * parent's commit certificate names *this* child topic — is the follow-on
32
+ * `cohort-topic-parent-ref-tx-log-content`, not this module.
33
+ */
34
+ import { parseBootstrapEvidenceEnvelope, parentRefSigningImage, DEFAULT_MAX_NO_POW_TIER, b64urlToBytes, } from "@optimystic/db-core";
35
+ import { verifyPeerSig } from "./peer-sig.js";
36
+ /**
37
+ * The real, all-tiers `verifyParentReference(reg) => boolean`. Total and synchronous:
38
+ *
39
+ * ```
40
+ * env = parseBootstrapEvidenceEnvelope(reg); if (!env?.parentRef) return false
41
+ * if (parentRef.parentTopicId === reg.topicId) return false // a topic cannot vouch for itself
42
+ * if (!verifyPeerSig(participantCoord, parentRefSigningImage(reg, parentTopicId), parentRef.sig)) return false
43
+ * return parentTopicView.exists(parentTopicId, reg.tier)
44
+ * ```
45
+ *
46
+ * - Absent `parentRef`, a malformed envelope, a bad/non-base64url signature, or an unknown parent → `false`
47
+ * (fails closed → `unwilling_cohort`).
48
+ * - The self-referential guard rejects `parentTopicId === reg.topicId`: a topic cannot reference itself to
49
+ * prove its own existence (a circular bootstrap).
50
+ */
51
+ export function createParentReferenceVerifier(deps) {
52
+ const { parentTopicView } = deps;
53
+ return (reg) => {
54
+ try {
55
+ const env = parseBootstrapEvidenceEnvelope(reg);
56
+ if (env?.parentRef === undefined) {
57
+ return false; // not offered / not a parent-reference envelope
58
+ }
59
+ const { parentTopicId, sig } = env.parentRef;
60
+ // A topic cannot vouch for its own existence (self-referential / circular bootstrap).
61
+ if (parentTopicId === reg.topicId) {
62
+ return false;
63
+ }
64
+ // 1. Signed reference (anti-replay): the participant binds THIS parent to THIS register.
65
+ const image = parentRefSigningImage(reg, parentTopicId);
66
+ if (!verifyPeerSig(b64urlToBytes(reg.participantCoord), image, b64urlToBytes(sig))) {
67
+ return false;
68
+ }
69
+ // 2. Existence: the parent topic must exist in locally-available committed / membership state.
70
+ return parentTopicView.exists(b64urlToBytes(parentTopicId), reg.tier);
71
+ }
72
+ catch {
73
+ return false; // any decode / verify failure on attacker input → fail closed
74
+ }
75
+ };
76
+ }
77
+ /**
78
+ * The host-default {@link BootstrapParentTopicView}, tier-routed exactly like the membership source
79
+ * (`docs/cohort-topic.md` §Membership source):
80
+ *
81
+ * - **T0/T1 (committed tiers):** consult `committedReader` — the committed-state backing. Absent → `false`
82
+ * (fail closed). A FRET-cached cert never satisfies a committed-tier existence check, so committed-tier
83
+ * integrity holds: a parent known only as a FRET (T2/T3) cohort cannot back a committed parent reference.
84
+ * - **T2/T3:** `membershipSource.has(coord_0(parentTopicId))` — a cached `MembershipCertV1` means a cohort
85
+ * is genuinely serving the parent topic.
86
+ *
87
+ * **Known limitation (interim).** No coord-keyed committed-membership index exists yet (the transaction-log
88
+ * commit certificate is keyed by action, not by `coord_0`), so a node typically wires no `committedReader`
89
+ * and T0/T1 parent-ref existence fails closed. T2/T3 parent-ref is fully real today. The dedicated committed
90
+ * backing is the follow-on `cohort-topic-parent-ref-tx-log-content`.
91
+ */
92
+ export function createDefaultParentTopicView(deps) {
93
+ const { membershipSource, addressing, committedReader } = deps;
94
+ const maxNoPowTier = deps.maxNoPowTier ?? DEFAULT_MAX_NO_POW_TIER;
95
+ return {
96
+ exists(parentTopicId, tier) {
97
+ const coord = addressing.coord0(parentTopicId);
98
+ if (tier <= maxNoPowTier) {
99
+ // Committed tiers (T0/T1): require a committed backing; fail closed without one. The FRET cache
100
+ // must not vouch for committed-tier existence (committed-tier integrity).
101
+ return committedReader !== undefined && committedReader(coord);
102
+ }
103
+ // T2/T3: the FRET membership cache reflects a cohort serving the parent topic.
104
+ return membershipSource.has(coord);
105
+ },
106
+ };
107
+ }
108
+ //# sourceMappingURL=bootstrap-parent-reference.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap-parent-reference.js","sourceRoot":"","sources":["../../../src/cohort-topic/bootstrap-parent-reference.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EACN,8BAA8B,EAC9B,qBAAqB,EACrB,uBAAuB,EACvB,aAAa,GAGb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAsB9C;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,6BAA6B,CAAC,IAAiC;IAC9E,MAAM,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC;IACjC,OAAO,CAAC,GAAe,EAAW,EAAE;QACnC,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,8BAA8B,CAAC,GAAG,CAAC,CAAC;YAChD,IAAI,GAAG,EAAE,SAAS,KAAK,SAAS,EAAE,CAAC;gBAClC,OAAO,KAAK,CAAC,CAAC,gDAAgD;YAC/D,CAAC;YACD,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,SAAS,CAAC;YAC7C,sFAAsF;YACtF,IAAI,aAAa,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC;gBACnC,OAAO,KAAK,CAAC;YACd,CAAC;YACD,yFAAyF;YACzF,MAAM,KAAK,GAAG,qBAAqB,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;YACxD,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;gBACpF,OAAO,KAAK,CAAC;YACd,CAAC;YACD,+FAA+F;YAC/F,OAAO,eAAe,CAAC,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QACvE,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,KAAK,CAAC,CAAC,8DAA8D;QAC7E,CAAC;IACF,CAAC,CAAC;AACH,CAAC;AAyBD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,4BAA4B,CAAC,IAAgC;IAC5E,MAAM,EAAE,gBAAgB,EAAE,UAAU,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC;IAC/D,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,uBAAuB,CAAC;IAClE,OAAO;QACN,MAAM,CAAC,aAAyB,EAAE,IAAY;YAC7C,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;YAC/C,IAAI,IAAI,IAAI,YAAY,EAAE,CAAC;gBAC1B,gGAAgG;gBAChG,0EAA0E;gBAC1E,OAAO,eAAe,KAAK,SAAS,IAAI,eAAe,CAAC,KAAK,CAAC,CAAC;YAChE,CAAC;YACD,+EAA+E;YAC/E,OAAO,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;KACD,CAAC;AACH,CAAC"}
@@ -0,0 +1,65 @@
1
+ import type { CohortTopicService, CollectionChangeEvent, CollectionChangeListener, CommitCert, IBlockChangeNotifier } from "@optimystic/db-core";
2
+ /**
3
+ * The local commit feed the bridge observes: a {@link IBlockChangeNotifier} (the node's
4
+ * `StorageRepo`) extended with the catch-all {@link onAnyCollectionChange} the bridge needs to see
5
+ * EVERY commit — it cannot enumerate collection ids ahead of time to subscribe per-collection, and
6
+ * origination must fire whether or not anyone subscribed to that collection.
7
+ */
8
+ export interface ChangeBridgeSource extends IBlockChangeNotifier {
9
+ onAnyCollectionChange(listener: CollectionChangeListener): () => void;
10
+ }
11
+ export interface CohortTopicChangeNotifierDeps {
12
+ /** The local node's commit feed (its `StorageRepo`). */
13
+ readonly source: ChangeBridgeSource;
14
+ /** The cohort-topic substrate whose `onLocalCommit` origination hook receives member commits. */
15
+ readonly service: CohortTopicService;
16
+ /**
17
+ * True iff this node is a cohort member responsible for this change event's reactivity-topic fan-out.
18
+ * Receives the whole {@link CollectionChangeEvent} (not just the collection id) because the reactivity
19
+ * topic is tail-anchored — `H(event.tailId ‖ "reactivity")` — so the gate needs `event.tailId` to
20
+ * derive the topic's `coord_0` cohort. A tail-less event (a read-driven promotion) is never a member.
21
+ */
22
+ readonly selfIsCohortMember: (event: CollectionChangeEvent) => boolean;
23
+ /** Resolve the pass-through commit cert for a change event (e.g. the cluster commit-cert store). */
24
+ readonly extractCommitCert: (event: CollectionChangeEvent) => CommitCert | undefined;
25
+ }
26
+ /**
27
+ * The reactivity/matchmaking **origination point**: bridge the local single-node change-notifier
28
+ * primitive into the networked cohort-topic substrate.
29
+ *
30
+ * On EVERY commit landing on this node (via the catch-all {@link ChangeBridgeSource.onAnyCollectionChange}
31
+ * feed), if this node is a cohort member for the collection's reactivity topic, the bridge hands the
32
+ * `CollectionChangeEvent` plus the pass-through {@link CommitCert} to `service.onLocalCommit` —
33
+ * reactivity reuses the commit cert's threshold signature directly and never re-signs. A commit on a
34
+ * non-member node (no fan-out responsibility) or one for which no cert is retained (nothing
35
+ * authoritative to forward) is a no-op. A throwing downstream hook is isolated + logged so
36
+ * origination can never break the commit (matching the {@link IBlockChangeNotifier} listener contract).
37
+ *
38
+ * The returned value IS an {@link IBlockChangeNotifier}: it is what `network-transactor` takes as its
39
+ * `localChangeNotifier`, so per-collection {@link IBlockChangeNotifier.onCollectionChange} subscribers
40
+ * (e.g. the Quereus reactive-watch vtab) keep working — those subscriptions delegate straight to
41
+ * `source`. Origination runs independently on the catch-all feed.
42
+ *
43
+ * `makeCohortTopicChangeNotifier` discards the catch-all unsubscribe (node-lifetime by intent) for the
44
+ * unit tests; the node assembly uses {@link attachCohortChangeBridge}, which returns the teardown.
45
+ */
46
+ export declare function makeCohortTopicChangeNotifier(deps: CohortTopicChangeNotifierDeps): IBlockChangeNotifier;
47
+ /**
48
+ * Wire the cohort-topic origination bridge as `node`'s `blockChangeNotifier` (the value the
49
+ * `NetworkTransactor` consumes as its `localChangeNotifier`). Call this from the node assembly once a
50
+ * {@link CohortTopicService} is running on the node, passing the node's `StorageRepo` as `source` and
51
+ * the membership + cert-extraction seams.
52
+ *
53
+ * Returns the installed `notifier` plus an idempotent `unsubscribe` that tears down the catch-all
54
+ * origination subscription — the node assembly calls it on node stop (alongside `host.stop()`) so the
55
+ * origination feed is released before the node's transports close. Tearing it down stops further
56
+ * origination but leaves the per-collection `onCollectionChange` delegation intact (those subscriptions
57
+ * live on the `source` `StorageRepo`, not on the bridge).
58
+ */
59
+ export declare function attachCohortChangeBridge(node: {
60
+ blockChangeNotifier?: IBlockChangeNotifier;
61
+ }, deps: CohortTopicChangeNotifierDeps): {
62
+ notifier: IBlockChangeNotifier;
63
+ unsubscribe: () => void;
64
+ };
65
+ //# sourceMappingURL=change-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"change-bridge.d.ts","sourceRoot":"","sources":["../../../src/cohort-topic/change-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAKjJ;;;;;GAKG;AACH,MAAM,WAAW,kBAAmB,SAAQ,oBAAoB;IAC/D,qBAAqB,CAAC,QAAQ,EAAE,wBAAwB,GAAG,MAAM,IAAI,CAAC;CACtE;AAED,MAAM,WAAW,6BAA6B;IAC7C,wDAAwD;IACxD,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC,iGAAiG;IACjG,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,OAAO,CAAC;IACvE,oGAAoG;IACpG,QAAQ,CAAC,iBAAiB,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,UAAU,GAAG,SAAS,CAAC;CACrF;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,6BAA6B,GAAG,oBAAoB,CAEvG;AAoCD;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CACvC,IAAI,EAAE;IAAE,mBAAmB,CAAC,EAAE,oBAAoB,CAAA;CAAE,EACpD,IAAI,EAAE,6BAA6B,GACjC;IAAE,QAAQ,EAAE,oBAAoB,CAAC;IAAC,WAAW,EAAE,MAAM,IAAI,CAAA;CAAE,CAI7D"}