@serfab/cadre-core 1.16.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. package/README.md +4 -3
  2. package/dist/bootstrap-peer-store-file.js +1 -1
  3. package/dist/bootstrap-peer-store.d.ts +1 -1
  4. package/dist/bootstrap-peer-store.js +4 -4
  5. package/dist/cadre-invite-protocol.d.ts +81 -142
  6. package/dist/cadre-invite-protocol.js +168 -458
  7. package/dist/cadre-invite-protocol.js.map +1 -1
  8. package/dist/cadre-join-request.d.ts +15 -2
  9. package/dist/cadre-join-request.js +22 -3
  10. package/dist/cadre-join-request.js.map +1 -1
  11. package/dist/cadre-node.d.ts +1089 -475
  12. package/dist/cadre-node.js +2170 -1037
  13. package/dist/cadre-node.js.map +1 -1
  14. package/dist/control-authorization.d.ts +36 -14
  15. package/dist/control-authorization.js +20 -3
  16. package/dist/control-authorization.js.map +1 -1
  17. package/dist/control-cohort.d.ts +88 -32
  18. package/dist/control-cohort.js +91 -33
  19. package/dist/control-cohort.js.map +1 -1
  20. package/dist/control-database.d.ts +856 -318
  21. package/dist/control-database.js +1422 -701
  22. package/dist/control-database.js.map +1 -1
  23. package/dist/control-formation-recorder.d.ts +46 -43
  24. package/dist/control-formation-recorder.js +77 -78
  25. package/dist/control-formation-recorder.js.map +1 -1
  26. package/dist/control-protocol-guard.d.ts +11 -4
  27. package/dist/control-protocol-guard.js +20 -5
  28. package/dist/control-protocol-guard.js.map +1 -1
  29. package/dist/control-schema-version.d.ts +97 -0
  30. package/dist/control-schema-version.js +225 -0
  31. package/dist/control-schema-version.js.map +1 -0
  32. package/dist/control-schema.d.ts +45 -5
  33. package/dist/control-schema.js +262 -78
  34. package/dist/control-schema.js.map +1 -1
  35. package/dist/control-write-retry.d.ts +45 -10
  36. package/dist/control-write-retry.js +92 -22
  37. package/dist/control-write-retry.js.map +1 -1
  38. package/dist/delegate-admission.d.ts +13 -0
  39. package/dist/delegate-admission.js +27 -0
  40. package/dist/delegate-admission.js.map +1 -1
  41. package/dist/ed25519-key.d.ts +10 -7
  42. package/dist/ed25519-key.js +23 -20
  43. package/dist/ed25519-key.js.map +1 -1
  44. package/dist/edge-node/config.d.ts +122 -0
  45. package/dist/edge-node/config.js +199 -0
  46. package/dist/edge-node/config.js.map +1 -0
  47. package/dist/edge-node/dissolve.d.ts +95 -0
  48. package/dist/edge-node/dissolve.js +184 -0
  49. package/dist/edge-node/dissolve.js.map +1 -0
  50. package/dist/edge-node/edge-join.d.ts +44 -0
  51. package/dist/edge-node/edge-join.js +227 -0
  52. package/dist/edge-node/edge-join.js.map +1 -0
  53. package/dist/edge-node/edge-node.d.ts +295 -0
  54. package/dist/edge-node/edge-node.js +704 -0
  55. package/dist/edge-node/edge-node.js.map +1 -0
  56. package/dist/edge-node/index.d.ts +18 -0
  57. package/dist/edge-node/index.js +18 -0
  58. package/dist/edge-node/index.js.map +1 -0
  59. package/dist/edge-node/join-credential.d.ts +11 -0
  60. package/dist/edge-node/join-credential.js +11 -0
  61. package/dist/edge-node/join-credential.js.map +1 -0
  62. package/dist/edge-node/lazy-raw-storage.d.ts +40 -0
  63. package/dist/edge-node/lazy-raw-storage.js +134 -0
  64. package/dist/edge-node/lazy-raw-storage.js.map +1 -0
  65. package/dist/edge-node/node-local.d.ts +60 -0
  66. package/dist/edge-node/node-local.js +58 -0
  67. package/dist/edge-node/node-local.js.map +1 -0
  68. package/dist/edge-node/options.d.ts +83 -0
  69. package/dist/edge-node/options.js +110 -0
  70. package/dist/edge-node/options.js.map +1 -0
  71. package/dist/edge-node/owner-grant.d.ts +41 -0
  72. package/dist/edge-node/owner-grant.js +38 -0
  73. package/dist/edge-node/owner-grant.js.map +1 -0
  74. package/dist/edge-node/platform.d.ts +140 -0
  75. package/dist/edge-node/platform.js +12 -0
  76. package/dist/edge-node/platform.js.map +1 -0
  77. package/dist/edge-node/strand-move.d.ts +115 -0
  78. package/dist/edge-node/strand-move.js +223 -0
  79. package/dist/edge-node/strand-move.js.map +1 -0
  80. package/dist/edge-node/strands.d.ts +28 -0
  81. package/dist/edge-node/strands.js +60 -0
  82. package/dist/edge-node/strands.js.map +1 -0
  83. package/dist/enrolled-machine-store.d.ts +3 -3
  84. package/dist/enrolled-machine-store.js +3 -3
  85. package/dist/formation-token.d.ts +48 -0
  86. package/dist/formation-token.js +26 -0
  87. package/dist/formation-token.js.map +1 -0
  88. package/dist/index.d.ts +27 -17
  89. package/dist/index.js +39 -17
  90. package/dist/index.js.map +1 -1
  91. package/dist/joined-strand-store.d.ts +29 -12
  92. package/dist/joined-strand-store.js +66 -27
  93. package/dist/joined-strand-store.js.map +1 -1
  94. package/dist/key-store.d.ts +9 -4
  95. package/dist/key-store.js +9 -4
  96. package/dist/key-store.js.map +1 -1
  97. package/dist/link-budget.d.ts +9 -7
  98. package/dist/link-budget.js +9 -7
  99. package/dist/link-budget.js.map +1 -1
  100. package/dist/machine-removal.d.ts +19 -39
  101. package/dist/machine-removal.js +24 -98
  102. package/dist/machine-removal.js.map +1 -1
  103. package/dist/member-redemption.d.ts +256 -0
  104. package/dist/member-redemption.js +490 -0
  105. package/dist/member-redemption.js.map +1 -0
  106. package/dist/membership-view.d.ts +91 -0
  107. package/dist/membership-view.js +110 -0
  108. package/dist/membership-view.js.map +1 -0
  109. package/dist/owner-anchor-sync.d.ts +4 -4
  110. package/dist/owner-anchor-sync.js +16 -15
  111. package/dist/owner-anchor-sync.js.map +1 -1
  112. package/dist/owner-grant-protocol.d.ts +251 -0
  113. package/dist/owner-grant-protocol.js +344 -0
  114. package/dist/owner-grant-protocol.js.map +1 -0
  115. package/dist/owner-key-export.d.ts +70 -0
  116. package/dist/owner-key-export.js +279 -0
  117. package/dist/owner-key-export.js.map +1 -0
  118. package/dist/owner-key-flows.d.ts +55 -0
  119. package/dist/owner-key-flows.js +60 -0
  120. package/dist/owner-key-flows.js.map +1 -0
  121. package/dist/owner-key-store.d.ts +31 -0
  122. package/dist/owner-key-store.js +81 -0
  123. package/dist/owner-key-store.js.map +1 -0
  124. package/dist/owner-keys.d.ts +78 -0
  125. package/dist/owner-keys.js +133 -0
  126. package/dist/owner-keys.js.map +1 -0
  127. package/dist/owner-signer.d.ts +54 -0
  128. package/dist/owner-signer.js +51 -0
  129. package/dist/owner-signer.js.map +1 -0
  130. package/dist/peer-addr-book.d.ts +10 -1
  131. package/dist/peer-addr-book.js +4 -3
  132. package/dist/peer-addr-book.js.map +1 -1
  133. package/dist/peer-authorization.d.ts +83 -18
  134. package/dist/peer-authorization.js +123 -53
  135. package/dist/peer-authorization.js.map +1 -1
  136. package/dist/peer-join-backfill.d.ts +89 -20
  137. package/dist/peer-join-backfill.js +265 -108
  138. package/dist/peer-join-backfill.js.map +1 -1
  139. package/dist/pending-join-runner.d.ts +48 -18
  140. package/dist/pending-join-runner.js +74 -56
  141. package/dist/pending-join-runner.js.map +1 -1
  142. package/dist/provider/rent-node.js +1 -1
  143. package/dist/provider/rent-node.js.map +1 -1
  144. package/dist/seed-bootstrap.d.ts +162 -133
  145. package/dist/seed-bootstrap.js +300 -283
  146. package/dist/seed-bootstrap.js.map +1 -1
  147. package/dist/seed-trust-policy.js +4 -4
  148. package/dist/strand-addr-protocol.d.ts +4 -1
  149. package/dist/strand-addr-protocol.js +8 -2
  150. package/dist/strand-addr-protocol.js.map +1 -1
  151. package/dist/strand-cohort.d.ts +3 -0
  152. package/dist/strand-cohort.js.map +1 -1
  153. package/dist/strand-database.d.ts +24 -2
  154. package/dist/strand-database.js +29 -6
  155. package/dist/strand-database.js.map +1 -1
  156. package/dist/strand-first-sync-gate.d.ts +176 -88
  157. package/dist/strand-first-sync-gate.js +288 -121
  158. package/dist/strand-first-sync-gate.js.map +1 -1
  159. package/dist/strand-formation-deadlines.d.ts +9 -9
  160. package/dist/strand-formation-deadlines.js +9 -9
  161. package/dist/strand-formation-manager.d.ts +23 -17
  162. package/dist/strand-formation-manager.js +46 -44
  163. package/dist/strand-formation-manager.js.map +1 -1
  164. package/dist/strand-formation-protocol.d.ts +5 -8
  165. package/dist/strand-formation-protocol.js +101 -16
  166. package/dist/strand-formation-protocol.js.map +1 -1
  167. package/dist/strand-instance-manager.d.ts +27 -18
  168. package/dist/strand-instance-manager.js +119 -50
  169. package/dist/strand-instance-manager.js.map +1 -1
  170. package/dist/strand-membership-reconciler.d.ts +16 -13
  171. package/dist/strand-membership-reconciler.js +30 -22
  172. package/dist/strand-membership-reconciler.js.map +1 -1
  173. package/dist/strand-membership-writer.d.ts +45 -22
  174. package/dist/strand-membership-writer.js +226 -131
  175. package/dist/strand-membership-writer.js.map +1 -1
  176. package/dist/strand-move.d.ts +6 -5
  177. package/dist/strand-move.js +36 -32
  178. package/dist/strand-move.js.map +1 -1
  179. package/dist/strand-peer-redial.js +2 -3
  180. package/dist/strand-peer-redial.js.map +1 -1
  181. package/dist/strand-revocation-enforcer.d.ts +134 -60
  182. package/dist/strand-revocation-enforcer.js +144 -71
  183. package/dist/strand-revocation-enforcer.js.map +1 -1
  184. package/dist/strand-solicitation.d.ts +50 -39
  185. package/dist/strand-solicitation.js +10 -3
  186. package/dist/strand-solicitation.js.map +1 -1
  187. package/dist/strand-watcher.d.ts +80 -13
  188. package/dist/strand-watcher.js +152 -48
  189. package/dist/strand-watcher.js.map +1 -1
  190. package/dist/table-change-watch.d.ts +63 -0
  191. package/dist/table-change-watch.js +209 -0
  192. package/dist/table-change-watch.js.map +1 -0
  193. package/dist/timeout-scheduler.d.ts +4 -3
  194. package/dist/timeout-scheduler.js +4 -3
  195. package/dist/timeout-scheduler.js.map +1 -1
  196. package/dist/types.d.ts +374 -150
  197. package/dist/types.js +4 -4
  198. package/dist/types.js.map +1 -1
  199. package/package.json +17 -8
  200. package/src/bootstrap-peer-store-file.ts +44 -44
  201. package/src/bootstrap-peer-store.ts +214 -214
  202. package/src/cadre-invite-protocol.ts +740 -1052
  203. package/src/cadre-join-request.ts +24 -3
  204. package/src/cadre-node.ts +2402 -1079
  205. package/src/control-authorization.ts +47 -14
  206. package/src/control-cohort.ts +204 -128
  207. package/src/control-database.ts +1749 -820
  208. package/src/control-formation-recorder.ts +359 -353
  209. package/src/control-protocol-guard.ts +23 -6
  210. package/src/control-schema-version.ts +301 -0
  211. package/src/control-schema.ts +273 -78
  212. package/src/control-write-retry.ts +641 -567
  213. package/src/delegate-admission.ts +351 -314
  214. package/src/ed25519-key.ts +174 -171
  215. package/src/edge-node/config.ts +277 -0
  216. package/src/edge-node/dissolve.ts +251 -0
  217. package/src/edge-node/edge-join.ts +319 -0
  218. package/src/edge-node/edge-node.ts +1045 -0
  219. package/src/edge-node/index.ts +59 -0
  220. package/src/edge-node/join-credential.ts +16 -0
  221. package/src/edge-node/lazy-raw-storage.ts +178 -0
  222. package/src/edge-node/node-local.ts +84 -0
  223. package/src/edge-node/options.ts +179 -0
  224. package/src/edge-node/owner-grant.ts +63 -0
  225. package/src/edge-node/platform.ts +151 -0
  226. package/src/edge-node/strand-move.ts +270 -0
  227. package/src/edge-node/strands.ts +72 -0
  228. package/src/enrolled-machine-store.ts +3 -3
  229. package/src/formation-token.ts +63 -0
  230. package/src/index.ts +899 -789
  231. package/src/joined-strand-store.ts +73 -28
  232. package/src/key-store.ts +10 -4
  233. package/src/link-budget.ts +9 -7
  234. package/src/machine-removal.ts +26 -111
  235. package/src/member-redemption.ts +649 -0
  236. package/src/membership-view.ts +144 -0
  237. package/src/owner-anchor-sync.ts +19 -18
  238. package/src/owner-grant-protocol.ts +547 -0
  239. package/src/owner-key-export.ts +348 -0
  240. package/src/owner-key-flows.ts +109 -0
  241. package/src/owner-key-store.ts +85 -0
  242. package/src/owner-keys.ts +178 -0
  243. package/src/owner-signer.ts +94 -0
  244. package/src/peer-addr-book.ts +4 -3
  245. package/src/peer-authorization.ts +558 -488
  246. package/src/peer-join-backfill.ts +971 -761
  247. package/src/pending-join-runner.ts +76 -53
  248. package/src/provider/rent-node.ts +1 -1
  249. package/src/seed-bootstrap.ts +343 -349
  250. package/src/seed-trust-policy.ts +4 -4
  251. package/src/strand-addr-protocol.ts +547 -538
  252. package/src/strand-cohort.ts +4 -0
  253. package/src/strand-database.ts +352 -319
  254. package/src/strand-first-sync-gate.ts +334 -133
  255. package/src/strand-formation-deadlines.ts +227 -227
  256. package/src/strand-formation-manager.ts +731 -725
  257. package/src/strand-formation-protocol.ts +122 -24
  258. package/src/strand-instance-manager.ts +2092 -2026
  259. package/src/strand-membership-reconciler.ts +33 -25
  260. package/src/strand-membership-writer.ts +2093 -1974
  261. package/src/strand-move.ts +50 -38
  262. package/src/strand-peer-redial.ts +2 -3
  263. package/src/strand-revocation-enforcer.ts +740 -654
  264. package/src/strand-solicitation.ts +61 -34
  265. package/src/strand-watcher.ts +175 -56
  266. package/src/table-change-watch.ts +285 -0
  267. package/src/timeout-scheduler.ts +29 -28
  268. package/src/types.ts +391 -152
