@optimystic/db-p2p 0.14.1 → 0.16.3

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 (275) hide show
  1. package/README.md +616 -609
  2. package/dist/src/cluster/block-transfer-service.d.ts.map +1 -1
  3. package/dist/src/cluster/block-transfer-service.js +4 -3
  4. package/dist/src/cluster/block-transfer-service.js.map +1 -1
  5. package/dist/src/cluster/block-transfer.d.ts +52 -3
  6. package/dist/src/cluster/block-transfer.d.ts.map +1 -1
  7. package/dist/src/cluster/block-transfer.js +129 -6
  8. package/dist/src/cluster/block-transfer.js.map +1 -1
  9. package/dist/src/cluster/client.d.ts.map +1 -1
  10. package/dist/src/cluster/client.js +3 -1
  11. package/dist/src/cluster/client.js.map +1 -1
  12. package/dist/src/cluster/cluster-repo.d.ts +182 -11
  13. package/dist/src/cluster/cluster-repo.d.ts.map +1 -1
  14. package/dist/src/cluster/cluster-repo.js +429 -69
  15. package/dist/src/cluster/cluster-repo.js.map +1 -1
  16. package/dist/src/cluster/peer-key-binding.d.ts +25 -0
  17. package/dist/src/cluster/peer-key-binding.d.ts.map +1 -0
  18. package/dist/src/cluster/peer-key-binding.js +39 -0
  19. package/dist/src/cluster/peer-key-binding.js.map +1 -0
  20. package/dist/src/cluster/quorum-restore.d.ts +72 -0
  21. package/dist/src/cluster/quorum-restore.d.ts.map +1 -0
  22. package/dist/src/cluster/quorum-restore.js +0 -0
  23. package/dist/src/cluster/quorum-restore.js.map +1 -0
  24. package/dist/src/cluster/rebalance-monitor.d.ts +23 -1
  25. package/dist/src/cluster/rebalance-monitor.d.ts.map +1 -1
  26. package/dist/src/cluster/rebalance-monitor.js +17 -2
  27. package/dist/src/cluster/rebalance-monitor.js.map +1 -1
  28. package/dist/src/cluster/service.d.ts.map +1 -1
  29. package/dist/src/cluster/service.js +7 -1
  30. package/dist/src/cluster/service.js.map +1 -1
  31. package/dist/src/cluster/spread-on-churn.d.ts +7 -0
  32. package/dist/src/cluster/spread-on-churn.d.ts.map +1 -1
  33. package/dist/src/cluster/spread-on-churn.js +4 -1
  34. package/dist/src/cluster/spread-on-churn.js.map +1 -1
  35. package/dist/src/cluster/supermajority-coupling.d.ts +22 -0
  36. package/dist/src/cluster/supermajority-coupling.d.ts.map +1 -0
  37. package/dist/src/cluster/supermajority-coupling.js +27 -0
  38. package/dist/src/cluster/supermajority-coupling.js.map +1 -0
  39. package/dist/src/cohort-topic/cohort-gossip-driver.d.ts +46 -4
  40. package/dist/src/cohort-topic/cohort-gossip-driver.d.ts.map +1 -1
  41. package/dist/src/cohort-topic/cohort-gossip-driver.js +62 -7
  42. package/dist/src/cohort-topic/cohort-gossip-driver.js.map +1 -1
  43. package/dist/src/cohort-topic/cohort-gossip-transport.d.ts +7 -0
  44. package/dist/src/cohort-topic/cohort-gossip-transport.d.ts.map +1 -1
  45. package/dist/src/cohort-topic/cohort-gossip-transport.js +9 -0
  46. package/dist/src/cohort-topic/cohort-gossip-transport.js.map +1 -1
  47. package/dist/src/cohort-topic/host.d.ts +197 -27
  48. package/dist/src/cohort-topic/host.d.ts.map +1 -1
  49. package/dist/src/cohort-topic/host.js +643 -87
  50. package/dist/src/cohort-topic/host.js.map +1 -1
  51. package/dist/src/dispute/arbitrator-selection.d.ts +68 -7
  52. package/dist/src/dispute/arbitrator-selection.d.ts.map +1 -1
  53. package/dist/src/dispute/arbitrator-selection.js +105 -16
  54. package/dist/src/dispute/arbitrator-selection.js.map +1 -1
  55. package/dist/src/dispute/cascade.d.ts +7 -0
  56. package/dist/src/dispute/cascade.d.ts.map +1 -1
  57. package/dist/src/dispute/cascade.js +1 -1
  58. package/dist/src/dispute/cascade.js.map +1 -1
  59. package/dist/src/dispute/client.d.ts.map +1 -1
  60. package/dist/src/dispute/client.js +3 -2
  61. package/dist/src/dispute/client.js.map +1 -1
  62. package/dist/src/dispute/dispute-service.d.ts +32 -3
  63. package/dist/src/dispute/dispute-service.d.ts.map +1 -1
  64. package/dist/src/dispute/dispute-service.js +82 -9
  65. package/dist/src/dispute/dispute-service.js.map +1 -1
  66. package/dist/src/dispute/index.d.ts +1 -1
  67. package/dist/src/dispute/index.d.ts.map +1 -1
  68. package/dist/src/dispute/index.js +1 -1
  69. package/dist/src/dispute/index.js.map +1 -1
  70. package/dist/src/dispute/invalidation.d.ts +25 -0
  71. package/dist/src/dispute/invalidation.d.ts.map +1 -1
  72. package/dist/src/dispute/invalidation.js +14 -2
  73. package/dist/src/dispute/invalidation.js.map +1 -1
  74. package/dist/src/dispute/service.d.ts.map +1 -1
  75. package/dist/src/dispute/service.js +7 -1
  76. package/dist/src/dispute/service.js.map +1 -1
  77. package/dist/src/index.d.ts +4 -1
  78. package/dist/src/index.d.ts.map +1 -1
  79. package/dist/src/index.js +4 -1
  80. package/dist/src/index.js.map +1 -1
  81. package/dist/src/it-utility.d.ts +1 -1
  82. package/dist/src/it-utility.d.ts.map +1 -1
  83. package/dist/src/it-utility.js +4 -13
  84. package/dist/src/it-utility.js.map +1 -1
  85. package/dist/src/libp2p-key-network.d.ts +98 -1
  86. package/dist/src/libp2p-key-network.d.ts.map +1 -1
  87. package/dist/src/libp2p-key-network.js +272 -17
  88. package/dist/src/libp2p-key-network.js.map +1 -1
  89. package/dist/src/libp2p-node-base.d.ts +12 -0
  90. package/dist/src/libp2p-node-base.d.ts.map +1 -1
  91. package/dist/src/libp2p-node-base.js +441 -89
  92. package/dist/src/libp2p-node-base.js.map +1 -1
  93. package/dist/src/matchmaking/query-transport.d.ts +2 -0
  94. package/dist/src/matchmaking/query-transport.d.ts.map +1 -1
  95. package/dist/src/matchmaking/query-transport.js +6 -0
  96. package/dist/src/matchmaking/query-transport.js.map +1 -1
  97. package/dist/src/matchmaking/traffic-validation.js +1 -0
  98. package/dist/src/matchmaking/traffic-validation.js.map +1 -1
  99. package/dist/src/network/network-manager-service.d.ts +2 -2
  100. package/dist/src/network/network-manager-service.d.ts.map +1 -1
  101. package/dist/src/network/network-manager-service.js +8 -4
  102. package/dist/src/network/network-manager-service.js.map +1 -1
  103. package/dist/src/owned-block-seed.d.ts +27 -0
  104. package/dist/src/owned-block-seed.d.ts.map +1 -0
  105. package/dist/src/owned-block-seed.js +37 -0
  106. package/dist/src/owned-block-seed.js.map +1 -0
  107. package/dist/src/protocol-client.d.ts +1 -0
  108. package/dist/src/protocol-client.d.ts.map +1 -1
  109. package/dist/src/protocol-client.js +9 -2
  110. package/dist/src/protocol-client.js.map +1 -1
  111. package/dist/src/protocol-limits.d.ts +32 -0
  112. package/dist/src/protocol-limits.d.ts.map +1 -0
  113. package/dist/src/protocol-limits.js +32 -0
  114. package/dist/src/protocol-limits.js.map +1 -0
  115. package/dist/src/repo/client.d.ts.map +1 -1
  116. package/dist/src/repo/client.js +3 -0
  117. package/dist/src/repo/client.js.map +1 -1
  118. package/dist/src/repo/cluster-coordinator.d.ts +41 -4
  119. package/dist/src/repo/cluster-coordinator.d.ts.map +1 -1
  120. package/dist/src/repo/cluster-coordinator.js +128 -80
  121. package/dist/src/repo/cluster-coordinator.js.map +1 -1
  122. package/dist/src/repo/coordinator-repo.d.ts +38 -1
  123. package/dist/src/repo/coordinator-repo.d.ts.map +1 -1
  124. package/dist/src/repo/coordinator-repo.js +92 -13
  125. package/dist/src/repo/coordinator-repo.js.map +1 -1
  126. package/dist/src/repo/service.d.ts.map +1 -1
  127. package/dist/src/repo/service.js +7 -1
  128. package/dist/src/repo/service.js.map +1 -1
  129. package/dist/src/reputation/peer-reputation.js +1 -1
  130. package/dist/src/reputation/peer-reputation.js.map +1 -1
  131. package/dist/src/reputation/types.d.ts +3 -1
  132. package/dist/src/reputation/types.d.ts.map +1 -1
  133. package/dist/src/reputation/types.js +3 -0
  134. package/dist/src/reputation/types.js.map +1 -1
  135. package/dist/src/rn.d.ts +5 -1
  136. package/dist/src/rn.d.ts.map +1 -1
  137. package/dist/src/rn.js +7 -1
  138. package/dist/src/rn.js.map +1 -1
  139. package/dist/src/storage/arachnode-fret-adapter.d.ts +30 -1
  140. package/dist/src/storage/arachnode-fret-adapter.d.ts.map +1 -1
  141. package/dist/src/storage/arachnode-fret-adapter.js +15 -2
  142. package/dist/src/storage/arachnode-fret-adapter.js.map +1 -1
  143. package/dist/src/storage/arachnode-partition.d.ts +49 -0
  144. package/dist/src/storage/arachnode-partition.d.ts.map +1 -0
  145. package/dist/src/storage/arachnode-partition.js +61 -0
  146. package/dist/src/storage/arachnode-partition.js.map +1 -0
  147. package/dist/src/storage/block-storage.d.ts +40 -1
  148. package/dist/src/storage/block-storage.d.ts.map +1 -1
  149. package/dist/src/storage/block-storage.js +150 -57
  150. package/dist/src/storage/block-storage.js.map +1 -1
  151. package/dist/src/storage/i-block-storage.d.ts +8 -0
  152. package/dist/src/storage/i-block-storage.d.ts.map +1 -1
  153. package/dist/src/storage/i-raw-storage.d.ts +13 -0
  154. package/dist/src/storage/i-raw-storage.d.ts.map +1 -1
  155. package/dist/src/storage/kv-raw-storage.d.ts +45 -0
  156. package/dist/src/storage/kv-raw-storage.d.ts.map +1 -0
  157. package/dist/src/storage/kv-raw-storage.js +113 -0
  158. package/dist/src/storage/kv-raw-storage.js.map +1 -0
  159. package/dist/src/storage/memory-storage.d.ts +20 -58
  160. package/dist/src/storage/memory-storage.d.ts.map +1 -1
  161. package/dist/src/storage/memory-storage.js +22 -148
  162. package/dist/src/storage/memory-storage.js.map +1 -1
  163. package/dist/src/storage/memory-store-driver.d.ts +39 -0
  164. package/dist/src/storage/memory-store-driver.d.ts.map +1 -0
  165. package/dist/src/storage/memory-store-driver.js +129 -0
  166. package/dist/src/storage/memory-store-driver.js.map +1 -0
  167. package/dist/src/storage/raw-store-codec.d.ts +10 -0
  168. package/dist/src/storage/raw-store-codec.d.ts.map +1 -0
  169. package/dist/src/storage/raw-store-codec.js +36 -0
  170. package/dist/src/storage/raw-store-codec.js.map +1 -0
  171. package/dist/src/storage/raw-store-driver.d.ts +69 -0
  172. package/dist/src/storage/raw-store-driver.d.ts.map +1 -0
  173. package/dist/src/storage/raw-store-driver.js +2 -0
  174. package/dist/src/storage/raw-store-driver.js.map +1 -0
  175. package/dist/src/storage/restoration-coordinator-v2.d.ts.map +1 -1
  176. package/dist/src/storage/restoration-coordinator-v2.js +1 -1
  177. package/dist/src/storage/restoration-coordinator-v2.js.map +1 -1
  178. package/dist/src/storage/restoration-coordinator.d.ts +73 -0
  179. package/dist/src/storage/restoration-coordinator.d.ts.map +1 -0
  180. package/dist/src/storage/restoration-coordinator.js +181 -0
  181. package/dist/src/storage/restoration-coordinator.js.map +1 -0
  182. package/dist/src/storage/ring-selector.d.ts +92 -5
  183. package/dist/src/storage/ring-selector.d.ts.map +1 -1
  184. package/dist/src/storage/ring-selector.js +153 -51
  185. package/dist/src/storage/ring-selector.js.map +1 -1
  186. package/dist/src/storage/ring-shift-coordinator.d.ts +128 -0
  187. package/dist/src/storage/ring-shift-coordinator.d.ts.map +1 -0
  188. package/dist/src/storage/ring-shift-coordinator.js +196 -0
  189. package/dist/src/storage/ring-shift-coordinator.js.map +1 -0
  190. package/dist/src/storage/storage-monitor.d.ts +28 -0
  191. package/dist/src/storage/storage-monitor.d.ts.map +1 -1
  192. package/dist/src/storage/storage-monitor.js +42 -2
  193. package/dist/src/storage/storage-monitor.js.map +1 -1
  194. package/dist/src/storage/storage-repo.d.ts +19 -0
  195. package/dist/src/storage/storage-repo.d.ts.map +1 -1
  196. package/dist/src/storage/storage-repo.js +172 -22
  197. package/dist/src/storage/storage-repo.js.map +1 -1
  198. package/dist/src/sync/client.d.ts.map +1 -1
  199. package/dist/src/sync/client.js +5 -1
  200. package/dist/src/sync/client.js.map +1 -1
  201. package/dist/src/sync/service.d.ts.map +1 -1
  202. package/dist/src/sync/service.js +2 -1
  203. package/dist/src/sync/service.js.map +1 -1
  204. package/dist/src/testing/cohort-topic-mesh-harness.d.ts +28 -4
  205. package/dist/src/testing/cohort-topic-mesh-harness.d.ts.map +1 -1
  206. package/dist/src/testing/cohort-topic-mesh-harness.js +51 -10
  207. package/dist/src/testing/cohort-topic-mesh-harness.js.map +1 -1
  208. package/dist/src/testing/index.d.ts +1 -0
  209. package/dist/src/testing/index.d.ts.map +1 -1
  210. package/dist/src/testing/index.js +1 -0
  211. package/dist/src/testing/index.js.map +1 -1
  212. package/dist/src/testing/mesh-harness.d.ts.map +1 -1
  213. package/dist/src/testing/mesh-harness.js +15 -7
  214. package/dist/src/testing/mesh-harness.js.map +1 -1
  215. package/dist/src/testing/raw-storage-conformance.d.ts +24 -0
  216. package/dist/src/testing/raw-storage-conformance.d.ts.map +1 -0
  217. package/dist/src/testing/raw-storage-conformance.js +313 -0
  218. package/dist/src/testing/raw-storage-conformance.js.map +1 -0
  219. package/package.json +4 -4
  220. package/src/cluster/block-transfer-service.ts +4 -3
  221. package/src/cluster/block-transfer.ts +424 -265
  222. package/src/cluster/client.ts +3 -1
  223. package/src/cluster/cluster-repo.ts +481 -71
  224. package/src/cluster/peer-key-binding.ts +37 -0
  225. package/src/cluster/quorum-restore.ts +0 -0
  226. package/src/cluster/rebalance-monitor.ts +34 -3
  227. package/src/cluster/service.ts +7 -1
  228. package/src/cluster/spread-on-churn.ts +11 -1
  229. package/src/cluster/supermajority-coupling.ts +37 -0
  230. package/src/cohort-topic/cohort-gossip-driver.ts +96 -9
  231. package/src/cohort-topic/cohort-gossip-transport.ts +10 -0
  232. package/src/cohort-topic/host.ts +831 -105
  233. package/src/dispute/arbitrator-selection.ts +138 -28
  234. package/src/dispute/cascade.ts +8 -1
  235. package/src/dispute/client.ts +3 -2
  236. package/src/dispute/dispute-service.ts +94 -9
  237. package/src/dispute/index.ts +7 -1
  238. package/src/dispute/invalidation.ts +40 -2
  239. package/src/dispute/service.ts +7 -1
  240. package/src/index.ts +46 -43
  241. package/src/it-utility.ts +5 -13
  242. package/src/libp2p-key-network.ts +281 -18
  243. package/src/libp2p-node-base.ts +511 -81
  244. package/src/matchmaking/query-transport.ts +9 -0
  245. package/src/network/network-manager-service.ts +8 -2
  246. package/src/owned-block-seed.ts +40 -0
  247. package/src/protocol-client.ts +10 -3
  248. package/src/protocol-limits.ts +33 -0
  249. package/src/repo/client.ts +3 -0
  250. package/src/repo/cluster-coordinator.ts +145 -82
  251. package/src/repo/coordinator-repo.ts +96 -16
  252. package/src/repo/service.ts +7 -1
  253. package/src/reputation/types.ts +3 -0
  254. package/src/rn.ts +7 -1
  255. package/src/storage/arachnode-fret-adapter.ts +33 -2
  256. package/src/storage/arachnode-partition.ts +74 -0
  257. package/src/storage/block-storage.ts +169 -61
  258. package/src/storage/i-block-storage.ts +9 -0
  259. package/src/storage/i-raw-storage.ts +14 -0
  260. package/src/storage/kv-raw-storage.ts +135 -0
  261. package/src/storage/memory-storage.ts +25 -173
  262. package/src/storage/memory-store-driver.ts +157 -0
  263. package/src/storage/raw-store-codec.ts +42 -0
  264. package/src/storage/raw-store-driver.ts +80 -0
  265. package/src/storage/{restoration-coordinator-v2.ts → restoration-coordinator.ts} +43 -37
  266. package/src/storage/ring-selector.ts +317 -176
  267. package/src/storage/ring-shift-coordinator.ts +271 -0
  268. package/src/storage/storage-monitor.ts +70 -3
  269. package/src/storage/storage-repo.ts +710 -558
  270. package/src/sync/client.ts +5 -1
  271. package/src/sync/service.ts +2 -1
  272. package/src/testing/cohort-topic-mesh-harness.ts +61 -11
  273. package/src/testing/index.ts +1 -0
  274. package/src/testing/mesh-harness.ts +14 -6
  275. package/src/testing/raw-storage-conformance.ts +397 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol-limits.d.ts","sourceRoot":"","sources":["../../src/protocol-limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,QAAkB,CAAC;AAEzD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,uBAAuB,QAAkB,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Inbound-message size caps for the db-p2p consensus protocols.
