@optimystic/db-p2p 0.13.5 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (342) 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 +7 -0
  134. package/dist/src/libp2p-key-network.d.ts.map +1 -1
  135. package/dist/src/libp2p-key-network.js +49 -5
  136. package/dist/src/libp2p-key-network.js.map +1 -1
  137. package/dist/src/libp2p-node-base.d.ts +45 -3
  138. package/dist/src/libp2p-node-base.d.ts.map +1 -1
  139. package/dist/src/libp2p-node-base.js +522 -5
  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 +13 -0
  186. package/dist/src/protocol-client.d.ts.map +1 -1
  187. package/dist/src/protocol-client.js +74 -2
  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 -23
  235. package/dist/src/repo/client.js.map +1 -1
  236. package/dist/src/repo/service.d.ts +46 -1
  237. package/dist/src/repo/service.d.ts.map +1 -1
  238. package/dist/src/repo/service.js +79 -45
  239. package/dist/src/repo/service.js.map +1 -1
  240. package/dist/src/rpc-deadline.d.ts +37 -0
  241. package/dist/src/rpc-deadline.d.ts.map +1 -0
  242. package/dist/src/rpc-deadline.js +31 -0
  243. package/dist/src/rpc-deadline.js.map +1 -0
  244. package/dist/src/storage/block-storage.d.ts +2 -0
  245. package/dist/src/storage/block-storage.d.ts.map +1 -1
  246. package/dist/src/storage/block-storage.js +95 -2
  247. package/dist/src/storage/block-storage.js.map +1 -1
  248. package/dist/src/storage/i-block-storage.d.ts +25 -0
  249. package/dist/src/storage/i-block-storage.d.ts.map +1 -1
  250. package/dist/src/storage/storage-repo.d.ts +53 -2
  251. package/dist/src/storage/storage-repo.d.ts.map +1 -1
  252. package/dist/src/storage/storage-repo.js +193 -9
  253. package/dist/src/storage/storage-repo.js.map +1 -1
  254. package/dist/src/sync/client.d.ts +4 -1
  255. package/dist/src/sync/client.d.ts.map +1 -1
  256. package/dist/src/sync/client.js +5 -2
  257. package/dist/src/sync/client.js.map +1 -1
  258. package/dist/src/testing/cohort-topic-mesh-harness.d.ts +219 -0
  259. package/dist/src/testing/cohort-topic-mesh-harness.d.ts.map +1 -0
  260. package/dist/src/testing/cohort-topic-mesh-harness.js +467 -0
  261. package/dist/src/testing/cohort-topic-mesh-harness.js.map +1 -0
  262. package/dist/src/testing/matchmaking-mesh-harness.d.ts +187 -0
  263. package/dist/src/testing/matchmaking-mesh-harness.d.ts.map +1 -0
  264. package/dist/src/testing/matchmaking-mesh-harness.js +358 -0
  265. package/dist/src/testing/matchmaking-mesh-harness.js.map +1 -0
  266. package/dist/src/testing/mesh-harness.d.ts.map +1 -1
  267. package/dist/src/testing/mesh-harness.js +23 -1
  268. package/dist/src/testing/mesh-harness.js.map +1 -1
  269. package/dist/src/testing/reactivity-mesh-harness.d.ts +298 -0
  270. package/dist/src/testing/reactivity-mesh-harness.d.ts.map +1 -0
  271. package/dist/src/testing/reactivity-mesh-harness.js +663 -0
  272. package/dist/src/testing/reactivity-mesh-harness.js.map +1 -0
  273. package/package.json +7 -4
  274. package/src/cluster/block-transfer-service.ts +133 -68
  275. package/src/cluster/client.ts +64 -45
  276. package/src/cluster/cluster-error.ts +64 -0
  277. package/src/cluster/cluster-repo.ts +405 -55
  278. package/src/cluster/commit-cert.ts +139 -0
  279. package/src/cluster/service.ts +116 -44
  280. package/src/cluster/spread-on-churn.ts +328 -285
  281. package/src/cohort-topic/bootstrap-evidence-builder.ts +122 -0
  282. package/src/cohort-topic/bootstrap-evidence-verifiers.ts +132 -0
  283. package/src/cohort-topic/bootstrap-parent-reference.ts +159 -0
  284. package/src/cohort-topic/change-bridge.ts +109 -0
  285. package/src/cohort-topic/cohort-gossip-driver.ts +144 -0
  286. package/src/cohort-topic/cohort-gossip-transport.ts +74 -0
  287. package/src/cohort-topic/fret-trust-anchor.ts +153 -0
  288. package/src/cohort-topic/host.ts +2175 -0
  289. package/src/cohort-topic/index.ts +13 -0
  290. package/src/cohort-topic/membership-publish-sink.ts +20 -0
  291. package/src/cohort-topic/membership-source.ts +68 -0
  292. package/src/cohort-topic/peer-codec.ts +31 -0
  293. package/src/cohort-topic/peer-sig.ts +86 -0
  294. package/src/cohort-topic/protocols.ts +71 -0
  295. package/src/cohort-topic/reactivity-membership-gate.ts +77 -0
  296. package/src/cohort-topic/size-estimator.ts +16 -0
  297. package/src/cohort-topic/stream-util.ts +87 -0
  298. package/src/cohort-topic/threshold-crypto.ts +239 -0
  299. package/src/cohort-topic/topic-router.ts +77 -0
  300. package/src/dispute/cascade.ts +517 -0
  301. package/src/dispute/client.ts +12 -2
  302. package/src/dispute/dispute-service.ts +171 -24
  303. package/src/dispute/index.ts +42 -0
  304. package/src/dispute/invalidation.ts +587 -0
  305. package/src/dispute/types.ts +14 -0
  306. package/src/index.ts +4 -0
  307. package/src/libp2p-key-network.ts +49 -6
  308. package/src/libp2p-node-base.ts +620 -12
  309. package/src/matchmaking/aggregate-counts.ts +104 -0
  310. package/src/matchmaking/index.ts +20 -0
  311. package/src/matchmaking/module.ts +363 -0
  312. package/src/matchmaking/protocols.ts +51 -0
  313. package/src/matchmaking/provider-manager.ts +95 -0
  314. package/src/matchmaking/query-handler.ts +88 -0
  315. package/src/matchmaking/query-transport.ts +483 -0
  316. package/src/matchmaking/seeker-manager.ts +64 -0
  317. package/src/matchmaking/seeker-walk-client.ts +293 -0
  318. package/src/matchmaking/traffic-validation.ts +195 -0
  319. package/src/network/network-manager-service.ts +9 -2
  320. package/src/protocol-client.ts +64 -3
  321. package/src/reactivity/forwarder-host.ts +438 -0
  322. package/src/reactivity/index.ts +19 -0
  323. package/src/reactivity/notify-transport.ts +144 -0
  324. package/src/reactivity/origination-manager.ts +192 -0
  325. package/src/reactivity/protocols.ts +61 -0
  326. package/src/reactivity/push-state-gossip.ts +291 -0
  327. package/src/reactivity/recover-transport.ts +408 -0
  328. package/src/reactivity/rotation-rereg-scheduler.ts +256 -0
  329. package/src/reactivity/subscriber-registry.ts +96 -0
  330. package/src/reactivity/subscription-manager.ts +450 -0
  331. package/src/reactivity/topic-bytes.ts +37 -0
  332. package/src/repo/client.ts +54 -23
  333. package/src/repo/service.ts +90 -42
  334. package/src/rpc-deadline.ts +45 -0
  335. package/src/storage/block-storage.ts +106 -3
  336. package/src/storage/i-block-storage.ts +27 -0
  337. package/src/storage/storage-repo.ts +209 -13
  338. package/src/sync/client.ts +5 -2
  339. package/src/testing/cohort-topic-mesh-harness.ts +613 -0
  340. package/src/testing/matchmaking-mesh-harness.ts +475 -0
  341. package/src/testing/mesh-harness.ts +22 -2
  342. package/src/testing/reactivity-mesh-harness.ts +922 -0