@@ -1,6 +1,6 @@
1
1
  import debug from 'debug';
2
2
  import { digest, verify } from '@optimystic/quereus-plugin-crypto';
3
- import { controlAuthorizationFields, unboundAuthorizationFields, cadreInviteRowFields } from './control-authorization.js';
3
+ import { controlAuthorizationFields, unboundAuthorizationFields, cadreInviteRowFields, ownerGrantRowFields } from './control-authorization.js';
4
4
  import { ed25519PublicKeyB64FromPeerId } from './ed25519-key.js';
5
5
  const log = debug('sereus:cadre:peer-authorization');
6
6
  /**
@@ -142,20 +142,22 @@ export function verifyRevocationSigner(partyId, row) {
142
142
  /**
143
143
  * Canonical digest an owner signs to seat a further `OwnerKey` row — the signed-add branch
144
144
  * of `OwnerKey.Authorized`, which stores the pair as `VouchOwner` / `VouchSig`. SQL mirror:
145
- * `digest('CadreControl.OwnerKey', 'add', party_id(), new.Key, new.StampId)`. The removal
146
- * digest needs no builder here: it is the generic guarded `'remove'` digest over (Key, StampId).
145
+ * `digest('CadreControl.OwnerKey', 'add', party_id(), new.Key, coalesce(new.Label, ''), new.StampId)`.
146
+ * The removal digest needs no builder here: it is the generic guarded `'remove'` digest over
147
+ * (Key, StampId).
147
148
  */