3
+ *
4
+ * Every inbound stream handler frames its wire data with length-prefixed
5
+ * encoding (`it-length-prefixed`) and `JSON.parse`s each frame. Passing one of
6
+ * these constants as the decoder's `maxDataLength` makes an oversized frame
7
+ * reject at the length-prefix (before any allocation against the declared size)
8
+ * instead of buffering up to the library default (4 MiB) of attacker-controlled
9
+ * JSON per frame. Mirrors the existing precedent
10
+ * `DEFAULT_MAX_MESSAGE_BYTES = 1024 * 1024` in
11
+ * `packages/db-core/src/cohort-topic/wire/codec.ts`.
12
+ */
13
+ /**
14
+ * Max size (bytes) of a single inbound framed message on a *control-plane*
15
+ * protocol — cluster records, dispute votes, sync requests. These carry a peer
16
+ * set + signatures + small metadata, never bulk block data.
17
+ */
18
+ export const MAX_CONTROL_MESSAGE_BYTES = 1 * 1024 * 1024; // 1 MiB
19
+ /**
20
+ * Max size (bytes) of a single inbound framed message on a *block-carrying*
21
+ * protocol — repo operations (pend/commit transforms + block bodies),
22
+ * block-transfer push payloads (base64-inflated block data, multiple per
23
+ * request), and the block-bearing responses those protocols return.
24
+ *
25
+ * NOTE: the repo enforces no hard per-block byte ceiling today, so this is a
26
+ * heuristic. If a legitimate block/transform can exceed this, the transfer will
27
+ * be rejected — raise this constant (or thread a config override) rather than
28
+ * removing the cap. If the repo later grows a real max-block constant, derive
29
+ * this cap from it.
30
+ */
31
+ export const MAX_BLOCK_MESSAGE_BYTES = 8 * 1024 * 1024; // 8 MiB
32
+ //# sourceMappingURL=protocol-limits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol-limits.js","sourceRoot":"","sources":["../../src/protocol-limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,QAAQ;AAElE;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,QAAQ"}
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/repo/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAC7F,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAC3D,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGvD,qBAAa,UAAW,SAAQ,cAAe,YAAW,KAAK;IACC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM;IAA/F,OAAO;IAIP,mCAAmC;WACrB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,UAAU;IAI9F,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAO5E,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,GAAG,YAAY,CAAC;IAOxF,MAAM,CAAC,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAOvE,MAAM,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC;IAOpF,OAAO,CAAC,oBAAoB;YASd,kBAAkB;YAkElB,wBAAwB;YA6BxB,kCAAkC;CAQhD"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/repo/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAC7F,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAC3D,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAIvD,qBAAa,UAAW,SAAQ,cAAe,YAAW,KAAK;IACC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM;IAA/F,OAAO;IAIP,mCAAmC;WACrB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,UAAU;IAI9F,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAO5E,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,GAAG,YAAY,CAAC;IAOxF,MAAM,CAAC,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAOvE,MAAM,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC;IAOpF,OAAO,CAAC,oBAAoB;YASd,kBAAkB;YAoElB,wBAAwB;YA6BxB,kCAAkC;CAQhD"}
@@ -1,5 +1,6 @@
1
1
  import { blockIdsForTransforms, blockIdToBytes } from "@optimystic/db-core";