@@ -0,0 +1,139 @@
1
+ import type { ActionId, ClusterRecord, CollectionChangeEvent, CommitCert } from "@optimystic/db-core";
2
+ import { fromString as uint8ArrayFromString } from 'uint8arrays';
3
+ import { createLogger } from "../logger.js";
4
+
5
+ const log = createLogger('commit-cert');
6
+
7
+ /**
8
+ * Build the {@link CommitCert} for a consensus-committed action from its {@link ClusterRecord}.
9
+ *
10
+ * The threshold signature is the cluster's `approve` **commit** signatures — the per-member Ed25519
11
+ * commit votes the cohort already produced over the commit hash — concatenated in ascending
12
+ * signer-id order, so the blob is reproducible and `signers[i]` aligns with chunk `i` (the
13
+ * collected-multisig convention the cohort-topic verifier uses). This is the **authoritative**
14
+ * commit cert: reactivity reuses these exact bytes as a notification's signature and never re-signs.
15
+ *
16
+ * `signedPayload` is the exact byte preimage every approving member signed — the cluster commit-vote
17
+ * payload `utf8(commitHash + ":approve")`, identical across signers. The caller supplies it (this stays
18
+ * pure and does **not** recompute the commit hash, since the canonical-JSON helper that derives it is
19
+ * private to `ClusterMember` and duplicating it here risks drift). Reactivity sets a notification's
20
+ * `digest` to base64url(signedPayload) so a subscriber's threshold-verify over `digest` reproduces the
21
+ * exact signed image. Pure.
22
+ */
23
+ export function buildCommitCert(record: ClusterRecord, minSigs: number, signedPayload: Uint8Array): CommitCert {
24
+ const approvals = Object.entries(record.commits)
25
+ .filter(([, sig]) => sig.type === 'approve')
26
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
27
+ const signers = approvals.map(([peerId]) => peerId);
28
+ const thresholdSig = concatBytes(approvals.map(([, sig]) => uint8ArrayFromString(sig.signature, 'base64url')));
29
+ return { thresholdSig, signers, minSigs, signedPayload };
30
+ }
31
+
32
+ /**
33
+ * The deterministic change-event/notification `actionId` for a durable invalidation, derived from the
34
+ * `(invalidatedActionId, disputeId)` pair that uniquely identifies the reversal. An invalidation has no
35
+ * transaction `actionId` of its own (it reverses one), but reactivity keys both the captured commit cert
36
+ * and the emitted {@link CollectionChangeEvent} by an `actionId` so the bridge's cert extractor can
37
+ * resolve the reused cert. Both the cluster member's cert capture and the invalidation-apply sink that
38
+ * emits the change event derive this same id from the same pair, closing the loop. Distinct from the
39
+ * per-block deterministic revert `actionId` in `dispute/invalidation.ts` (which also carries blockId+rev);
40
+ * this is the single transaction-level id for the whole reversal.
41
+ */
42
+ export function invalidationActionId(invalidatedActionId: ActionId, disputeId: string): ActionId {
43
+ return `inv:${invalidatedActionId}:${disputeId}`;
44
+ }
45
+
46
+ function concatBytes(parts: readonly Uint8Array[]): Uint8Array {
47
+ const total = parts.reduce((n, p) => n + p.length, 0);
48
+ const out = new Uint8Array(total);
49
+ let offset = 0;
50
+ for (const part of parts) {
51
+ out.set(part, offset);
52
+ offset += part.length;
53
+ }
54
+ return out;
55
+ }
56
+
57
+ /** Default retention for a captured commit cert — long enough for the post-commit change event to
58
+ * resolve it, short enough that the store stays bounded under sustained commit load. */
59
+ export const DEFAULT_COMMIT_CERT_TTL_MS = 60_000;
60
+
61
+ /** Default cap on retained certs — a backstop against unbounded growth if commits ever stop emitting. */
62
+ export const DEFAULT_COMMIT_CERT_MAX_ENTRIES = 4096;
63
+
64
+ /**
65
+ * Bounded, TTL'd cache of recently-committed {@link CommitCert}s keyed by `actionId`. The cluster
66
+ * member records a cert here just before consensus applies the commit to local storage; the
67
+ * change-notifier bridge's extractor reads it when the StorageRepo emits the matching
68
+ * {@link CollectionChangeEvent}. Both happen on the same node within one commit, so the window is
69
+ * tiny — but a TTL + cap keep the map from leaking if a commit ever lands without emitting a change
70
+ * event (e.g. an idempotent re-commit, or a path with no catch-all subscriber).
71
+ */
72
+ export interface CommitCertStore {
73
+ /** Record `cert` for `actionId` (overwrites any prior entry). `now` is unix ms (injectable for tests). */
74
+ put(actionId: ActionId, cert: CommitCert, now?: number): void;
75
+ /** The cert for `actionId` if still retained, else `undefined`. */
76
+ get(actionId: ActionId, now?: number): CommitCert | undefined;
77
+ }
78
+
79
+ export interface CommitCertStoreOptions {
80
+ /** Retention per entry (ms). Default {@link DEFAULT_COMMIT_CERT_TTL_MS}. */
81
+ readonly ttlMs?: number;
82
+ /** Maximum retained entries (oldest evicted first). Default {@link DEFAULT_COMMIT_CERT_MAX_ENTRIES}. */
83
+ readonly maxEntries?: number;
84
+ }
85
+
86
+ /** Build an in-memory {@link CommitCertStore} (insertion-ordered Map → recency for eviction). */
87
+ export function createCommitCertStore(options: CommitCertStoreOptions = {}): CommitCertStore {
88
+ const ttlMs = options.ttlMs ?? DEFAULT_COMMIT_CERT_TTL_MS;
89
+ const maxEntries = options.maxEntries ?? DEFAULT_COMMIT_CERT_MAX_ENTRIES;
90
+ const entries = new Map<ActionId, { cert: CommitCert; expiresAt: number }>();
91
+
92
+ const dropExpired = (now: number): void => {
93
+ for (const [actionId, entry] of entries) {
94
+ if (entry.expiresAt <= now) {
95
+ entries.delete(actionId);
96
+ }
97
+ }
98
+ };
99
+
100
+ return {
101
+ put(actionId, cert, now = Date.now()): void {
102
+ dropExpired(now);
103
+ // Re-insert so a refreshed key moves to the most-recent end (Map preserves insertion order).
104
+ entries.delete(actionId);
105
+ entries.set(actionId, { cert, expiresAt: now + ttlMs });
106
+ while (entries.size > maxEntries) {
107
+ const oldest = entries.keys().next().value;
108
+ if (oldest === undefined) break;
109
+ entries.delete(oldest);
110
+ }
111
+ },
112
+ get(actionId, now = Date.now()): CommitCert | undefined {
113
+ const entry = entries.get(actionId);
114
+ if (!entry) {
115
+ return undefined;
116
+ }
117
+ if (entry.expiresAt <= now) {
118
+ entries.delete(actionId);
119
+ return undefined;
120
+ }
121
+ return entry.cert;
122
+ },
123
+ };
124
+ }
125
+
126
+ /**
127
+ * The bridge's `extractCommitCert` over a {@link CommitCertStore}: resolve a change event's committed
128
+ * action to the cluster commit cert captured for it. Returns `undefined` (logged) when no cert is
129
+ * retained — the bridge then skips origination rather than fabricating an unsigned notification.
130
+ */
131
+ export function makeClusterCommitCertExtractor(store: CommitCertStore): (event: CollectionChangeEvent) => CommitCert | undefined {
132
+ return (event) => {
133
+ const cert = store.get(event.actionId);
134
+ if (!cert) {
135
+ log('no commit cert retained for actionId=%s (collection=%s rev=%d); skipping origination', event.actionId, event.collectionId, event.rev);
136
+ }
137
+ return cert;
138
+ };
139
+ }
@@ -1,7 +1,10 @@
1
1
  import { pipe } from 'it-pipe';
