@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,127 @@
1
+ /**
2
+ * Matchmaking — seeker walk client (db-p2p, drives the hang-out-vs-continue walk over the substrate).
3
+ *
4
+ * `docs/matchmaking.md` §Hang-out vs. continue. This is the RPC orchestration on top of the pure
5
+ * db-core {@link decide} engine: starting at `d_max`, it registers the seeker, issues `QueryV1`,
6
+ * re-validates and dedupes returned providers, and on each `Accepted` reply asks {@link decide} whether
7
+ * to finish, hang out (renew + requery on the `requery_interval_ms` poll cadence), or escalate (withdraw
8
+ * + re-register one tier toward the root). At `d = 0` there is nowhere left to walk, so it hangs out for
9
+ * the remaining patience and returns whatever matched (possibly `< wantCount`).
10
+ *
11
+ * Patience is a single budget that **drains across hops** (`docs/matchmaking.md` §Patience budgeting):
12
+ * a wall-clock deadline is fixed at the start, so every walked tier and every hang-out poll consumes
13
+ * the same `patienceMs` — escalation makes the next tier's hang-out progressively less attractive, which
14
+ * is correct since the root is terminal.
15
+ *
16
+ * The transport, clock, sleep, and per-entry verifier are all injected, so the walk unit-tests without a
17
+ * live libp2p stack (mock-tier e2e is a documented follow-on). This client implements the **poll path**
18
+ * only; the arrival-push path (`pushOnArrival`) is a separate slice.
19
+ *
20
+ * Edge cases encoded here (`docs/matchmaking.md` §Edge cases — the rest live in {@link decide}):
21
+ * - **`topicTraffic` absent (case 1):** the cohort is treated as zero-rate; the seeker issues one query
22
+ * (immediate-match) and walks one tier toward the root **without** hanging out.
23
+ * - **Stale `arrivalsPerMin = 0` after an epoch change (case 2):** never withdraw on a single zero
24
+ * reading — the immediate `QueryV1` runs first; a cohort that actually holds `>= wantCount` providers
25
+ * resolves to `done`, and only a query that also yields below threshold escalates.
26
+ * - **`UnwillingCohort`/`UnwillingMember` (case 3):** the hang-out decision is never entered (no
27
+ * `Accepted`); the walk terminates with whatever matched and standard substrate back-off applies.
28
+ */
29
+ import { type CapabilityFilter, type EntrySigVerifier, type HangOutConfig, type ProviderEntryV1, type QueryReplyV1 } from "@optimystic/db-core";
30
+ /** A seeker register/probe reply at a tree tier (the matchmaking-relevant subset of `RegisterReplyV1`). */
31
+ export interface SeekerProbeReply {
32
+ readonly result: "accepted" | "no_state" | "promoted" | "unwilling_member" | "unwilling_cohort";
33
+ /** Present on `accepted` and `promoted` (the substrate's barometer); absent triggers edge case 1. */
34
+ readonly topicTraffic?: QueryReplyV1["topicTraffic"];
35
+ /** Present on `promoted` — the tier to descend to. */
36
+ readonly targetTier?: number;
37
+ }
38
+ /** The substrate seam the walk drives: register/query/renew/withdraw against a tree tier. */
39
+ export interface SeekerWalkTransport {
40
+ /** Register (or re-register) the seeker at tree tier `treeTier`; resolves the probe reply. */
41
+ register(treeTier: number): Promise<SeekerProbeReply>;
42
+ /** Issue a `QueryV1` against the cohort the seeker is currently registered with. */
43
+ query(treeTier: number): Promise<QueryReplyV1>;
44
+ /** Renew the live seeker registration (hang-out keep-alive via TTL renewal). */
45
+ renew(): Promise<void>;
46
+ /** Withdraw the seeker registration before escalating (polite `RenewV1` TTL = 0; optional). */
47
+ withdraw(): Promise<void>;
48
+ }
49
+ /** Construction inputs for {@link SeekerWalkClient}. */
50
+ export interface SeekerWalkClientDeps {
51
+ readonly transport: SeekerWalkTransport;
52
+ /** The matchmaking topic id (used to re-validate each forwarded entry's `registrationSig`). */
53
+ readonly topicId: Uint8Array;
54
+ /** Providers the seeker needs. */
55
+ readonly wantCount: number;
56
+ /** The starting tree tier `d_max`. */
57
+ readonly dMax: number;
58
+ /** Total patience budget (ms); drains across hops + hang-out. */
59
+ readonly patienceMs: number;
60
+ /** Optional capability filter (re-applied seeker-side over the returned set). */
61
+ readonly filter?: CapabilityFilter;
62
+ /** Per-entry signature verifier (db-p2p binds `verifyPeerSig`). */
63
+ readonly verifyEntry: EntrySigVerifier;
64
+ /** Hang-out decision config. Default {@link DEFAULT_HANG_OUT_CONFIG}. */
65
+ readonly config?: HangOutConfig;
66
+ /** Assumed competing-seeker mean `wantCount`. Default {@link DEFAULT_MEAN_WANT_COUNT}. */
67
+ readonly meanWantCount?: number;
68
+ /** Starting `filterAcceptRatio` (refined per walk). Default {@link FILTER_ACCEPT_RATIO_INITIAL}. */
69
+ readonly filterAcceptRatioInitial?: number;
70
+ /** Wall clock (unix ms); injectable for tests. Default `Date.now`. */
71
+ readonly clock?: () => number;
72
+ /** Sleep for the requery cadence; injectable for tests. Default a real timer. */
73
+ readonly sleep?: (ms: number) => Promise<void>;
74
+ }
75
+ /** The result of a completed walk. */
76
+ export interface SeekerWalkResult {
77
+ /** Matched, re-validated, deduped providers (up to whatever accumulated; may be `< wantCount`). */
78
+ readonly providers: ProviderEntryV1[];
79
+ /** Whether `wantCount` was met. */
80
+ readonly metWantCount: boolean;
81
+ /** The tier the walk terminated at. */
82
+ readonly terminalTier: number;
83
+ /** Total register hops issued (probes + escalations + descends). */
84
+ readonly hops: number;
85
+ /**
86
+ * Max `topicTraffic.childCohortCount` observed across every `Accepted` reply this walk saw. `> 0`
87
+ * means the topic has promoted (it is hot), so the single-cohort sample is unrepresentative — the
88
+ * public seeker session / voting `QuorumDiscovery` binding uses this to decide whether to escalate to
89
+ * the multi-cohort sweep (`docs/matchmaking.md` §Multi-cohort sweep).
90
+ */
91
+ readonly maxChildCohortCount: number;
92
+ }
93
+ /** Drives the seeker hang-out-vs-continue walk for one matchmaking topic. See the module header. */
94
+ export declare class SeekerWalkClient {
95
+ private readonly transport;
96
+ private readonly topicId;
97
+ private readonly wantCount;
98
+ private readonly dMax;
99
+ private readonly patienceMs;
100
+ private readonly filter?;
101
+ private readonly verifyEntry;
102
+ private readonly config;
103
+ private readonly meanWantCount;
104
+ private readonly filterAcceptRatioInitial;
105
+ private readonly clock;
106
+ private readonly sleep;
107
+ /** Matched providers, deduped by `participantId` (a provider seen via two queries counts once). */
108
+ private readonly matched;
109
+ private ratioState;
110
+ private deadline;
111
+ private hops;
112
+ /** Max `childCohortCount` seen across `Accepted` replies — the hot-topic / sweep-escalation signal. */
113
+ private maxChildCohortCount;
114
+ constructor(deps: SeekerWalkClientDeps);
115
+ /** Run the walk from `d_max` toward the root; resolves the matched providers + termination info. */
116
+ run(): Promise<SeekerWalkResult>;
117
+ /** Remaining patience (ms); the wall-clock deadline drains uniformly across hops + hang-out. */
118
+ private remaining;
119
+ /** Filter, re-validate (`registrationSig`), and dedupe a query reply's providers into {@link matched}. */
120
+ private collect;
121
+ /** Evaluate one `Accepted` tier: immediate query, then {@link decide} → done / hangOut / escalate. */
122
+ private handleAccepted;
123
+ /** Keep the registration alive and re-query on the poll cadence until `wantCount` met or patience drains. */
124
+ private hangOut;
125
+ private finish;
126
+ }
127
+ //# sourceMappingURL=seeker-walk-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seeker-walk-client.d.ts","sourceRoot":"","sources":["../../../src/matchmaking/seeker-walk-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Matchmaking — seeker walk client (db-p2p, drives the hang-out-vs-continue walk over the substrate).
3
+ *
4
+ * `docs/matchmaking.md` §Hang-out vs. continue. This is the RPC orchestration on top of the pure
5
+ * db-core {@link decide} engine: starting at `d_max`, it registers the seeker, issues `QueryV1`,
6
+ * re-validates and dedupes returned providers, and on each `Accepted` reply asks {@link decide} whether
7
+ * to finish, hang out (renew + requery on the `requery_interval_ms` poll cadence), or escalate (withdraw
8
+ * + re-register one tier toward the root). At `d = 0` there is nowhere left to walk, so it hangs out for
9
+ * the remaining patience and returns whatever matched (possibly `< wantCount`).
10
+ *
11
+ * Patience is a single budget that **drains across hops** (`docs/matchmaking.md` §Patience budgeting):
12
+ * a wall-clock deadline is fixed at the start, so every walked tier and every hang-out poll consumes
13
+ * the same `patienceMs` — escalation makes the next tier's hang-out progressively less attractive, which
14
+ * is correct since the root is terminal.
15
+ *
16
+ * The transport, clock, sleep, and per-entry verifier are all injected, so the walk unit-tests without a
17
+ * live libp2p stack (mock-tier e2e is a documented follow-on). This client implements the **poll path**
18
+ * only; the arrival-push path (`pushOnArrival`) is a separate slice.
19
+ *
20
+ * Edge cases encoded here (`docs/matchmaking.md` §Edge cases — the rest live in {@link decide}):
21
+ * - **`topicTraffic` absent (case 1):** the cohort is treated as zero-rate; the seeker issues one query
22
+ * (immediate-match) and walks one tier toward the root **without** hanging out.
23
+ * - **Stale `arrivalsPerMin = 0` after an epoch change (case 2):** never withdraw on a single zero
24
+ * reading — the immediate `QueryV1` runs first; a cohort that actually holds `>= wantCount` providers
25
+ * resolves to `done`, and only a query that also yields below threshold escalates.
26
+ * - **`UnwillingCohort`/`UnwillingMember` (case 3):** the hang-out decision is never entered (no
27
+ * `Accepted`); the walk terminates with whatever matched and standard substrate back-off applies.
28
+ */
29
+ import { decide, filterAcceptRatio, matchesFilter, newFilterAcceptRatioState, observeYield, verifyProviderEntry, DEFAULT_HANG_OUT_CONFIG, DEFAULT_MEAN_WANT_COUNT, FILTER_ACCEPT_RATIO_INITIAL, } from "@optimystic/db-core";
30
+ /** Drives the seeker hang-out-vs-continue walk for one matchmaking topic. See the module header. */
31
+ export class SeekerWalkClient {
32
+ transport;
33
+ topicId;
34
+ wantCount;
35
+ dMax;
36
+ patienceMs;
37
+ filter;
38
+ verifyEntry;
39
+ config;
40
+ meanWantCount;
41
+ filterAcceptRatioInitial;
42
+ clock;
43
+ sleep;
44
+ /** Matched providers, deduped by `participantId` (a provider seen via two queries counts once). */
45
+ matched = new Map();
46
+ ratioState = newFilterAcceptRatioState();
47
+ deadline = 0;
48
+ hops = 0;
49
+ /** Max `childCohortCount` seen across `Accepted` replies — the hot-topic / sweep-escalation signal. */
50
+ maxChildCohortCount = 0;
51
+ constructor(deps) {
52
+ this.transport = deps.transport;
53
+ this.topicId = deps.topicId;
54
+ this.wantCount = deps.wantCount;
55
+ this.dMax = deps.dMax;
56
+ this.patienceMs = deps.patienceMs;
57
+ this.filter = deps.filter;
58
+ this.verifyEntry = deps.verifyEntry;
59
+ this.config = deps.config ?? DEFAULT_HANG_OUT_CONFIG;
60
+ this.meanWantCount = deps.meanWantCount ?? DEFAULT_MEAN_WANT_COUNT;
61
+ this.filterAcceptRatioInitial = deps.filterAcceptRatioInitial ?? FILTER_ACCEPT_RATIO_INITIAL;
62
+ this.clock = deps.clock ?? (() => Date.now());
63
+ this.sleep = deps.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
64
+ }
65
+ /** Run the walk from `d_max` toward the root; resolves the matched providers + termination info. */
66
+ async run() {
67
+ this.deadline = this.clock() + this.patienceMs;
68
+ let d = this.dMax;
69
+ while (true) {
70
+ this.hops++;
71
+ const reply = await this.transport.register(d);
72
+ switch (reply.result) {
73
+ case "no_state": {
74
+ if (d <= 0) {
75
+ return this.finish(d);
76
+ }
77
+ d -= 1;
78
+ continue;
79
+ }
80
+ case "unwilling_member":
81
+ case "unwilling_cohort": {
82
+ // Substrate-level refusal — never received Accepted, so hang-out is not entered (case 3).
83
+ return this.finish(d);
84
+ }
85
+ case "promoted": {
86
+ const target = reply.targetTier ?? d + 1;
87
+ if (target <= d) {
88
+ return this.finish(d);
89
+ }
90
+ d = target;
91
+ continue;
92
+ }
93
+ case "accepted": {
94
+ const outcome = await this.handleAccepted(d, reply.topicTraffic);
95
+ if (outcome === "done" || outcome === "terminal") {
96
+ return this.finish(d);
97
+ }
98
+ await this.transport.withdraw();
99
+ d -= 1;
100
+ continue;
101
+ }
102
+ }
103
+ }
104
+ }
105
+ /** Remaining patience (ms); the wall-clock deadline drains uniformly across hops + hang-out. */
106
+ remaining() {
107
+ return Math.max(0, this.deadline - this.clock());
108
+ }
109
+ /** Filter, re-validate (`registrationSig`), and dedupe a query reply's providers into {@link matched}. */
110
+ collect(reply) {
111
+ const returned = reply.providers ?? [];
112
+ let matchedThisQuery = 0;
113
+ for (const entry of returned) {
114
+ if (!matchesFilter(entry, this.filter)) {
115
+ continue;
116
+ }
117
+ if (!verifyProviderEntry(this.topicId, entry, this.verifyEntry)) {
118
+ continue;
119
+ }
120
+ matchedThisQuery++;
121
+ this.matched.set(entry.participantId, entry);
122
+ }
123
+ this.ratioState = observeYield(this.ratioState, matchedThisQuery, returned.length);
124
+ }
125
+ /** Evaluate one `Accepted` tier: immediate query, then {@link decide} → done / hangOut / escalate. */
126
+ async handleAccepted(d, traffic) {
127
+ // Record the hottest tier seen as soon as this Accepted reply's traffic is available — *before* the
128
+ // immediate-match/done short-circuit below, so the single-cohort-vs-sweep decision (public session /
129
+ // voting QuorumDiscovery binding) still sees a hot topic even when one cohort's query already met
130
+ // wantCount. Folding it only on the `decide` path would drop the signal for a small quorum that a
131
+ // single hot cohort satisfies, leaving the assembler with a prefix-biased sample it should sweep.
132
+ if (traffic !== undefined) {
133
+ this.maxChildCohortCount = Math.max(this.maxChildCohortCount, traffic.childCohortCount);
134
+ }
135
+ // Immediate-match check runs in every case — also satisfies edge case 2 (a stale arrivalsPerMin=0
136
+ // cohort that actually holds enough providers resolves here rather than escalating spuriously).
137
+ this.collect(await this.transport.query(d));
138
+ if (this.matched.size >= this.wantCount) {
139
+ return "done";
140
+ }
141
+ // Edge case 1: a reply without topicTraffic is treated as zero-rate — walk one tier toward the
142
+ // root without hanging out (no estimation against absent inputs).
143
+ if (traffic === undefined) {
144
+ return d <= 0 ? "terminal" : "escalate";
145
+ }
146
+ const decision = decide({
147
+ currentMatches: this.matched.size,
148
+ directParticipants: traffic.directParticipants,
149
+ arrivalsPerMin: traffic.arrivalsPerMin,
150
+ queriesPerMin: traffic.queriesPerMin,
151
+ childCohortCount: traffic.childCohortCount,
152
+ wantCount: this.wantCount,
153
+ patienceMsRemaining: this.remaining(),
154
+ filterAcceptRatio: filterAcceptRatio(this.ratioState, this.filterAcceptRatioInitial),
155
+ meanWantCount: this.meanWantCount,
156
+ }, this.config);
157
+ if (decision.action === "hangOut") {
158
+ await this.hangOut(d, decision.requeryIntervalMs);
159
+ if (this.matched.size >= this.wantCount) {
160
+ return "done";
161
+ }
162
+ return d <= 0 ? "terminal" : "escalate";
163
+ }
164
+ // escalate — but at the root there is nowhere to walk: hang out the remaining patience, then end.
165
+ if (d <= 0) {
166
+ await this.hangOut(d, this.config.requeryIntervalMs);
167
+ return "terminal";
168
+ }
169
+ return "escalate";
170
+ }
171
+ /** Keep the registration alive and re-query on the poll cadence until `wantCount` met or patience drains. */
172
+ async hangOut(d, requeryIntervalMs) {
173
+ while (this.remaining() > 0 && this.matched.size < this.wantCount) {
174
+ await this.sleep(Math.min(requeryIntervalMs, this.remaining()));
175
+ await this.transport.renew();
176
+ this.collect(await this.transport.query(d));
177
+ }
178
+ }
179
+ finish(terminalTier) {
180
+ return {
181
+ providers: [...this.matched.values()],
182
+ metWantCount: this.matched.size >= this.wantCount,
183
+ terminalTier,
184
+ hops: this.hops,
185
+ maxChildCohortCount: this.maxChildCohortCount,
186
+ };
187
+ }
188
+ }
189
+ //# sourceMappingURL=seeker-walk-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seeker-walk-client.js","sourceRoot":"","sources":["../../../src/matchmaking/seeker-walk-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Matchmaking — seeker-side adversarial traffic-reporting bounds + reputation cross-check hooks (db-p2p).
3
+ *
4
+ * `docs/matchmaking.md` §Adversarial cohort traffic reporting. A `QueryReplyV1.topicTraffic` (and the
5
+ * registration reply's traffic) is signed by the cohort **primary's single member key, not a threshold
6
+ * signature**, because the response is advisory — so a malicious primary can over- or under-report. The
7
+ * doc proves the harm is bounded either way; this module makes those bounds explicit for the seeker walk
8
+ * and emits the cross-check signals the reputation subsystem consumes.
9
+ *
10
+ * - **Over-reporting** (fake *hot* tier ⇒ seeker hangs out): bounded by the seeker's `patienceMs`. The
11
+ * worst case is wasted patience plus the one `register → walk` hop after timeout — there is **no
12
+ * spatial flood**, because the decision rule only ever walks *toward the root*, never speculatively
13
+ * outward. {@link boundReportedTraffic} therefore caps any hang-out to the seeker's remaining
14
+ * wall-clock patience ({@link TrafficBoundResult.capPatienceMs}).
15
+ * - **Under-reporting** (fake *cold* tier ⇒ seeker escalates): bounded to **one extra hop per affected
16
+ * tier**, terminating at the root where aggregated truth is hardest to fake
17
+ * ({@link TrafficBoundResult.escalateAfterTiers}).
18
+ * - **Cross-check via cohort gossip → reputation.** Other cohort members can detect a primary whose
19
+ * reported rate diverges from the gossip-derived view. Detection *routing* is the reputation
20
+ * subsystem's job (out of scope to implement); this module provides the **emission points**
21
+ * ({@link TrafficCrossCheckSignal}) and a thin bridge ({@link reportTrafficCrossCheck}) into the
22
+ * existing {@link IPeerReputation}. It scores nothing itself — the reputation subsystem owns the
23
+ * aggregation/decay policy that turns a stream of advisory signals into an actual penalty.
24
+ *
25
+ * **GROUNDING (matchmaking.md §Adversarial traffic reporting):** no threshold signature is added per
26
+ * `QueryReplyV1` — the single-member signature stands; the bounded worst-case here does not justify the
27
+ * per-reply threshold cost. This module enforces the bounds purely seeker-side instead.
28
+ */
29
+ import { type QueryReplyV1 } from "@optimystic/db-core";
30
+ import { type IPeerReputation } from "../reputation/index.js";
31
+ /**
32
+ * The seeker's running walk state at the moment a reply lands — enough to bound the reply's reported
33
+ * traffic and attribute a cross-check signal. The seeker walk client (or the public seeker session)
34
+ * supplies it per reply.
35
+ */
36
+ export interface SeekerWalkState {
37
+ /** Tree tier `d` the reply came from. */
38
+ readonly currentTier: number;
39
+ /** Starting tier `d_max` (the walk only descends from here toward `0`). */
40
+ readonly dMax: number;
41
+ /** Register hops issued so far (probes + escalations). Bounded by `d_max + 1` — the walk never loops. */
42
+ readonly tiersWalked: number;
43
+ /** Total patience budget for the task (ms). */
44
+ readonly patienceMs: number;
45
+ /** Patience left on the wall-clock deadline (ms) — the hang-out cap. */
46
+ readonly patienceRemainingMs: number;
47
+ /** Filter-matched providers the seeker's *own* immediate `QueryV1` at this tier actually returned. */
48
+ readonly observedMatches: number;
49
+ /** The reply's cohort primary peer id, for reputation attribution (absent → no attribution). */
50
+ readonly primaryId?: string;
51
+ }
52
+ /** Tunables for {@link boundReportedTraffic}. */
53
+ export interface TrafficBoundConfig {
54
+ /**
55
+ * Upper bound on extra register hops a single under-reported tier may cost. The doc fixes this at
56
+ * **1** ("one extra hop per affected tier"); exposed for tests / future policy, not meant to change.
57
+ */
58
+ readonly maxExtraHopsPerTier: number;
59
+ /**
60
+ * Over-report plausibility ratio. When a reply claims `directParticipants` more than this multiple of
61
+ * the seeker's *own* query yield, the over-report is flagged *suspect* (a cross-check signal — never a
62
+ * hard reject; the patience cap already bounds the harm).
63
+ */
64
+ readonly overReportSuspectRatio: number;
65
+ }
66
+ /** The documented defaults (`maxExtraHopsPerTier = 1`; suspect ratio chosen to tolerate normal churn). */
67
+ export declare const DEFAULT_TRAFFIC_BOUND_CONFIG: TrafficBoundConfig;
68
+ /** The kind of divergence a {@link TrafficCrossCheckSignal} reports. */
69
+ export type TrafficCrossCheckKind = "over-report-suspected" | "under-report-suspected";
70
+ /**
71
+ * One advisory cross-check observation about a cohort primary's reported traffic. Emitted by
72
+ * {@link boundReportedTraffic}; consumed by the reputation subsystem (via {@link reportTrafficCrossCheck}
73
+ * or a custom sink). Carries the raw discrepancy so the reputation policy — not this module — decides
74
+ * whether it warrants a penalty.
75
+ */
76
+ export interface TrafficCrossCheckSignal {
77
+ readonly kind: TrafficCrossCheckKind;
78
+ /** The cohort primary peer id (the subject), if the walk state attributed one. */
79
+ readonly subjectId?: string;
80
+ /** The tier the reply came from. */
81
+ readonly tier: number;
82
+ /** `topicTraffic.directParticipants` as reported. */
83
+ readonly reportedDirectParticipants: number;
84
+ /** `topicTraffic.arrivalsPerMin` as reported. */
85
+ readonly reportedArrivalsPerMin: number;
86
+ /** The seeker's own immediate-query yield, which the report is cross-checked against. */
87
+ readonly observedMatches: number;
88
+ }
89
+ /** The outcome of {@link boundReportedTraffic}. */
90
+ export interface TrafficBoundResult {
91
+ /** Whether the reported traffic is within plausible bounds (advisory; a flag, not an admission). */
92
+ readonly trusted: boolean;
93
+ /**
94
+ * Over-report bound: never hang out at this tier beyond the seeker's remaining wall-clock patience.
95
+ * Equals `max(0, patienceRemainingMs)` — so a fabricated hot tier wastes at most that, then the walk
96
+ * proceeds with its one register hop.
97
+ */
98
+ readonly capPatienceMs: number;
99
+ /** Under-report bound: at most this many extra register hops attributable to one tier (== config). */
100
+ readonly escalateAfterTiers: number;
101
+ /** Cross-check emission points (possibly empty). Forward to the reputation subsystem if desired. */
102
+ readonly reputationSignals: TrafficCrossCheckSignal[];
103
+ }
104
+ /**
105
+ * Bound the harm of a (possibly adversarial) `topicTraffic` report and emit cross-check signals. Pure —
106
+ * no I/O, no clock, no reputation scoring. The seeker walk consults `capPatienceMs` before hanging out
107
+ * and treats `escalateAfterTiers` as the per-tier hop ceiling; the bounds it returns hold *by
108
+ * construction* of the toward-root-only walk, so this function documents + asserts them rather than
109
+ * changing the walk topology.
110
+ */
111
+ export declare function boundReportedTraffic(reply: QueryReplyV1, walkState: SeekerWalkState, cfg?: TrafficBoundConfig): TrafficBoundResult;
112
+ /**
113
+ * The total hop budget the toward-root-only walk can consume under any sequence of (honest or
114
+ * adversarial) traffic reports: at most `maxExtraHopsPerTier` per tier from `d_max` down to the root,
115
+ * plus the terminal hop — i.e. `(dMax + 1) * maxExtraHopsPerTier`. Exposed so the walk and its tests can
116
+ * assert the under-report bound holds (the walk never exceeds it, because escalation is monotone toward
117
+ * `d = 0`).
118
+ */
119
+ export declare function maxWalkHops(dMax: number, cfg?: TrafficBoundConfig): number;
120
+ /**
121
+ * Integration hook: forward cross-check signals into the reputation subsystem. This is the **emission
122
+ * point only** — it records a `ProtocolViolation` against the reporting primary; the reputation
123
+ * subsystem's own weighting, decay, and deprioritize/ban thresholds (`PeerReputationService`) decide
124
+ * whether an accumulation of these advisory signals actually penalizes the peer. Signals without an
125
+ * attributed `subjectId` are skipped.
126
+ */
127
+ export declare function reportTrafficCrossCheck(reputation: IPeerReputation, signals: readonly TrafficCrossCheckSignal[]): void;
128
+ //# sourceMappingURL=traffic-validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traffic-validation.d.ts","sourceRoot":"","sources":["../../../src/matchmaking/traffic-validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE7E;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC/B,yCAAyC;IACzC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,yGAAyG;IACzG,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,+CAA+C;IAC/C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,wEAAwE;IACxE,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,sGAAsG;IACtG,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,gGAAgG;IAChG,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,iDAAiD;AACjD,MAAM,WAAW,kBAAkB;IAClC;;;OAGG;IACH,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC;;;;OAIG;IACH,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;CACxC;AAED,0GAA0G;AAC1G,eAAO,MAAM,4BAA4B,EAAE,kBAG1C,CAAC;AAEF,wEAAwE;AACxE,MAAM,MAAM,qBAAqB,GAAG,uBAAuB,GAAG,wBAAwB,CAAC;AAEvF;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,kFAAkF;IAClF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,oCAAoC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,QAAQ,CAAC,0BAA0B,EAAE,MAAM,CAAC;IAC5C,iDAAiD;IACjD,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;IACxC,yFAAyF;IACzF,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CACjC;AAED,mDAAmD;AACnD,MAAM,WAAW,kBAAkB;IAClC,oGAAoG;IACpG,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,sGAAsG;IACtG,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,oGAAoG;IACpG,QAAQ,CAAC,iBAAiB,EAAE,uBAAuB,EAAE,CAAC;CACtD;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,eAAe,EAC1B,GAAG,GAAE,kBAAiD,GACpD,kBAAkB,CA4BpB;AAgBD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAE,kBAAiD,GAAG,MAAM,CAExG;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,eAAe,EAAE,OAAO,EAAE,SAAS,uBAAuB,EAAE,GAAG,IAAI,CAOtH"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Matchmaking — seeker-side adversarial traffic-reporting bounds + reputation cross-check hooks (db-p2p).
3
+ *
4
+ * `docs/matchmaking.md` §Adversarial cohort traffic reporting. A `QueryReplyV1.topicTraffic` (and the
5
+ * registration reply's traffic) is signed by the cohort **primary's single member key, not a threshold
6
+ * signature**, because the response is advisory — so a malicious primary can over- or under-report. The
7
+ * doc proves the harm is bounded either way; this module makes those bounds explicit for the seeker walk
8
+ * and emits the cross-check signals the reputation subsystem consumes.
9
+ *
10
+ * - **Over-reporting** (fake *hot* tier ⇒ seeker hangs out): bounded by the seeker's `patienceMs`. The
11
+ * worst case is wasted patience plus the one `register → walk` hop after timeout — there is **no
12
+ * spatial flood**, because the decision rule only ever walks *toward the root*, never speculatively
13
+ * outward. {@link boundReportedTraffic} therefore caps any hang-out to the seeker's remaining
14
+ * wall-clock patience ({@link TrafficBoundResult.capPatienceMs}).
15
+ * - **Under-reporting** (fake *cold* tier ⇒ seeker escalates): bounded to **one extra hop per affected
16
+ * tier**, terminating at the root where aggregated truth is hardest to fake
17
+ * ({@link TrafficBoundResult.escalateAfterTiers}).
18
+ * - **Cross-check via cohort gossip → reputation.** Other cohort members can detect a primary whose
19
+ * reported rate diverges from the gossip-derived view. Detection *routing* is the reputation
20
+ * subsystem's job (out of scope to implement); this module provides the **emission points**
21
+ * ({@link TrafficCrossCheckSignal}) and a thin bridge ({@link reportTrafficCrossCheck}) into the
22
+ * existing {@link IPeerReputation}. It scores nothing itself — the reputation subsystem owns the
23
+ * aggregation/decay policy that turns a stream of advisory signals into an actual penalty.
24
+ *
25
+ * **GROUNDING (matchmaking.md §Adversarial traffic reporting):** no threshold signature is added per
26
+ * `QueryReplyV1` — the single-member signature stands; the bounded worst-case here does not justify the
27
+ * per-reply threshold cost. This module enforces the bounds purely seeker-side instead.
28
+ */
29
+ import { PenaltyReason } from "../reputation/index.js";
30
+ /** The documented defaults (`maxExtraHopsPerTier = 1`; suspect ratio chosen to tolerate normal churn). */
31
+ export const DEFAULT_TRAFFIC_BOUND_CONFIG = {
32
+ maxExtraHopsPerTier: 1,
33
+ overReportSuspectRatio: 8,
34
+ };
35
+ /**
36
+ * Bound the harm of a (possibly adversarial) `topicTraffic` report and emit cross-check signals. Pure —
37
+ * no I/O, no clock, no reputation scoring. The seeker walk consults `capPatienceMs` before hanging out
38
+ * and treats `escalateAfterTiers` as the per-tier hop ceiling; the bounds it returns hold *by
39
+ * construction* of the toward-root-only walk, so this function documents + asserts them rather than
40
+ * changing the walk topology.
41
+ */
42
+ export function boundReportedTraffic(reply, walkState, cfg = DEFAULT_TRAFFIC_BOUND_CONFIG) {
43
+ const traffic = reply.topicTraffic;
44
+ const signals = [];
45
+ // Over-report: a primary advertising a hot tier (many directParticipants) whose own query yields far
46
+ // fewer matches is suspect. Harm is bounded regardless — the patience cap below means a fabricated hot
47
+ // tier can only waste the seeker's remaining patience before it walks on (no spatial flood, since the
48
+ // walk only steps toward the root).
49
+ const overReportSuspect = traffic.directParticipants > cfg.overReportSuspectRatio * Math.max(walkState.observedMatches, 1);
50
+ if (overReportSuspect) {
51
+ signals.push(crossCheckSignal("over-report-suspected", traffic, walkState));
52
+ }
53
+ // Under-report: a primary claiming a cold tier (zero arrivals) while the seeker's own query yields
54
+ // matches is suspect. Either way the escalation costs at most one extra hop for this tier and
55
+ // terminates at the root.
56
+ const underReportSuspect = traffic.arrivalsPerMin === 0 && walkState.observedMatches > 0;
57
+ if (underReportSuspect) {
58
+ signals.push(crossCheckSignal("under-report-suspected", traffic, walkState));
59
+ }
60
+ return {
61
+ trusted: !overReportSuspect && !underReportSuspect,
62
+ capPatienceMs: Math.max(0, walkState.patienceRemainingMs),
63
+ escalateAfterTiers: cfg.maxExtraHopsPerTier,
64
+ reputationSignals: signals,
65
+ };
66
+ }
67
+ function crossCheckSignal(kind, traffic, walkState) {
68
+ const signal = {
69
+ kind,
70
+ tier: walkState.currentTier,
71
+ reportedDirectParticipants: traffic.directParticipants,
72
+ reportedArrivalsPerMin: traffic.arrivalsPerMin,
73
+ observedMatches: walkState.observedMatches,
74
+ };
75
+ if (walkState.primaryId !== undefined) {
76
+ signal.subjectId = walkState.primaryId;
77
+ }
78
+ return signal;
79
+ }
80
+ /**
81
+ * The total hop budget the toward-root-only walk can consume under any sequence of (honest or
82
+ * adversarial) traffic reports: at most `maxExtraHopsPerTier` per tier from `d_max` down to the root,
83
+ * plus the terminal hop — i.e. `(dMax + 1) * maxExtraHopsPerTier`. Exposed so the walk and its tests can
84
+ * assert the under-report bound holds (the walk never exceeds it, because escalation is monotone toward
85
+ * `d = 0`).
86
+ */
87
+ export function maxWalkHops(dMax, cfg = DEFAULT_TRAFFIC_BOUND_CONFIG) {
88
+ return Math.max(0, dMax + 1) * cfg.maxExtraHopsPerTier;
89
+ }
90
+ /**
91
+ * Integration hook: forward cross-check signals into the reputation subsystem. This is the **emission
92
+ * point only** — it records a `ProtocolViolation` against the reporting primary; the reputation
93
+ * subsystem's own weighting, decay, and deprioritize/ban thresholds (`PeerReputationService`) decide
94
+ * whether an accumulation of these advisory signals actually penalizes the peer. Signals without an
95
+ * attributed `subjectId` are skipped.
96
+ */
97
+ export function reportTrafficCrossCheck(reputation, signals) {
98
+ for (const signal of signals) {
99
+ if (signal.subjectId === undefined) {
100
+ continue;
101
+ }
102
+ reputation.reportPeer(signal.subjectId, PenaltyReason.ProtocolViolation, `matchmaking:${signal.kind}`);
103
+ }
104
+ }
105
+ //# sourceMappingURL=traffic-validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traffic-validation.js","sourceRoot":"","sources":["../../../src/matchmaking/traffic-validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAGH,OAAO,EAAE,aAAa,EAAwB,MAAM,wBAAwB,CAAC;AAuC7E,0GAA0G;AAC1G,MAAM,CAAC,MAAM,4BAA4B,GAAuB;IAC/D,mBAAmB,EAAE,CAAC;IACtB,sBAAsB,EAAE,CAAC;CACzB,CAAC;AAyCF;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CACnC,KAAmB,EACnB,SAA0B,EAC1B,MAA0B,4BAA4B;IAEtD,MAAM,OAAO,GAAG,KAAK,CAAC,YAAY,CAAC;IACnC,MAAM,OAAO,GAA8B,EAAE,CAAC;IAE9C,qGAAqG;IACrG,uGAAuG;IACvG,sGAAsG;IACtG,oCAAoC;IACpC,MAAM,iBAAiB,GACtB,OAAO,CAAC,kBAAkB,GAAG,GAAG,CAAC,sBAAsB,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC;IAClG,IAAI,iBAAiB,EAAE,CAAC;QACvB,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,uBAAuB,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;IAC7E,CAAC;IAED,mGAAmG;IACnG,8FAA8F;IAC9F,0BAA0B;IAC1B,MAAM,kBAAkB,GAAG,OAAO,CAAC,cAAc,KAAK,CAAC,IAAI,SAAS,CAAC,eAAe,GAAG,CAAC,CAAC;IACzF,IAAI,kBAAkB,EAAE,CAAC;QACxB,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,wBAAwB,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;IAC9E,CAAC;IAED,OAAO;QACN,OAAO,EAAE,CAAC,iBAAiB,IAAI,CAAC,kBAAkB;QAClD,aAAa,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,mBAAmB,CAAC;QACzD,kBAAkB,EAAE,GAAG,CAAC,mBAAmB;QAC3C,iBAAiB,EAAE,OAAO;KAC1B,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,IAA2B,EAAE,OAAqC,EAAE,SAA0B;IACvH,MAAM,MAAM,GAA4B;QACvC,IAAI;QACJ,IAAI,EAAE,SAAS,CAAC,WAAW;QAC3B,0BAA0B,EAAE,OAAO,CAAC,kBAAkB;QACtD,sBAAsB,EAAE,OAAO,CAAC,cAAc;QAC9C,eAAe,EAAE,SAAS,CAAC,eAAe;KAC1C,CAAC;IACF,IAAI,SAAS,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACtC,MAAgC,CAAC,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC;IACnE,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,MAA0B,4BAA4B;IAC/F,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,mBAAmB,CAAC;AACxD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CAAC,UAA2B,EAAE,OAA2C;IAC/G,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC9B,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YACpC,SAAS;QACV,CAAC;QACD,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,SAAS,EAAE,aAAa,CAAC,iBAAiB,EAAE,eAAe,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACxG,CAAC;AACF,CAAC"}
@@ -59,9 +59,11 @@ export declare class NetworkManagerService implements Startable {
59
59
  getRebalanceMonitor(): RebalanceMonitor | undefined;
60
60
  /**
61
61
  * Initialize the spread-on-churn monitor. Call after libp2p, FRET are available.
62
- * Caller provides repo and peerNetwork (not held by NetworkManagerService directly).
62
+ * Caller provides repo and peerNetwork (not held by NetworkManagerService directly),
63
+ * plus the node's protocolPrefix (/optimystic/<networkName>) so churn pushes dial the
64
+ * same block-transfer protocol the node registers its handler under.
63
65
  */
64
- initSpreadOnChurnMonitor(partitionDetector: PartitionDetector, repo: SpreadOnChurnDeps['repo'], peerNetwork: SpreadOnChurnDeps['peerNetwork'], clusterSize: number, config?: Partial<SpreadOnChurnConfig>): SpreadOnChurnMonitor;
66
+ initSpreadOnChurnMonitor(partitionDetector: PartitionDetector, repo: SpreadOnChurnDeps['repo'], peerNetwork: SpreadOnChurnDeps['peerNetwork'], clusterSize: number, protocolPrefix: string, config?: Partial<SpreadOnChurnConfig>): SpreadOnChurnMonitor;
65
67
  getSpreadOnChurnMonitor(): SpreadOnChurnMonitor | undefined;
66
68
  private getLibp2p;
67
69
  private getFret;
@@ -1 +1 @@
1
- {"version":3,"file":"network-manager-service.d.ts","sourceRoot":"","sources":["../../../src/network/network-manager-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"network-manager-service.d.ts","sourceRoot":"","sources":["../../../src/network/network-manager-service.ts"],"names":[],"mappings":"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"}
@@ -54,15 +54,21 @@ export class NetworkManagerService {
54
54
  }
55
55
  /**
56
56
  * Initialize the spread-on-churn monitor. Call after libp2p, FRET are available.
57
- * Caller provides repo and peerNetwork (not held by NetworkManagerService directly).
57
+ * Caller provides repo and peerNetwork (not held by NetworkManagerService directly),
58
+ * plus the node's protocolPrefix (/optimystic/<networkName>) so churn pushes dial the
59
+ * same block-transfer protocol the node registers its handler under.
58
60
  */
59
- initSpreadOnChurnMonitor(partitionDetector, repo, peerNetwork, clusterSize, config) {
61
+ initSpreadOnChurnMonitor(partitionDetector, repo, peerNetwork, clusterSize, protocolPrefix, config) {
60
62
  const libp2p = this.getLibp2p();
61
63
  const fret = this.getFret();
62
64
  if (!libp2p || !fret) {
63
65
  throw new Error('Cannot init SpreadOnChurnMonitor: libp2p or FRET not available');
64
66
  }
65
- this.spreadOnChurnMonitor = new SpreadOnChurnMonitor({ libp2p, fret, partitionDetector, repo, peerNetwork, clusterSize }, config);
67
+ // protocolPrefix MUST flow into SpreadOnChurnDeps: performSpread builds its
68
+ // BlockTransferClient with it, and the receiving node registers the block-transfer
69
+ // handler under /optimystic/<networkName>. A missing/empty prefix dials the wrong
70
+ // protocol and every churn push fails to connect.
71
+ this.spreadOnChurnMonitor = new SpreadOnChurnMonitor({ libp2p, fret, partitionDetector, repo, peerNetwork, clusterSize, protocolPrefix }, config);
66
72
  return this.spreadOnChurnMonitor;
67
73
  }
68
74
  getSpreadOnChurnMonitor() {