2
2
  import { ProtocolClient } from "../protocol-client.js";
3
+ import { MAX_BLOCK_MESSAGE_BYTES } from "../protocol-limits.js";
3
4
  import { peerIdFromString } from "@libp2p/peer-id";
4
5
  export class RepoClient extends ProtocolClient {
5
6
  protocolPrefix;
@@ -67,6 +68,8 @@ export class RepoClient extends ProtocolClient {
67
68
  signal: combinedSignal,
68
69
  correlationId,
69
70
  dialTimeoutMs: options?.dialTimeoutMs,
71
+ // A get response carries block data → block cap (not control).
72
+ maxDataLength: MAX_BLOCK_MESSAGE_BYTES,
70
73
  });
71
74
  }
72
75
  finally {
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/repo/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/repo/client.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,19 @@ import type { PeerId } from "@libp2p/interface";
4
4
  import type { FretService } from "p2p-fret";
5
5
  import type { IPeerReputation } from "../reputation/types.js";
6
6
  import type { ITransactionStateStore } from "../cluster/i-transaction-state-store.js";
7
+ /** Cancel handle for an injected timer; cancels a not-yet-fired timer (safe no-op after fire/cancel). */
8
+ export type TimerCancel = () => void;
9
+ /**
10
+ * Optional injection seam for deterministic time. Production leaves both undefined and gets
11
+ * `Date.now` + an unref'd `setTimeout`; tests inject a fake clock + timer queue so scheduled
12
+ * commit-retries fire in virtual (not wall-clock) time.
13
+ */
14
+ export interface ClusterCoordinatorClock {
15
+ /** Clock (Unix ms). Defaults to `Date.now`. */
16
+ now?: () => number;
17
+ /** Schedule a one-shot timer, returning a cancel handle. Defaults to an unref'd `setTimeout`. */
18
+ setTimer?: (fn: () => void, delayMs: number) => TimerCancel;
19
+ }
7
20
  /** Manages distributed transactions across clusters */
8
21
  export declare class ClusterCoordinator {
9
22
  private readonly keyNetwork;
@@ -19,18 +32,42 @@ export declare class ClusterCoordinator {
19
32
  private readonly retryMaxIntervalMs;
20
33
  private readonly retryMaxAttempts;
21
34
  private readonly commitBroadcastImmediateRetries;
35
+ private readonly promiseImmediateRetries;
36
+ /** Injected clock/timer seam; production defaults to `Date.now` + unref'd `setTimeout`. */
37
+ private readonly now;
38
+ private readonly setTimer;
22
39
  constructor(keyNetwork: IKeyNetwork, createClusterClient: (peerId: PeerId) => ClusterClient, cfg: ClusterConsensusConfig & {
23
40
  clusterSize: number;
24
41
  }, localCluster?: {
25
42
  update: (record: ClusterRecord) => Promise<ClusterRecord>;
26
43
  peerId: PeerId;
27
44
  wasTransactionExecuted?: (messageHash: string) => boolean;
28
- } | undefined, fretService?: FretService | undefined, reputation?: IPeerReputation | undefined, stateStore?: ITransactionStateStore | undefined);
45
+ } | undefined, fretService?: FretService | undefined, reputation?: IPeerReputation | undefined, stateStore?: ITransactionStateStore | undefined, clock?: ClusterCoordinatorClock);
46
+ /**
47
+ * Invoke one cluster member's `update`, retrying transient REMOTE failures up to
48
+ * `immediateRetries` times before surfacing the error. The local cluster is invoked
49
+ * exactly once — a local throw is a real fault (validation / merge / consensus), not a
50
+ * transient transport blip. A remote call rides a libp2p stream that a circuit-relay
51
+ * ("limited") connection can reset once a per-circuit cap or reservation lapses, which
52
+ * surfaces as a StreamResetError; an immediate retry on the (usually still-warm)
53
+ * connection recovers most of those without escalating the peer to a failure. Shared by
54
+ * the promise-collection, commit-collection, and commit-broadcast phases so all three
55
+ * react to a relayed reset the same way.
56
+ */
57
+ private updateMember;
29
58
  /**
30
- * Creates a base 58 BTC string hash for a message to uniquely identify a transaction
59
+ * Creates a base58btc string hash uniquely identifying a transaction. For a v2 record the caller
60
+ * threads in the {@link membershipDigest} of the peer set so the responsible membership is bound into
61
+ * the identity (two different peer sets ⇒ two different hashes). Omitting `membershipDigestValue`
62
+ * reproduces the legacy v1 hash byte-for-byte.
63
+ *
64
+ * NOTE: the whole `message` is hashed (canonicalJson), so a transaction's advisory aged priority —
65
+ * which rides inside the pend operation as `pend.transaction.priority` (multi-collection) or
66
+ * `pend.priority` (single-collection) — is automatically covered here and by the derived
67
+ * promise/commit hashes. That is what makes priority integrity-protected in transit: a relaying peer
68
+ * cannot strip or inflate it without invalidating the message hash the members verify. No separate
69
+ * priority-hashing step is needed.
31
70
  */
32
- /** Deterministic JSON: sorts object keys so hash is order-independent */
33
- private static canonicalJson;
34
71
  private createMessageHash;
35
72
  /**
36
73
  * Gets all peers in the cluster for a specific block ID
@@ -1 +1 @@
1
- {"version":3,"file":"cluster-coordinator.d.ts","sourceRoot":"","sources":["../../../src/repo/cluster-coordinator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAgB,cAAc,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAGlJ,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAGhD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AAwBtF,uDAAuD;AACvD,qBAAa,kBAAkB;IAS7B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IACpC,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;IAK9B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAC7B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAC5B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAlB7B,OAAO,CAAC,YAAY,CAAmD;IACvE,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAS;IAChD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAC5C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAC5C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,+BAA+B,CAAS;gBAGvC,UAAU,EAAE,WAAW,EACvB,mBAAmB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,aAAa,EACtD,GAAG,EAAE,sBAAsB,GAAG;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,EACrD,YAAY,CAAC,EAAE;QAC/B,MAAM,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;QAC1D,MAAM,EAAE,MAAM,CAAC;QACf,sBAAsB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC;KAC1D,YAAA,EACgB,WAAW,CAAC,EAAE,WAAW,YAAA,EACzB,UAAU,CAAC,EAAE,eAAe,YAAA,EAC5B,UAAU,CAAC,EAAE,sBAAsB,YAAA;IASrD;;OAEG;IACH,yEAAyE;IACzE,OAAO,CAAC,MAAM,CAAC,aAAa;YAQd,iBAAiB;IAM/B;;OAEG;YACW,kBAAkB;IAahC,OAAO,CAAC,UAAU;IA6BlB;;;OAGG;IACG,yBAAyB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC;QAC3G,MAAM,EAAE,aAAa,CAAC;QACtB,aAAa,EAAE,OAAO,CAAC;KACvB,CAAC;IAuEF;;OAEG;YACW,kBAAkB;IAyF1B,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IAKvD;;;OAGG;YACW,oBAAoB;IAmClC;;OAEG;YACW,eAAe;IA6F7B;;OAEG;YACW,iBAAiB;IAiH/B;;;;;;OAMG;YACW,qBAAqB;IA8CnC,OAAO,CAAC,uBAAuB;IAgB/B,OAAO,CAAC,mBAAmB;YAqCb,YAAY;IAkD1B,OAAO,CAAC,UAAU;IAoBlB,iEAAiE;IACjE,OAAO,CAAC,uBAAuB;IAgB/B,gEAAgE;IAChE,OAAO,CAAC,sBAAsB;IAM9B;;;OAGG;IACG,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;CA+B1C"}
1
+ {"version":3,"file":"cluster-coordinator.d.ts","sourceRoot":"","sources":["../../../src/repo/cluster-coordinator.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,22 @@
1
1
  import { peerIdFromString } from "@libp2p/peer-id";
2
- import { base58btc } from "multiformats/bases/base58";
3
- import { sha256 } from "multiformats/hashes/sha2";
2
+ import { CURRENT_MEMBERSHIP_VERSION, computeClusterMessageHash, membershipDigest } from "@optimystic/db-core";
3
+ import { ClusterClient } from "../cluster/client.js";
4
4
  import { Pending } from "@optimystic/db-core";
5
5
  import { createLogger, verbose } from '../logger.js';
6
6
  import { PenaltyReason } from "../reputation/types.js";
7
7
  const log = createLogger('cluster');
8
+ /**
9
+ * Production timer binding: a one-shot `setTimeout` whose handle is **unref'd** so a pending
10
+ * commit-retry (or the deferred transaction cleanup) never keeps an otherwise-idle process alive.
11
+ * The returned handle clears the timeout (idempotent). Mirrors the reactivity rotation
12
+ * re-registration scheduler's `defaultSetTimer` (see reactivity/rotation-rereg-scheduler.ts).
13
+ */
14
+ function defaultSetTimer(fn, delayMs) {
15
+ const handle = setTimeout(fn, delayMs);
16
+ // An idle retry/cleanup timer must not pin a process (mirror rotation re-registration + push-state gossip).
17
+ handle.unref?.();
18
+ return () => clearTimeout(handle);
19
+ }
8
20
  /** Manages distributed transactions across clusters */
9
21
  export class ClusterCoordinator {
10
22
  keyNetwork;
@@ -20,7 +32,11 @@ export class ClusterCoordinator {
20
32
  retryMaxIntervalMs;
21
33
  retryMaxAttempts;
22
34
  commitBroadcastImmediateRetries;
23
- constructor(keyNetwork, createClusterClient, cfg, localCluster, fretService, reputation, stateStore) {
35
+ promiseImmediateRetries;
36
+ /** Injected clock/timer seam; production defaults to `Date.now` + unref'd `setTimeout`. */
37
+ now;
38
+ setTimer;
39
+ constructor(keyNetwork, createClusterClient, cfg, localCluster, fretService, reputation, stateStore, clock) {
24
40
  this.keyNetwork = keyNetwork;
25
41
  this.createClusterClient = createClusterClient;
26
42
  this.cfg = cfg;
@@ -33,20 +49,62 @@ export class ClusterCoordinator {
33
49
  this.retryMaxIntervalMs = cfg.commitBroadcastRetryMaxIntervalMs ?? 8000;
34
50
  this.retryMaxAttempts = cfg.commitBroadcastRetryMaxAttempts ?? 5;
35
51
  this.commitBroadcastImmediateRetries = cfg.commitBroadcastImmediateRetries ?? 1;
52
+ this.promiseImmediateRetries = cfg.promiseImmediateRetries ?? 1;
53
+ this.now = clock?.now ?? (() => Date.now());
54
+ this.setTimer = clock?.setTimer ?? defaultSetTimer;
36
55
  }
37
56
  /**
38
- * Creates a base 58 BTC string hash for a message to uniquely identify a transaction
57
+ * Invoke one cluster member's `update`, retrying transient REMOTE failures up to
58
+ * `immediateRetries` times before surfacing the error. The local cluster is invoked
59
+ * exactly once — a local throw is a real fault (validation / merge / consensus), not a
60
+ * transient transport blip. A remote call rides a libp2p stream that a circuit-relay
61
+ * ("limited") connection can reset once a per-circuit cap or reservation lapses, which
62
+ * surfaces as a StreamResetError; an immediate retry on the (usually still-warm)
63
+ * connection recovers most of those without escalating the peer to a failure. Shared by
64
+ * the promise-collection, commit-collection, and commit-broadcast phases so all three
65
+ * react to a relayed reset the same way.
39
66
  */
40
- /** Deterministic JSON: sorts object keys so hash is order-independent */
41
- static canonicalJson(value) {
42
- return JSON.stringify(value, (_, v) => v && typeof v === 'object' && !Array.isArray(v)
43
- ? Object.keys(v).sort().reduce((o, k) => { o[k] = v[k]; return o; }, {})
44
- : v);
67
+ async updateMember(peerIdStr, record, immediateRetries, phase) {
68
+ const isLocal = this.localCluster && peerIdStr === this.localCluster.peerId.toString();
69
+ if (isLocal) {
70
+ return await this.localCluster.update(record);
71
+ }
72
+ const maxAttempts = 1 + Math.max(0, immediateRetries);
73
+ let lastError;
74
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
75
+ try {
76
+ return await this.createClusterClient(peerIdFromString(peerIdStr)).update(record);
77
+ }
78
+ catch (err) {
79
+ lastError = err;
80
+ if (attempt < maxAttempts) {
81
+ log('cluster-tx:member-update-retry', {
82
+ messageHash: record.messageHash,
83
+ peerId: peerIdStr,
84
+ phase,
85
+ attempt,
86
+ error: err instanceof Error ? err.message : String(err)
87
+ });
88
+ }
89
+ }
90
+ }
91
+ throw lastError;
45
92
  }
46
- async createMessageHash(message) {
47
- const msgBytes = new TextEncoder().encode(ClusterCoordinator.canonicalJson(message));
48
- const hashBytes = await sha256.digest(msgBytes);
49
- return base58btc.encode(hashBytes.digest);
93
+ /**
94
+ * Creates a base58btc string hash uniquely identifying a transaction. For a v2 record the caller
95
+ * threads in the {@link membershipDigest} of the peer set so the responsible membership is bound into
96
+ * the identity (two different peer sets ⇒ two different hashes). Omitting `membershipDigestValue`
97
+ * reproduces the legacy v1 hash byte-for-byte.
98
+ *
99
+ * NOTE: the whole `message` is hashed (canonicalJson), so a transaction's advisory aged priority —
100
+ * which rides inside the pend operation as `pend.transaction.priority` (multi-collection) or
101
+ * `pend.priority` (single-collection) — is automatically covered here and by the derived
102
+ * promise/commit hashes. That is what makes priority integrity-protected in transit: a relaying peer
103
+ * cannot strip or inflate it without invalidating the message hash the members verify. No separate
104
+ * priority-hashing step is needed.
105
+ */
106
+ async createMessageHash(message, membershipDigestValue) {
107
+ return computeClusterMessageHash(message, membershipDigestValue);
50
108
  }
51
109
  /**
52
110
  * Gets all peers in the cluster for a specific block ID
@@ -64,11 +122,15 @@ export class ClusterCoordinator {
64
122
  return {};
65
123
  }
66
124
  }
67
- makeRecord(peers, messageHash, message) {
125
+ makeRecord(peers, messageHash, message, membershipDigestValue) {
68
126
  const peerCount = Object.keys(peers ?? {}).length;
69
127
  const record = {
70
128
  messageHash,
71
129
  peers,
130
+ // v2: bind the responsible membership into the signed identity. messageHash was computed over
131
+ // this same digest, so a different peer set would have produced a different messageHash.
132
+ membershipVersion: CURRENT_MEMBERSHIP_VERSION,
133
+ membershipDigest: membershipDigestValue,
72
134
  message,
73
135
  coordinatingBlockIds: message.coordinatingBlockIds,
74
136
  promises: {},
@@ -98,10 +160,14 @@ export class ClusterCoordinator {
98
160
  async executeClusterTransaction(blockId, message, _options) {
99
161
  // Get the cluster peers for this block
100
162
  const peers = await this.getClusterForBlock(blockId);
101
- // Create a unique hash for this transaction
102
- const messageHash = await this.createMessageHash(message);
163
+ // Bind the responsible membership into the transaction identity (v2): the digest is folded into
164
+ // the messageHash below, so two different peer sets produce two different messageHashes rather
165
+ // than one hash with a silent internal disagreement about who is responsible.
166
+ const membershipDigestValue = await membershipDigest(peers);
167
+ // Create a unique hash for this transaction (over message + membership digest)
168
+ const messageHash = await this.createMessageHash(message, membershipDigestValue);
103
169
  // Create a cluster record for this transaction
104
- const record = this.makeRecord(peers, messageHash, message);
170
+ const record = this.makeRecord(peers, messageHash, message, membershipDigestValue);
105
171
  log('cluster-tx:start', {
106
172
  messageHash,
107
173
  blockId,
@@ -119,7 +185,7 @@ export class ClusterCoordinator {
119
185
  messageHash,
120
186
  record,
121
187
  pending,
122
- lastUpdate: Date.now()
188
+ lastUpdate: this.now()
123
189
  };
124
190
  this.transactions.set(messageHash, state);
125
191
  this.persistCoordinatorState(messageHash, record, 'promising');
@@ -150,7 +216,7 @@ export class ClusterCoordinator {
150
216
  // Let the retry completion or abort handle cleanup
151
217
  if (!stored?.retry) {
152
218
  // Wait a bit before cleanup to allow any in-flight responses to arrive
153
- setTimeout(() => {
219
+ this.setTimer(() => {
154
220
  this.transactions.delete(messageHash);
155
221
  this.deleteCoordinatorState(messageHash);
156
222
  log('cluster-tx:transaction-remove', {
@@ -240,6 +306,11 @@ export class ClusterCoordinator {
240
306
  rejectionCount,
241
307
  peerCount
242
308
  });
309
+ // [dispute-subsystem-dormant] Evidence is computed and persisted but initiateDispute() is
310
+ // intentionally NOT called here. Dispute origination stays dormant pending arbitrator-set
311
+ // anchoring — without it a forged synthetic cohort passes resolution.
312
+ // Gate: tickets/backlog/hardening/invalidation-live-wiring-requires-arbitrator-set-anchoring
313
+ // Wiring plan: tickets/backlog/feat-dispute-subsystem-live-activation
243
314
  }
244
315
  this.persistCoordinatorState(promised.record.messageHash, promised.record, 'committing');
245
316
  return await this.commitTransaction(promised.record);
@@ -277,13 +348,18 @@ export class ClusterCoordinator {
277
348
  // Ignore errors
278
349
  }
279
350
  }
280
- // Fallback: accept small clusters in development/testing scenarios
281
- // In production, FRET should provide validation
282
- log('cluster-tx:small-cluster-accepted-without-validation', {
351
+ // Fallback: with no confident network-size estimate, fail CLOSED by default.
352
+ // An undersized cluster with no way to justify its size is unsafe (a lone/
353
+ // near-lone node could rubber-stamp its own writes), so reject unless the
354
+ // operator has explicitly opted in via allowUnvalidatedSmallCluster (e.g.
355
+ // single-node / local dev knowingly running below the floor).
356
+ const admit = this.cfg.allowUnvalidatedSmallCluster ?? false;
357
+ log('cluster-tx:small-cluster-no-confident-estimate', {
283
358
  localSize,
284
- reason: 'no-confident-network-size-estimate'
359
+ reason: 'no-confident-network-size-estimate',
360
+ admit
285
361
  });
286
- return true;
362
+ return admit;
287
363
  }
288
364
  /**
289
365
  * Collects promises from all peers in the cluster
@@ -298,14 +374,15 @@ export class ClusterCoordinator {
298
374
  }));
299
375
  log('cluster-tx:promise-peers', { messageHash: record.messageHash, peers: peerDetail });
300
376
  }
301
- // For each peer, create a client and request a promise
377
+ // For each peer, create a client and request a promise. A remote promise rides
378
+ // a libp2p stream that a relayed (limited) connection can reset transiently, so
379
+ // each remote request gets `promiseImmediateRetries` in-line re-attempts before
380
+ // it counts as a failure — without this a single relayed reset drops the peer and
381
+ // sinks super-majority (the commit broadcast already has the same guard).
302
382
  const promiseRequests = peerIds.map(peerIdStr => {
303
383
  const isLocal = this.localCluster && peerIdStr === this.localCluster.peerId.toString();
304
384
  log('cluster-tx:promise-request', { messageHash: record.messageHash, peerId: peerIdStr, isLocal });
305
- const promise = isLocal
306
- ? this.localCluster.update(record)
307
- : this.createClusterClient(peerIdFromString(peerIdStr)).update(record);
308
- return new Pending(promise);
385
+ return new Pending(this.updateMember(peerIdStr, record, this.promiseImmediateRetries, 'promise'));
309
386
  });
310
387
  // Wait for all promises to complete
311
388
  const results = await Promise.all(promiseRequests.map((p, idx) => p.result().then(res => {
@@ -396,6 +473,10 @@ export class ClusterCoordinator {
396
473
  const commitPayload = {
397
474
  ...record
398
475
  };
476
+ // No per-peer immediate retry here: a commit-collection failure is recovered
477
+ // downstream by broadcastMergedRecord's in-line retry and the scheduled
478
+ // commit-retry timer. (The promise phase has no such backstop, which is why
479
+ // collectPromises gets the immediate retry instead.)
399
480
  const commitRequests = peerIds.map(peerIdStr => {
400
481
  const isLocal = this.localCluster && peerIdStr === this.localCluster.peerId.toString();
401
482
  log('cluster-tx:commit-request', { messageHash: record.messageHash, peerId: peerIdStr, isLocal });
@@ -499,48 +580,19 @@ export class ClusterCoordinator {
499
580
  * Local cluster is invoked exactly once — local failures are fatal, not transient.
500
581
  */
501
582
  async broadcastMergedRecord(record, peerIds) {
502
- const maxAttempts = 1 + Math.max(0, this.commitBroadcastImmediateRetries);
503
583
  const results = await Promise.all(peerIds.map(async (peerIdStr) => {
504
- const isLocal = this.localCluster && peerIdStr === this.localCluster.peerId.toString();
505
- if (isLocal) {
506
- try {
507
- await this.localCluster.update(record);
508
- return { peerId: peerIdStr, success: true };
509
- }
510
- catch (err) {
511
- log('cluster-tx:consensus-broadcast-error', {
512
- messageHash: record.messageHash,
513
- peerId: peerIdStr,
514
- error: err.message
515
- });
516
- return { peerId: peerIdStr, success: false };
517
- }
584
+ try {
585
+ await this.updateMember(peerIdStr, record, this.commitBroadcastImmediateRetries, 'commit-broadcast');
586
+ return { peerId: peerIdStr, success: true };
518
587
  }
519
- let lastError;
520
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
521
- try {
522
- await this.createClusterClient(peerIdFromString(peerIdStr)).update(record);
523
- return { peerId: peerIdStr, success: true };
524
- }
525
- catch (err) {
526
- lastError = err;
527
- if (attempt < maxAttempts) {
528
- log('cluster-tx:consensus-broadcast-retry', {
529
- messageHash: record.messageHash,
530
- peerId: peerIdStr,
531
- attempt,
532
- error: err.message
533
- });
534
- }
535
- }
588
+ catch (err) {
589
+ log('cluster-tx:consensus-broadcast-error', {
590
+ messageHash: record.messageHash,
591
+ peerId: peerIdStr,
592
+ error: err instanceof Error ? err.message : String(err)
593
+ });
594
+ return { peerId: peerIdStr, success: false };
536
595
  }
537
- log('cluster-tx:consensus-broadcast-error', {
538
- messageHash: record.messageHash,
539
- peerId: peerIdStr,
540
- attempts: maxAttempts,
541
- error: lastError instanceof Error ? lastError.message : String(lastError)
542
- });
543
- return { peerId: peerIdStr, success: false };
544
596
  }));
545
597
  const failures = results.filter(r => !r.success).map(r => r.peerId);
546
598
  return { failures };
@@ -552,7 +604,7 @@ export class ClusterCoordinator {
552
604
  return;
553
605
  }
554
606
  state.record = { ...record };
555
- state.lastUpdate = Date.now();
607
+ state.lastUpdate = this.now();
556
608
  log('cluster-tx:transaction-update', {
557
609
  messageHash: record.messageHash,
558
610
  stage,
@@ -577,17 +629,15 @@ export class ClusterCoordinator {
577
629
  }
578
630
  const pendingPeers = new Set(missingPeers);
579
631
  const baseInterval = existing ? Math.min(existing.intervalMs * this.retryBackoffFactor, this.retryMaxIntervalMs) : this.retryInitialIntervalMs;
580
- if (existing?.timer) {
581
- clearTimeout(existing.timer);
582
- }
583
- const timer = setTimeout(() => {
632
+ existing?.cancel?.();
633
+ const cancel = this.setTimer(() => {
584
634
  void this.retryCommits(messageHash);
585
635
  }, baseInterval);
586
636
  state.retry = {
587
637
  pendingPeers,
588
638
  attempt: nextAttempt,
589
639
  intervalMs: baseInterval,
590
- timer
640
+ cancel
591
641
  };
592
642
  this.persistCoordinatorState(messageHash, state.record, 'broadcasting', {
593
643
  pendingPeers: Array.from(pendingPeers),
@@ -651,12 +701,10 @@ export class ClusterCoordinator {
651
701
  if (!state?.retry) {
652
702
  return;
653
703
  }
654
- if (state.retry.timer) {
655
- clearTimeout(state.retry.timer);
656
- }
704
+ state.retry.cancel?.();
657
705
  state.retry = undefined;
658
706
  // Clean up the transaction after retry is complete
659
- setTimeout(() => {
707
+ this.setTimer(() => {
660
708
  this.transactions.delete(messageHash);
661
709
  this.deleteCoordinatorState(messageHash);
662
710
  log('cluster-tx:transaction-remove', {
@@ -672,7 +720,7 @@ export class ClusterCoordinator {
672
720
  this.stateStore.saveCoordinatorState(messageHash, {
673
721
  messageHash,
674
722
  record,
675
- lastUpdate: Date.now(),
723
+ lastUpdate: this.now(),
676
724
  phase,
677
725
  retryState
678
726
  }).catch(err => log('cluster-tx:persist-error', { messageHash, error: err.message }));
@@ -695,7 +743,7 @@ export class ClusterCoordinator {
695
743
  for (const state of states) {
696
744
  const { messageHash } = state;
697
745
  // Expired — clean up
698
- if (state.record.message.expiration && state.record.message.expiration < Date.now()) {
746
+ if (state.record.message.expiration && state.record.message.expiration < this.now()) {
699
747
  log('cluster-tx:recovery-expired', { messageHash });
700
748
  await this.stateStore.deleteCoordinatorState(messageHash);
701
749
  continue;