2
2
  import { decode as lpDecode, encode as lpEncode } from 'it-length-prefixed';
3
- import type { Startable, Logger, Stream, Connection, StreamHandler } from '@libp2p/interface';
3
+ import { peerIdFromString } from '@libp2p/peer-id';
4
+ import type { Startable, Logger, Stream, Connection, StreamHandler, PeerId } from '@libp2p/interface';
4
5
  import type { ICluster, ClusterRecord } from '@optimystic/db-core';
6
+ import { encodePeers, type RedirectPayload } from '../repo/redirect.js';
7
+ import { toClusterErrorEnvelope } from './cluster-error.js';
5
8
  import type { Uint8ArrayList } from 'uint8arraylist';
6
9
 
7
10
  interface BaseComponents {
@@ -14,6 +17,17 @@ interface BaseComponents {
14
17
 
15
18
  export interface ClusterServiceComponents extends BaseComponents {
16
19
  cluster: ICluster
20
+ /**
21
+ * This node's own peer id, used to decide whether we are a member of a
22
+ * cluster record's peer set. When absent the service cannot scope membership
23
+ * and processes every update locally (no redirect).
24
+ */
25
+ peerId?: PeerId
26
+ /**
27
+ * Optional resolver for a peer's dialable multiaddrs, used as a fallback when
28
+ * a redirect target has no multiaddrs embedded in `record.peers`.
29
+ */
30
+ getConnectionAddrs?: (peerId: PeerId) => string[]
17
31
  }
18
32
 
19
33
  export interface ClusterServiceInit {
@@ -22,17 +36,13 @@ export interface ClusterServiceInit {
22
36
  maxInboundStreams?: number,
23
37
  maxOutboundStreams?: number,
24
38
  logPrefix?: string,
25
- kBucketSize?: number,
26
- configuredClusterSize?: number,
27
- allowClusterDownsize?: boolean,
28
- clusterSizeTolerance?: number,
29
39
  /**
30
40
  * Responsibility K - the replica set size for determining cluster membership.
31
- * This is distinct from kBucketSize (DHT routing) and configuredClusterSize (consensus quorum).
32
- * When set, this determines how many peers (by XOR distance) are considered
33
- * responsible for a key. If this node is not in the top responsibilityK peers,
34
- * it will redirect requests to closer peers.
35
- * Default: 1 (only the closest peer handles requests)
41
+ * When the cluster record's peer set is smaller than this, the mesh is treated
42
+ * as "small" and the update is processed locally regardless of membership. When
43
+ * the peer set is at least this size and we are not a member, the update is
44
+ * redirected to the responsible peers.
45
+ * Default: 1 (only members process; any larger non-member set redirects)
36
46
  */
37
47
  responsibilityK?: number,
38
48
  }
@@ -52,6 +62,8 @@ export class ClusterService implements Startable {
52
62
  private readonly cluster: ICluster;
53
63
  private readonly components: ClusterServiceComponents;
54
64
  private running: boolean;
65
+ /** Responsibility K - small-mesh bypass threshold for redirect decisions */
66
+ private readonly responsibilityK: number;
55
67
 
56
68
  constructor(components: ClusterServiceComponents, init: ClusterServiceInit = {}) {
57
69
  this.components = components;
@@ -61,10 +73,74 @@ export class ClusterService implements Startable {
61
73
  this.log = components.logger.forComponent(init.logPrefix ?? 'db-p2p:cluster');
62
74
  this.cluster = components.cluster;
63
75
  this.running = false;
76
+ this.responsibilityK = init.responsibilityK ?? 1;
64
77
  }
65
78
 
66
79
  readonly [Symbol.toStringTag] = '@libp2p/cluster';
67
80
 
81
+ private getSelfId(): PeerId | undefined {
82
+ if (this.components.peerId) return this.components.peerId;
83
+ return (this.components as any).libp2p?.peerId as PeerId | undefined;
84
+ }
85
+
86
+ private getPeerAddrs(id: string): string[] {
87
+ let pid: PeerId;
88
+ try {
89
+ pid = peerIdFromString(id);
90
+ } catch {
91
+ return [];
92
+ }
93
+ if (this.components.getConnectionAddrs) return this.components.getConnectionAddrs(pid);
94
+ const libp2p = (this.components as any).libp2p;
95
+ if (!libp2p?.getConnections) return [];
96
+ const conns: any[] = libp2p.getConnections(pid) ?? [];
97
+ const addrs: string[] = [];
98
+ for (const c of conns) {
99
+ const addr = c.remoteAddr?.toString?.();
100
+ if (addr) addrs.push(addr);
101
+ }
102
+ return addrs;
103
+ }
104
+
105
+ /**
106
+ * Decide whether this node should redirect a cluster update instead of
107
+ * participating in its consensus.
108
+ *
109
+ * Membership is scoped against `record.peers` — the authoritative set the
110
+ * coordinator already computed and embedded (it only ever dials peers in this
111
+ * set). Using it directly (rather than independently recomputing the cluster
112
+ * from the key) is regression-proof against the "empty promises" symptom: a
113
+ * peer the coordinator legitimately included is, by construction, present in
114
+ * `record.peers` and is therefore never redirected.
115
+ *
116
+ * Returns a {@link RedirectPayload} when this node is not responsible, or null
117
+ * when the update should be processed locally (we are a member, the mesh is too
118
+ * small to scope, or we lack the identity/peer set to make a decision).
119
+ */
120
+ checkRedirect(record: ClusterRecord): RedirectPayload | null {
121
+ const selfId = this.getSelfId();
122
+ if (!selfId) return null; // no identity → can't scope, process locally
123
+
124
+ const peers = record.peers ?? {};
125
+ const peerIds = Object.keys(peers);
126
+ if (peerIds.length === 0) return null; // nothing to scope against → process locally
127
+
128
+ const selfStr = selfId.toString();
129
+ const isMember = peerIds.includes(selfStr);
130
+ const smallMesh = peerIds.length < this.responsibilityK;
131
+
132
+ if (!smallMesh && !isMember) {
133
+ const others = peerIds.filter(id => id !== selfStr);
134
+ return encodePeers(others.map(id => {
135
+ const recAddrs = peers[id]?.multiaddrs ?? [];
136
+ const addrs = recAddrs.length > 0 ? recAddrs : this.getPeerAddrs(id);
137
+ return { id, addrs };
138
+ }));
139
+ }
140
+
141
+ return null;
142
+ }
143
+
68
144
  async start(): Promise<void> {
69
145
  if (this.running) {
70
146
  return;
@@ -87,51 +163,47 @@ export class ClusterService implements Startable {
87
163
  this.running = false;
88
164
  }
89
165
 
166
+ /**
167
+ * Run a single decoded protocol message. An application-level throw
168
+ * (validation / signature / merge / consensus failure inside `cluster.update`)
169
+ * propagates to the caller, which turns it into a structured error envelope;
170
+ * a redirect or a successful {@link ClusterRecord} is returned as-is.
171
+ */
172
+ private async processOperation(message: { operation: string; record: ClusterRecord }): Promise<unknown> {
173
+ if (message.operation === 'update') {
174
+ // Scope consensus to responsible peers: redirect when we are not a
175
+ // member of the record's authoritative peer set, otherwise process.
176
+ const redirect = this.checkRedirect(message.record);
177
+ return redirect ?? await this.cluster.update(message.record);
178
+ }
179
+ throw new Error(`Unknown operation: ${message.operation}`);
180
+ }
181
+
90
182
  private handleIncomingStream(stream: Stream, connection: Connection): void {
91
183
  const peerId = connection.remotePeer;
92
184
 
93
185
  const processStream = async function* (this: ClusterService, source: AsyncIterable<Uint8ArrayList>) {
94
186
  for await (const msg of source) {
95
- // Decode the message
187
+ // Decode the framing. A malformed/undecodable message is a transport
188
+ // fault handled by the outer abort path, not an application error.
96
189
  const decoded = new TextDecoder().decode(msg.subarray());
97
190
  const message = JSON.parse(decoded) as { operation: string; record: ClusterRecord };
98
191
 
99
- // Process the operation
100
- let response: any;
101
- if (message.operation === 'update') {
102
- // TEMPORARY: Disable cluster membership check to fix empty promises issue
103
- // The membership check was causing peers to return redirect responses
104
- // instead of processing cluster updates, leading to empty promise arrays.
105
- // TODO: Re-enable and fix cluster membership logic for proper DHT routing
106
- response = await this.cluster.update(message.record)
107
- } else {
108
- throw new Error(`Unknown operation: ${message.operation}`);
192
+ // Application-level processing: surface any throw to the coordinator as
193
+ // a structured error envelope (closing the stream normally) instead of
194
+ // aborting, so the real cause — not an opaque StreamResetError — reaches
195
+ // the coordinator, which already enables debug logging. The abort path
196
+ // is reserved for genuinely unrecoverable framing/transport faults.
197
+ let response: unknown;
198
+ try {
199
+ response = await this.processOperation(message);
200
+ } catch (err) {
201
+ this.log.error('error processing cluster %s from %p - %e', message.operation, peerId, err);
202
+ response = toClusterErrorEnvelope(err);
109
203
  }
110
204
 
111
205
  // Encode and yield the response
112
- if (message.operation === 'update') {
113
- const rec = response as any;
114
- this.log('cluster-service:pre-serialize', {
115
- messageHash: rec?.messageHash,
116
- responseType: typeof response,
117
- hasPromises: 'promises' in (rec ?? {}),
118
- hasCommits: 'commits' in (rec ?? {}),
119
- promiseKeys: Object.keys(rec?.promises ?? {}),
120
- commitKeys: Object.keys(rec?.commits ?? {}),
121
- promiseValues: rec?.promises,
122
- commitValues: rec?.commits
123
- });
124
- }
125
- const serialized = JSON.stringify(response);
126
- if (message.operation === 'update') {
127
- const deserialized = JSON.parse(serialized);
128
- this.log('cluster-service:post-serialize', {
129
- messageHash: (deserialized as any)?.messageHash,
130
- promiseKeys: Object.keys((deserialized as any)?.promises ?? {}),
131
- commitKeys: Object.keys((deserialized as any)?.commits ?? {})
132
- });
133
- }
134
- yield new TextEncoder().encode(serialized);
206
+ yield new TextEncoder().encode(JSON.stringify(response));
135
207
  }
136
208
  };
137
209