148
- export function ownerKeyAddDigest(partyId, key, stampId) {
149
- return taggedDigest('CadreControl.OwnerKey', 'add', partyId, [key, stampId]);
149
+ export function ownerKeyAddDigest(partyId, key, label, stampId) {
150
+ return taggedDigest('CadreControl.OwnerKey', 'add', partyId, [key, label ?? '', stampId]);
150
151
  }
151
152
  /**
152
153
  * Does an owner-signed `OwnerKey` row's stored voucher verify — `vouchSig` by `vouchOwner`
153
- * over {@link ownerKeyAddDigest} for (`partyId`, `key`, `stampId`)? Whether `vouchOwner` is
154
- * anchored is the caller's question, as for {@link verifyCadrePeerVoucher}. Never throws.
154
+ * over {@link ownerKeyAddDigest} for (`partyId`, `key`, `label`, `stampId`)? Whether
155
+ * `vouchOwner` is anchored is the caller's question, as for {@link verifyCadrePeerVoucher}.
156
+ * Never throws.
155
157
  */
156
- export function verifyOwnerKeyVoucher(partyId, key, stampId, vouchOwner, vouchSig) {
158
+ export function verifyOwnerKeyVoucher(partyId, key, label, stampId, vouchOwner, vouchSig) {
157
159
  try {
158
- return verifyB64(ownerKeyAddDigest(partyId, key, stampId), vouchSig, vouchOwner);
160
+ return verifyB64(ownerKeyAddDigest(partyId, key, label, stampId), vouchSig, vouchOwner);
159
161
  }
160
162
  catch (error) {
161
163
  log('verifyOwnerKeyVoucher failed: %o', error);
@@ -310,40 +312,24 @@ export function verifyCadreInviteRedemption(partyId, fields, inviteSig, peerSig)
310
312
  return false;
311
313
  }
312
314
  }
313
- /**
314
- * The links of an invitation admission that do not depend on WHICH table's row was
315
- * admitted — shared by {@link verifyInvitationAdmission} (`CadrePeer`) and
316
- * {@link verifyInvitationOwnerAdmission} (`OwnerKey`), which differ only in the row
317
- * columns the usage must name and, for an owner row, in `grantsOwner`. The chain is
318
- *
319
- * row --vouchUsage--> usage --inviteKey--> invitation --issuerKey--> anchored owner
320
- *
321
- * and every link here is verified: the issuer is anchored (`isAnchored`) and is the row's
322
- * `vouchOwner`; the usage names this invitation and is the row's `vouchUsage`; a targeted
323
- * invitation names the redeeming device; the stored `peerKey` really is the key behind the
324
- * usage's `peerId` (the schema cannot unwrap a multihash, so a writer could assert any
325
- * pair); the invitation's stored `'add'` signature verifies over the row rebuilt from its
326
- * columns; the holder's `'redeem'` signature verifies with the invitation key and the
327
- * device's `'consent'` signature with its own key. All three signatures are judged for
328
- * `partyId`. Throws on malformed input; the two callers turn that into `false`.
329
- */
330
- function verifyAdmissionChain(partyId, vouchOwner, vouchUsage, usage, invite, isAnchored) {
331
- return isAnchored(vouchOwner)
332
- && invite.issuerKey === vouchOwner
333
- && usage.usageStampId === vouchUsage
334
- && usage.inviteKey === invite.key
335
- && (invite.peerId === null || invite.peerId === usage.peerId)
336
- && ed25519PublicKeyB64FromPeerId(usage.peerId) === usage.peerKey
337
- && verifyB64(cadreInviteAddDigest(partyId, invite), invite.issuerSig, invite.issuerKey)
338
- && verifyB64(cadreInviteRedeemDigest(partyId, invite.key, usage.usageStampId, usage.peerKey), usage.inviteSig, invite.key)
339
- && verifyB64(cadreInviteConsentDigest(partyId, invite.key, usage.usageStampId, usage.peerKey), usage.peerSig, usage.peerKey);
340
- }
341
315
  /**
342
316
  * Is an invitation-admitted `CadrePeer` row (`vouchSig` null, `vouchUsage` set) a
343
317
  * member this node should trust? The read-side mirror of the consent branch of
344
318
  * `CadrePeer.AuthorizedInsert`, re-checked against THIS node's anchor because the
345
- * replicated `OwnerKey` table can be polluted. The usage must name this peer id and this
346
- * exact row incarnation (`peerStampId`); every other link is {@link verifyAdmissionChain}.
319
+ * replicated `OwnerKey` table can be polluted. The chain is
320
+ *
321
+ * row --vouchUsage--> usage --inviteKey--> invitation --issuerKey--> anchored owner
322
+ *
323
+ * and every link is verified: the issuer is anchored (`isAnchored`) and is the row's
324
+ * `vouchOwner`; the usage is the row's `vouchUsage`, names this peer id and this exact row
325
+ * incarnation (`peerStampId`), and names this invitation; a targeted invitation names the
326
+ * redeeming device; the stored `peerKey` really is the key behind the usage's `peerId` (the
327
+ * schema cannot unwrap a multihash, so a writer could assert any pair); the invitation's
328
+ * stored `'add'` signature verifies over the row rebuilt from its columns; the holder's
329
+ * `'redeem'` signature verifies with the invitation key and the device's `'consent'`
330
+ * signature with its own key. All three signatures are judged for `partyId`. A machine
331
+ * invitation admits a machine and nothing else, so no `OwnerKey` row is ever verified
332
+ * through this chain; a grant-seated owner row is {@link verifyOwnerGrantAdmission}'s.
347
333
  *
348
334
  * Expiry, use count and withdrawal are deliberately NOT re-checked: they were conditions
349
335
  * at redemption (`CadreInviteUsage.Authorized`), and membership persists until an owner
@@ -358,9 +344,17 @@ export function verifyInvitationAdmission(partyId, row, usage, invite, isAnchore
358
344
  return row.stampId !== null
359
345
  && row.vouchOwner !== null
360
346
  && row.vouchUsage !== null
347
+ && isAnchored(row.vouchOwner)
348
+ && invite.issuerKey === row.vouchOwner
349
+ && usage.usageStampId === row.vouchUsage
361
350
  && usage.peerStampId === row.stampId
362
351
  && usage.peerId === row.peerId
363
- && verifyAdmissionChain(partyId, row.vouchOwner, row.vouchUsage, usage, invite, isAnchored);
352
+ && usage.inviteKey === invite.key
353
+ && (invite.peerId === null || invite.peerId === usage.peerId)
354
+ && ed25519PublicKeyB64FromPeerId(usage.peerId) === usage.peerKey
355
+ && verifyB64(cadreInviteAddDigest(partyId, invite), invite.issuerSig, invite.issuerKey)
356
+ && verifyB64(cadreInviteRedeemDigest(partyId, invite.key, usage.usageStampId, usage.peerKey), usage.inviteSig, invite.key)
357
+ && verifyB64(cadreInviteConsentDigest(partyId, invite.key, usage.usageStampId, usage.peerKey), usage.peerSig, usage.peerKey);
364
358
  }
365
359
  catch (error) {
366
360
  log('verifyInvitationAdmission failed: %o', error);
@@ -368,25 +362,101 @@ export function verifyInvitationAdmission(partyId, row, usage, invite, isAnchore
368
362
  }
369
363
  }
370
364
  /**
371
- * Is an invitation-admitted `OwnerKey` row (`vouchSig` null, `vouchUsage` set) an owner
372
- * this node should derive into its anchor? The read-side mirror of the consent branch of
373
- * `OwnerKey.Authorized` (`owner-anchor-sync.ts` → `deriveOwnerAnchor`): the invitation
374
- * must grant ownership, and the usage must name this key (`peerKey`) and this exact row
375
- * incarnation (`ownerStampId`); every other link is {@link verifyAdmissionChain}. Same
376
- * never-throws contract and the same deliberate omissions as
377
- * {@link verifyInvitationAdmission}.
365
+ * Canonical digest an owner signs to seat an `OwnerGrant` row — the read-side mirror of
366
+ * `ownerGrantAddMessage` in control-database.ts, base64url instead of raw bytes. The whole
367
+ * row is bound, the label included, through the one field builder both sides share
368
+ * (`ownerGrantRowFields`). SQL mirror: `OwnerGrant.AuthorizedInsert`.
369
+ */
370
+ export function ownerGrantAddDigest(partyId, row) {
371
+ return taggedDigest('CadreControl.OwnerGrant', 'add', partyId, ownerGrantRowFields(row));
372
+ }
373
+ /**
374
+ * Canonical digest the HOLDER of an `OwnerGrant`'s private key signs to redeem it once:
375
+ * proof of possession, verified against the grant key itself
376
+ * (`OwnerGrantUsage.GrantPossessed`). Binds the redemption's nonce and the key being seated,
377
+ * so one redemption cannot be re-presented for another key or another use. Mirror of
378
+ * `ownerGrantRedeemMessage` in control-database.ts.
379
+ */
380
+ export function ownerGrantRedeemDigest(partyId, grantKey, usageStampId, seatedKey) {
381
+ return taggedDigest('CadreControl.OwnerGrantUsage', 'redeem', partyId, [grantKey, usageStampId, seatedKey]);
382
+ }
383
+ /**
384
+ * Canonical digest the key being SEATED signs to prove it is held by the redeemer
385
+ * (`OwnerGrantUsage.OwnerConsented`), over the same fields as {@link ownerGrantRedeemDigest}
386
+ * under a distinct action tag, so the holder's and the key's signatures are never
387
+ * interchangeable. Mirror of `ownerGrantConsentMessage` in control-database.ts.
388
+ */
389
+ export function ownerGrantConsentDigest(partyId, grantKey, usageStampId, seatedKey) {
390
+ return taggedDigest('CadreControl.OwnerGrantUsage', 'consent', partyId, [grantKey, usageStampId, seatedKey]);
391
+ }
392
+ /**
393
+ * Does an `OwnerGrant` row carry a valid `'add'` signature by its own `issuerKey`, for
394
+ * `partyId`? The grant twin of {@link verifyCadreInviteRow}, with the same contract: whether
395
+ * that issuer IS an owner is the caller's question, and a malformed row verifies as `false`.
396
+ */
397
+ export function verifyOwnerGrantRow(partyId, grant) {
398
+ try {
399
+ return verifyB64(ownerGrantAddDigest(partyId, grant), grant.issuerSig, grant.issuerKey);
400
+ }
401
+ catch (error) {
402
+ log('verifyOwnerGrantRow failed: %o', error);
403
+ return false;
404
+ }
405
+ }
406
+ /**
407
+ * The two signatures an owner-grant redemption carries, checked before any database work:
408
+ * the holder's `'redeem'` signature with the grant key and the seated key's `'consent'`
409
+ * signature with itself, both over (`grantKey`, `usageStampId`, `seatedKey`). The grant twin
410
+ * of {@link verifyCadreInviteRedemption}, with the same contract: the schema
411
+ * (`OwnerGrantUsage.GrantPossessed` / `OwnerConsented`) stays the authority, this turns a bad
412
+ * signature into a clean refusal instead of a constraint failure at commit. Never throws.
413
+ */
414
+ export function verifyOwnerGrantRedemption(partyId, fields, grantSig, ownerSig) {
415
+ try {
416
+ return verifyB64(ownerGrantRedeemDigest(partyId, fields.grantKey, fields.usageStampId, fields.seatedKey), grantSig, fields.grantKey)
417
+ && verifyB64(ownerGrantConsentDigest(partyId, fields.grantKey, fields.usageStampId, fields.seatedKey), ownerSig, fields.seatedKey);
418
+ }
419
+ catch (error) {
420
+ log('verifyOwnerGrantRedemption failed: %o', error);
421
+ return false;
422
+ }
423
+ }
424
+ /**
425
+ * Is a grant-seated `OwnerKey` row (`vouchSig` null, `vouchUsage` naming an `OwnerGrantUsage`
426
+ * row) an owner this node should derive into its anchor? The read-side mirror of the grant
427
+ * branch of `OwnerKey.Authorized` (`owner-anchor-sync.ts` → `deriveOwnerAnchor`). The chain is
428
+ *
429
+ * row --vouchUsage--> usage --grantKey--> grant --issuerKey--> anchored owner
430
+ *
431
+ * and every link is verified: the issuer is anchored and is the row's `vouchOwner`; the usage
432
+ * is the row's `vouchUsage` and names this key and this exact row incarnation
433
+ * (`seatedStampId`); the usage names this grant; the row carries the grant's label; the
434
+ * grant's stored `'add'` signature verifies over the row rebuilt from its columns; the
435
+ * holder's `'redeem'` signature verifies with the grant key and the seated key's `'consent'`
436
+ * signature with itself. All three signatures are judged for `partyId`.
437
+ *
438
+ * Expiry, use count and withdrawal are deliberately NOT re-checked, as
439
+ * {@link verifyInvitationAdmission} omits them: they were conditions at redemption
440
+ * (`OwnerGrantUsage.Authorized`), and ownership persists until an owner removes the row.
441
+ * Same never-throws contract as the siblings.
378
442
  */
379
- export function verifyInvitationOwnerAdmission(partyId, row, usage, invite, isAnchored) {
443
+ export function verifyOwnerGrantAdmission(partyId, row, usage, grant, isAnchored) {
380
444
  try {
381
445
  return row.vouchOwner !== null
382
446
  && row.vouchUsage !== null
383
- && invite.grantsOwner
384
- && usage.peerKey === row.key
385
- && usage.ownerStampId === row.stampId
386
- && verifyAdmissionChain(partyId, row.vouchOwner, row.vouchUsage, usage, invite, isAnchored);
447
+ && isAnchored(row.vouchOwner)
448
+ && grant.issuerKey === row.vouchOwner
449
+ && usage.usageStampId === row.vouchUsage
450
+ && usage.seatedKey === row.key
451
+ && usage.seatedStampId === row.stampId
452
+ && usage.grantKey === grant.key
453
+ && (grant.label ?? '') === (row.label ?? '')
454
+ && verifyB64(ownerGrantAddDigest(partyId, grant), grant.issuerSig, grant.issuerKey)
455
+ && verifyB64(ownerGrantRedeemDigest(partyId, grant.key, usage.usageStampId, usage.seatedKey), usage.grantSig, grant.key)
456
+ && verifyB64(ownerGrantConsentDigest(partyId, grant.key, usage.usageStampId, usage.seatedKey), usage.ownerSig, usage.seatedKey);
387
457
  }
388
458
  catch (error) {
389
- log('verifyInvitationOwnerAdmission failed: %o', error);
459
+ log('verifyOwnerGrantAdmission failed: %o', error);
390
460
  return false;
391
461
  }
392
462
  }
@@ -1 +1 @@
1
- {"version":3,"file":"peer-authorization.js","sourceRoot":"","sources":["../src/peer-authorization.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"peer-authorization.js","sourceRoot":"","sources":["../src/peer-authorization.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import type { Libp2p, PeerId } from '@libp2p/interface';
2
2
  import type { IPeerNetwork } from '@optimystic/db-core';
3
3
  import { BlockTransferClient, type IRawStorage } from '@optimystic/db-p2p';
4
+ import type { Libp2pNodeWithRepo } from './types.js';
4
5
  /**
5
6
  * The block-transfer protocol's hard cap on one length-prefixed message. Mirrors
6
7
  * `MAX_BLOCK_MESSAGE_BYTES` in `@optimystic/db-p2p`'s `protocol-limits.ts` (8 MiB), which
@@ -19,7 +20,10 @@ export declare const PEER_JOIN_BACKFILL_WARN_AFTER_FAILURES = 3;
19
20
  export interface PeerJoinBackfillConfig {
20
21
  /** Default true. False disables the catch-up entirely (the pre-existing behaviour). */
21
22
  enabled?: boolean;
22
- /** Settle time after a connection opens before catching that peer up, ms. Default 1000. */
23
+ /**
24
+ * Settle time before re-running a peer this instance has already run for (a denied or failed
25
+ * peer's next schedule), ms. Default 1000. A peer never run for is run at once.
26
+ */
23
27
  debounceMs?: number;
24
28
  /** Ceiling on blocks copied in one catch-up. Default 10_000. Reaching it is LOGGED, never silent. */
25
29
  maxBlocks?: number;
@@ -76,6 +80,12 @@ export interface PeerJoinBackfillDeps {
76
80
  * see the module comment for why the strand no-gate argument does not carry over.
77
81
  */
78
82
  authorizePeer?: (peerId: string) => Promise<boolean>;
83
+ /**
84
+ * The node's `reportBlockHeld` ({@link Libp2pNodeWithRepo.reportBlockHeld}), told of each block a
85
+ * peer accepted so Optimystic's under-replication drain does not push the peer the same block
86
+ * again, one request per block. Absent = nothing reported, and the drain re-sends.
87
+ */
88
+ reportBlockHeld?: Libp2pNodeWithRepo['reportBlockHeld'];
79
89
  /**
80
90
  * Test seam: build the per-peer push client. Defaults to a real
81
91
  * `BlockTransferClient` over {@link peerNetwork} + {@link protocolPrefix}.
@@ -84,11 +94,21 @@ export interface PeerJoinBackfillDeps {
84
94
  }
85
95
  /** What one peer's catch-up actually did. Returned for tests and logged at the end of each run. */
86
96
  export interface PeerJoinBackfillResult {
87
- /** Blocks offered: had a committed `latest` AND materialized content locally. */
97
+ /** Blocks offered: had a committed `latest` AND materialized content locally, and the peer was not known to hold it. */
88
98
  offered: number;
99
+ /**
100
+ * Skipped: the peer already accepted or refused this revision from this node, or signed its
101
+ * commit (see "What is pushed" in the module comment). Not offered, so not counted toward
102
+ * `maxBlocks`.
103
+ */
104
+ alreadyHeld: number;
89
105
  /** Blocks the remote reported it persisted. */
90
106
  accepted: number;
91
- /** Block ids the remote reported in `missing` (parse or persist failure on its side). */
107
+ /**
108
+ * Block ids the remote reported in `missing` (unparseable, not persisted, or pushed without a
109
+ * commit proof it accepts). Remembered per revision; not offered to that peer again until the
110
+ * local revision moves.
111
+ */
92
112
  rejected: string[];
93
113
  /** Skipped: metadata has no `latest` (pending-only — not yet a durability claim here). */
94
114
  uncommitted: number;
@@ -109,8 +129,8 @@ export interface PeerJoinBackfillResult {
109
129
  *
110
130
  * Best-effort throughout: nothing here throws into a libp2p event handler or into a
111
131
  * runtime bring-up; a failed chunk is logged and the run continues. A peer is marked
112
- * fully caught up ONLY after a run with no thrown chunk and an empty `missing` list, so
113
- * the next `peer:identify` from a peer whose catch-up failed retries it.
132
+ * caught up only after a run with no thrown chunk, so a peer whose catch-up failed is
133
+ * retried; each block is pushed to each peer once (see "What is pushed" in the module comment).
114
134
  */
115
135
  export declare class PeerJoinBackfill {
116
136
  private readonly deps;
@@ -119,10 +139,22 @@ export declare class PeerJoinBackfill {
119
139
  private started;
120
140
  private stopped;
121
141
  /**
122
- * Peers fully caught up this runtime (never rescheduled until the runtime is rebuilt; only
123
- * {@link forceCatchUpPeer} pushes to one again).
142
+ * Peers caught up since their current connection opened. Cleared for a peer when its last
143
+ * connection closes, so a reconnect re-runs; {@link forceCatchUpPeer} runs past it.
124
144
  */
125
145
  private readonly done;
146
+ /**
147
+ * Peers that disconnected while their run was in flight, so that run does not mark them
148
+ * {@link done} after the disconnect cleared it. Cleared when the run ends.
149
+ */
150
+ private readonly disconnectedInFlight;
151
+ /** Per-peer, per-block verdicts from push replies; see {@link PeerMemo}. */
152
+ private readonly memos;
153
+ /**
154
+ * Peers a run has been started for. A peer not in it is run at once on its first schedule;
155
+ * later schedules wait out `debounceMs`.
156
+ */
157
+ private readonly contacted;
126
158
  /**
127
159
  * Peers with a catch-up currently running, each with that run (suppresses concurrent
128
160
  * duplicates; {@link forceCatchUpPeer} waits on the run).
@@ -130,9 +162,9 @@ export declare class PeerJoinBackfill {
130
162
  private readonly inFlight;
131
163
  /**
132
164
  * Peers whose (re-)schedule arrived while their OWN run was in flight, replayed once
133
- * that run finishes. Load-bearing for the gated path: the gate's authorization check is
134
- * a control-database read, so the window between it and the run's end is wide enough for
135
- * the very membership commit that would have authorized the peer to land inside it —
165
+ * that run finishes. Load-bearing for the gated path: the gate is judged once, at the start
166
+ * of a run, and the run's pushes take long enough for the very membership commit that would
167
+ * have authorized the peer to land after that check —
136
168
  * dropping that schedule (rather than deferring it) leaves the denied peer waiting for a
137
169
  * reconnect, which is exactly what the re-arm exists to avoid.
138
170
  */
@@ -150,17 +182,32 @@ export declare class PeerJoinBackfill {
150
182
  /** Peers already reported on `console.warn`; reset when a run finally lands cleanly. */
151
183
  private readonly warned;
152
184
  private readonly onPeerIdentify;
185
+ private readonly onPeerDisconnect;
153
186
  private loggedNoListBlockIds;
154
187
  constructor(deps: PeerJoinBackfillDeps, config?: PeerJoinBackfillConfig);
155
188
  /**
156
189
  * Subscribe to `peer:identify` AND schedule a catch-up for already-connected peers whose
157
190
  * stored protocols already name this network's block-transfer protocol — a peer that does
158
- * not speak it (a bare circuit relay, a bootstrap node) is never scheduled at all. See
159
- * {@link speaksBlockTransfer} and the module comment.
191
+ * not speak it (a bare circuit relay, a bootstrap node) is never scheduled at all. Also
192
+ * subscribes to `peer:disconnect`, so a peer caught up before it went away is run again on
193
+ * its return. See {@link speaksBlockTransfer} and the module comment.
160
194
  */
161
195
  start(): void;
162
196
  /** Unsubscribe, clear timers; in-flight runs observe the stopped flag and bail. */
163
197
  stop(): void;
198
+ /**
199
+ * A peer's last connection closed: it is no longer caught up, so its next `peer:identify`
200
+ * re-runs. Only `done` is cleared. The memo stays (it keeps the re-run to what moved),
201
+ * `contacted` stays (a link flapping inside one settle window costs one run), and the
202
+ * backoff state stays (clearing it re-dials an unreachable peer on every reconnect; see the
203
+ * module comment's retry paragraph).
204
+ *
205
+ * When the returning peer wrote while away with a cohort that named this node, its own
206
+ * re-run pushes those blocks here and reports them through `reportBlockHeld`, so its
207
+ * under-replication drain does not push them again. Revisit if a measurement shows reconnect
208
+ * re-runs dominating push traffic.
209
+ */
210
+ private forgetCaughtUp;
164
211
  /**
165
212
  * (Re-)schedule a debounced catch-up for every currently-connected peer whose protocols, as
166
213
  * already stored in the libp2p peer store, name this network's block-transfer protocol. A
@@ -177,7 +224,11 @@ export declare class PeerJoinBackfill {
177
224
  scheduleConnectedPeers(): Promise<number>;
178
225
  /** Schedules `peerId` only if the peer store already knows it speaks this network's protocol. */
179
226
  private scheduleIfKnownToSpeak;
180
- /** Debounced entry point for connection churn: one run per peer per settle window. */
227
+ /**
228
+ * Entry point for connection churn: one run per peer per settle window, except that a peer
229
+ * never run for is run at once (on a zero-delay timer, so a burst of identify events in one
230
+ * turn still collapses, and no work happens inside the libp2p event dispatch).
231
+ */
181
232
  private schedulePeer;
182
233
  /**
183
234
  * Run one peer's catch-up now, bypassing the debounce. Never rejects. Returns an
@@ -186,14 +237,16 @@ export declare class PeerJoinBackfill {
186
237
  */
187
238
  catchUpPeer(peerId: PeerId): Promise<PeerJoinBackfillResult>;
188
239
  /**
189
- * Run one peer's catch-up now and wait for it, whatever this instance remembers about the
190
- * peer: wait out a run already in flight for it, then push the whole store again even when
191
- * the peer is memoized as caught up. Never rejects; an all-zero result only when stopped.
240
+ * Run one peer's catch-up now and wait for it, even when the peer is memoized as caught up:
241
+ * wait out a run already in flight for it, then run again. The run still skips every block the
242
+ * peer is known to hold (it accepted or refused that revision, or signed it), so for a peer that
243
+ * holds the whole store it pushes nothing and returns `alreadyHeld` equal to the store size.
244
+ * Never rejects; an all-zero result only when stopped.
192
245
  *
193
246
  * For a caller that must know the peer holds this store before it proceeds, where
194
247
  * {@link catchUpPeer}'s empty answer would hide a run that was denied (a `peer:identify`
195
- * run can pass the gate a moment before the caller authorized the peer) or a memo older
196
- * than the commits since.
248
+ * run can pass the gate a moment before the caller authorized the peer) or commits made
249
+ * since the peer was caught up.
197
250
  */
198
251
  forceCatchUpPeer(peerId: PeerId): Promise<PeerJoinBackfillResult>;
199
252
  /**
@@ -218,10 +271,26 @@ export declare class PeerJoinBackfill {
218
271
  * timeout. Reset when a run finally lands cleanly, so a peer that recovers can report again.
219
272
  */
220
273
  private warnPersistentFailure;
274
+ /** This peer's memo, created empty on first use. */
275
+ private memoFor;
276
+ /**
277
+ * Tell the node which blocks of one push reply the peer accepted, at the revision pushed.
278
+ * Best-effort: a failed report is logged and costs only the drain's duplicate push.
279
+ */
280
+ private reportAccepted;
221
281
  /**
222
- * The actual copy. `clean` = every chunk pushed and the remote persisted every block.
282
+ * The actual copy. `clean` = the gate admitted the peer, the store is listable and no push
283
+ * threw (a block the receiver refused is remembered per block instead, see {@link PeerMemo}).
223
284
  * `pushFailed` = at least one push THREW, which is the only non-clean outcome a retry can
224
- * change; the others are verdicts (denied, inert store, blocks the receiver refused).
285
+ * change; the others are verdicts (denied, inert store).
225
286
  */
226
287
  private runCatchUp;
288
+ /**
289
+ * Read one block for the push to `key`, or count why it is skipped in `result` and return
290
+ * nothing: not committed, already held by the peer (memo or its own commit signature), not
291
+ * materialized, or too large for one message. The proof is read for EXACTLY the revision the
292
+ * meta will name, from the same `latest`; absent is normal (nothing retained a proof for that
293
+ * revision), and the block still ships with its meta for the receiver to decide.
294
+ */
295
+ private readOffer;
227
296
  }