chainlesschain 0.166.37 → 0.166.39
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.
- package/package.json +7 -2
- package/scripts/governed-learning-local-attestor-service.mjs +222 -0
- package/scripts/governed-learning-local-attestor-trust-approval-service.mjs +338 -0
- package/scripts/governed-learning-local-attestor-trust-operations-service.mjs +575 -0
- package/scripts/governed-learning-windows-secure-pipe-broker.ps1 +375 -0
- package/src/assets/web-panel/assets/{AIOps-B_Nt1Qe4.js → AIOps-qWUdiFr5.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CHQbie4X.js → ActionButton-B_f7go3E.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-Bm9364Lw.js → Analytics-hSGFlSkB.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DTwlIh2v.js → AppLayout-CCYGgj71.js} +3 -3
- package/src/assets/web-panel/assets/{Artifacts-OibP0qB4.js → Artifacts-BdS1H9gq.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-B8Fwavkg.js → Audit-Cck9IebC.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-p1Vb2K2B.js → BackgroundAgents-DZzoM_QS.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BI3QT-wI.js → Backup-D8H_QtGu.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BW_VRWWu.js → BaseInput-CTsNF_pu.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CUEhDQfq.js → Chat-CcEiTYY8.js} +4 -4
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-C5UVXdVE.js → ChatBubbleRenderer-9BY1DPuc.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-URYsaaxv.js → Checkbox-BPB9NNJx.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DJAwC80a.js → Codegen-CKKMf7jD.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DfRKFzc9.js → Col-DpSSB4Uu.js} +1 -1
- package/src/assets/web-panel/assets/{Community-GOkGHuly.js → Community-CfR6ikoH.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-CIMs13NC.js → Compact-CqnkGGjK.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BE-TQIxV.js → Compliance-9IzhdVQb.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CYmbJiWw.js → Cowork-eXsgH33N.js} +4 -4
- package/src/assets/web-panel/assets/{Cron-Be3OIWyM.js → Cron-DvkzHFRi.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-2xB2HS2D.js → Crosschain--az9d9f7.js} +1 -1
- package/src/assets/web-panel/assets/{DID-B_lJO2yF.js → DID-_Eb4kpnJ.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DnVWqUER.js → Dashboard-aDVisdXj.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-C7ZJvHVa.js → Dropdown-oQ54XzS9.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DLevT-0F.js → EmailListRenderer-BUPdMau1.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BwhQ5BRU.js → FamilyGuardDashboard-DtQTOCQI.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BkGI-Xkq.js → Federation-Cpnb3Moe.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BgIIbMd7.js → FormItemContext-DmsrJkeU.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-qL-qN8Nb.js → GenericCardRenderer-CpFDYnh3.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BTzgrC4U.js → Git-HFG17p7Q.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-p28vdCN4.js → Governance-D5Z5c7N8.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-Cqephrur.js → Inference-DH159h74.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-C3v5Q4Zp.js → KnowledgeGraph-DuL1pcJD.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-T6f0w32w.js → Logs-Gqn8hFsM.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-Dj5XPm3S.js → MarkdownRenderer-NHJaejHI.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-ClDsvHDH.js → Marketplace-BArcWifg.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-C4P-_snx.js → McpTools-Q1BfBSnd.js} +2 -2
- package/src/assets/web-panel/assets/{Memory-BZZfG6y6.js → Memory-Cz8nRL7N.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DpIv_BLs.js → MobileBridge-CRuxLRJw.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-Buz3NIQg.js → MobileProjects-B1CQIAGp.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-HS2PJB79.js → Mtc-CFhXZbPk.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-UmBrcU27.js → MtcAudit-C69LqcZ5.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-C00sXiZf.js → Multisig-y7yZeTTG.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Dj1ng_ph.js → NLProgramming-DgjhoWea.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-C4LEVKlk.js → Notes-DRc2WTDh.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-BWXwnekv.js → NotificationSettings-CLPx24yn.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-CZHfK8Nn.js → OrderTableRenderer-CMSNA4CO.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-CFEtFPrV.js → Organization-Dm6LIyhZ.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-DSz4MJK1.js → Overflow-DP4DOYd-.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-DyTEytwG.js → P2P-HFwvtFI1.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-B5QNGLVx.js → PdhVaultBrowser-D9gPfKRM.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-wEC_X7x4.js → Permissions-Bdtxniwh.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-If5GZlGZ.js → PersonalDataHub-Dgl2AbES.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-LB4gqqmX.js → Pipeline-DpZrzYwK.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-QVLhoxcN.js → Privacy-EQ551c0t.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-FaAbTYTo.js → ProjectInit-xUSeczsM.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DhMeNA21.js → ProjectSettings-B66Sr_t8.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-5L4lkWAZ.js → Projects-B4zikj95.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DhZFp8fO.js → Providers-DjLbqQPh.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BZuJ7_xi.js → QrScannerModal-KVsAQCd_.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-TXddPYYb.js → QuickAsk-C4noJXu8.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DDuXIKYt.js → Recommend-Cn15clqY.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-CDrTXImv.js → RemoteSession-DdonMFwH.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-B2xKaKzt.js → Reputation-Bqe3NwWN.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DzAjWAOX.js → Row-CnxBgjkD.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CKH38BLF.js → RssFeed-CSRrgZyK.js} +2 -2
- package/src/assets/web-panel/assets/{Search-CuPqJYoQ.js → Search-DTUYUfFx.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DmAd2hxz.js → Security-BHExHVIm.js} +4 -4
- package/src/assets/web-panel/assets/{Services-Bt3nljnY.js → Services-B_IWqPes.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CP7RH093.js → Skeleton-C_oAtzmX.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DKNeMBTx.js → Skills-maJNokSL.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CbpM8Nrd.js → Sla-CMM_ZsLH.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DTk-vTzF.js → SpeechSettings-D7w_oNwK.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DKiplwmc.js → SyncSettings-D0Zl3NIr.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-z-lOm8fx.js → Tasks-Bs0H0ctR.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-Rb-Q0DGX.js → Templates-C6T6oCpR.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-C2sqDUnR.js → Tenant-ByL-kAYO.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DcyzskEE.js → Terminal-6JXNhc3b.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-lg0Eam7N.js → TimelineRenderer-KiuUtCsl.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-D9USIMIA.js → Tokens-C0TWTIER.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BQpaQJ5k.js → Trigger-DpC5aaJu.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-C-Mik04s.js → Trust-lqqflCwv.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DrnZ_o56.js → UkeySign-BYSlVfBc.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BDOsoZi0.js → VideoEditing-DX08oo_R.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Ct_bleI7.js → Wallet-CcIFPvzL.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-B6b6FDao.js → WebAuthn-D8DfxfVT.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-ZUJMaIHr.js → WorkflowEditor-Csadpaln.js} +1 -1
- package/src/assets/web-panel/assets/{chat-BII20OJy.js → chat-CewHWc_T.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DEsJRV3n.js → colors-B8at89r3.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DoDYAzN9.js → compact-item-v_gxtF5-.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-o_nofnVW.js → createContext-BOwFpJqA.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DenB_kSS.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CAsABTHC.js → hasIn-DjHUzt7E.js} +1 -1
- package/src/assets/web-panel/assets/{index-CeJSTcXw.js → index-1Tfwr_GA.js} +1 -1
- package/src/assets/web-panel/assets/{index-CVQSl1uY.js → index-5qmLo1us.js} +1 -1
- package/src/assets/web-panel/assets/index-B8bNwM9U.js +1 -0
- package/src/assets/web-panel/assets/{index-CQE-WMEU.js → index-BC20EQ7h.js} +1 -1
- package/src/assets/web-panel/assets/{index-DciLb_Ww.js → index-BGrmPk8T.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bqyg3PME.js → index-BPJ7uL2Q.js} +1 -1
- package/src/assets/web-panel/assets/{index-DU2Rpx1m.js → index-BRNyE3Kb.js} +1 -1
- package/src/assets/web-panel/assets/{index-CeWJqXNX.js → index-BVPsegMN.js} +1 -1
- package/src/assets/web-panel/assets/{index-DWZNYecl.js → index-B_egGFcR.js} +3 -3
- package/src/assets/web-panel/assets/{index-TSwbtCYG.js → index-BdZLA7k9.js} +1 -1
- package/src/assets/web-panel/assets/{index-BrIIJ2s-.js → index-Bk_Te9OR.js} +1 -1
- package/src/assets/web-panel/assets/{index-D5Fd4tdL.js → index-Bz8C8VXx.js} +1 -1
- package/src/assets/web-panel/assets/{index-B4SfcwZA.js → index-C7MHbmwn.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bn2ZPUXO.js → index-CFL1Hewx.js} +1 -1
- package/src/assets/web-panel/assets/{index-DsoFTdA2.js → index-CV1SgaBd.js} +1 -1
- package/src/assets/web-panel/assets/{index-B9hYHPhs.js → index-CXIPAeAB.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dgt1mKby.js → index-Ca8YZU2B.js} +1 -1
- package/src/assets/web-panel/assets/{index-DRAA2McB.js → index-Caf9UjhG.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcYbQoY7.js → index-Cb1uNDOv.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bycj011d.js → index-CquUCUzS.js} +1 -1
- package/src/assets/web-panel/assets/{index-BzMA6Ra3.js → index-CwHoF-TP.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dbb34cAr.js → index-Cxk0mCoQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BxT8yTwS.js → index-D3o-pacB.js} +1 -1
- package/src/assets/web-panel/assets/{index-DrsAF-Ar.js → index-DA3n0Y28.js} +1 -1
- package/src/assets/web-panel/assets/index-DC0cpgIP.js +1 -0
- package/src/assets/web-panel/assets/{index-B9Z75LfA.js → index-DRRK_8Eg.js} +1 -1
- package/src/assets/web-panel/assets/{index-kIyLNyoF.js → index-DUMvVGyf.js} +1 -1
- package/src/assets/web-panel/assets/{index-DQmX_-hk.js → index-DdHdbXpy.js} +1 -1
- package/src/assets/web-panel/assets/{index-tCeNfxv4.js → index-Ddw05Myq.js} +1 -1
- package/src/assets/web-panel/assets/{index-BDRh3v44.js → index-Dfrb3Prv.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bmwo5wQG.js → index-DiKaYIdo.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1YDdyQ1.js → index-DmZLZsyC.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dhnau6uw.js → index-FgUrhq_H.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cf3sFEoE.js → index-Khw7wzVk.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0ApxOMw.js → index-San3zacc.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_CMB_wC.js → index-coOi37of.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnbnmRqg.js → index-hyeBuocp.js} +1 -1
- package/src/assets/web-panel/assets/{index-DDQzBK3l.js → index-uk59xr0W.js} +1 -1
- package/src/assets/web-panel/assets/{index-CE2J04dA.js → index-wjvn8-9F.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-CNjeeoKE.js → initDefaultProps-Id2dFdjh.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CBT8IZDm.js → motion-DRxtwxng.js} +1 -1
- package/src/assets/web-panel/assets/{move-h1MOxjqv.js → move-BDYvdTb6.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-C_3pqNmn.js → mtc-parser-cz8LGI8Z.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CMUnPFDk.js → omit-DHJeh6tH.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-p8_c1xq0.js → pickAttrs-XJEQIp7e.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-D6O67r23.js → placementArrow-AFcf8lEn.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DquhepAK.js → responsiveObserve-CDEeBxs1.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CZ-m6gmS.js → slide-CvbVfi6T.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-k9ejZFtd.js → statusUtils-DtCyuEnq.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-NX6_137R.js → styleChecker--UgmTsGY.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-bCqR70lP.js → useFlexGapSupport-D9i1as-Y.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-2l0vSqyY.js → useFs-CJx3zw01.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-1yccm4O7.js → usePersonalDataHub-ZsIKYdZv.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CxQzajDo.js → vnode-B2RGEQG4.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CrTKwFyb.js → zoom-ob-0px2z.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +1 -1
- package/src/commands/evolution-attestor-trust.js +113 -0
- package/src/commands/evolution.js +2 -0
- package/src/commands/learning.js +34 -5
- package/src/data/changelog.json +26 -0
- package/src/lib/evolution/evolution-artifact-ports.js +21 -0
- package/src/lib/evolution/evolution-deployment-loader.js +56 -0
- package/src/lib/evolution/evolution-immutable-ledger-segment-store.js +812 -0
- package/src/lib/evolution/evolution-ledger-file-manifest-catalog.js +218 -0
- package/src/lib/evolution/evolution-ledger-manifest-catalog.js +472 -0
- package/src/lib/evolution/evolution-ledger-manifest-chain.js +997 -0
- package/src/lib/evolution/evolution-ledger-manifest-head-store.js +408 -0
- package/src/lib/evolution/evolution-ledger-manifest-witness-adapter.js +554 -0
- package/src/lib/evolution/evolution-ledger-v2-manifest-backend.js +460 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-ipc-endpoint.js +94 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-approval-client.js +485 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-ipc-capability.js +200 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-ledger.js +1222 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-operations-cli-host.js +802 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-operations-client.js +445 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-operations.js +1082 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-operator-registry.js +1453 -0
- package/src/lib/evolution/governed-skill-synthesis-candidate-evaluator.js +147 -0
- package/src/lib/evolution/governed-skill-synthesis-cli-host.js +115 -0
- package/src/lib/evolution/governed-skill-synthesis-evaluation-ledger-adapter.js +715 -0
- package/src/lib/evolution/governed-skill-synthesis-external-attestor.js +499 -0
- package/src/lib/evolution/governed-skill-synthesis-model-evaluator.js +514 -0
- package/src/lib/evolution/governed-skill-synthesis-process-attestor-worker.mjs +208 -0
- package/src/lib/evolution/governed-skill-synthesis-process-attestor.js +557 -0
- package/src/lib/evolution/governed-skill-synthesis-process-grader-worker.mjs +143 -0
- package/src/lib/evolution/governed-skill-synthesis-process-grader.js +444 -0
- package/src/lib/evolution/governed-skill-synthesis-provider-chat.js +220 -0
- package/src/lib/evolution/governed-skill-synthesis-windows-secure-pipe-host.js +236 -0
- package/src/lib/hook-audit-store.js +68 -2
- package/src/lib/hooks-v2-runtime.js +52 -26
- package/src/lib/learning/skill-synthesizer.js +66 -5
- package/src/lib/remote-read-loop-guard.js +30 -3
- package/src/assets/web-panel/assets/devWarning-0tgDCszN.js +0 -1
- package/src/assets/web-panel/assets/index-CFF8XEFE.js +0 -1
- package/src/assets/web-panel/assets/index-DVUEISry.js +0 -1
|
@@ -0,0 +1,997 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { types as utilTypes } from "node:util";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
EVOLUTION_IMMUTABLE_LEDGER_SEGMENT_RECEIPT_SCHEMA,
|
|
6
|
+
EVOLUTION_IMMUTABLE_LEDGER_SEGMENT_RESOLUTION_SCHEMA,
|
|
7
|
+
captureImmutableLedgerSegmentStorePort,
|
|
8
|
+
} from "./evolution-immutable-ledger-segment-store.js";
|
|
9
|
+
|
|
10
|
+
export const EVOLUTION_LEDGER_MANIFEST_CHAIN_SCHEMA =
|
|
11
|
+
"chainlesschain.evolution-ledger-manifest-chain/v2";
|
|
12
|
+
export const EVOLUTION_LEDGER_SEGMENT_PAYLOAD_SCHEMA =
|
|
13
|
+
"chainlesschain.evolution-ledger-segment-payload/v2";
|
|
14
|
+
export const EVOLUTION_LEDGER_SEGMENT_MANIFEST_SCHEMA =
|
|
15
|
+
"chainlesschain.evolution-ledger-segment-manifest/v2";
|
|
16
|
+
export const EVOLUTION_LEDGER_MANIFEST_HEAD_SCHEMA =
|
|
17
|
+
"chainlesschain.evolution-ledger-manifest-head/v2";
|
|
18
|
+
|
|
19
|
+
export const EVOLUTION_LEDGER_MANIFEST_INVALID_CODE =
|
|
20
|
+
"CC_EVOLUTION_LEDGER_MANIFEST_INVALID";
|
|
21
|
+
export const EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE =
|
|
22
|
+
"CC_EVOLUTION_LEDGER_MANIFEST_CORRUPT";
|
|
23
|
+
export const EVOLUTION_LEDGER_MANIFEST_UNAVAILABLE_CODE =
|
|
24
|
+
"CC_EVOLUTION_LEDGER_MANIFEST_UNAVAILABLE";
|
|
25
|
+
|
|
26
|
+
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
27
|
+
const MAX_EVENTS_PER_SEGMENT = 1024;
|
|
28
|
+
const MAX_SIGNATURE_CHARS = 4096;
|
|
29
|
+
const AUTHORITIES = new WeakSet();
|
|
30
|
+
|
|
31
|
+
const CHAIN_DESCRIPTOR_KEYS = new Set([
|
|
32
|
+
"epoch",
|
|
33
|
+
"ledgerId",
|
|
34
|
+
"maximumEventsPerSegment",
|
|
35
|
+
"tenantId",
|
|
36
|
+
]);
|
|
37
|
+
const AUTHORITY_DESCRIPTOR_KEYS = new Set([
|
|
38
|
+
"algorithm",
|
|
39
|
+
"authorityId",
|
|
40
|
+
"revision",
|
|
41
|
+
]);
|
|
42
|
+
const AUTHORITY_CONFIG_KEYS = new Set(["descriptor", "sign", "verify"]);
|
|
43
|
+
const SEAL_CONFIG_KEYS = new Set([
|
|
44
|
+
"authority",
|
|
45
|
+
"descriptor",
|
|
46
|
+
"eventDigests",
|
|
47
|
+
"minimumRetainedUntil",
|
|
48
|
+
"now",
|
|
49
|
+
"previousHead",
|
|
50
|
+
"segmentStore",
|
|
51
|
+
]);
|
|
52
|
+
const VERIFY_CONFIG_KEYS = new Set([
|
|
53
|
+
"authority",
|
|
54
|
+
"descriptor",
|
|
55
|
+
"head",
|
|
56
|
+
"manifests",
|
|
57
|
+
"segmentStore",
|
|
58
|
+
]);
|
|
59
|
+
const VERIFY_HEAD_CONFIG_KEYS = new Set(["authority", "descriptor", "head"]);
|
|
60
|
+
const VERIFY_MANIFEST_CONFIG_KEYS = new Set([
|
|
61
|
+
"authority",
|
|
62
|
+
"descriptor",
|
|
63
|
+
"manifest",
|
|
64
|
+
]);
|
|
65
|
+
const PAYLOAD_KEYS = new Set([
|
|
66
|
+
"eventDigests",
|
|
67
|
+
"schema",
|
|
68
|
+
"sequenceEnd",
|
|
69
|
+
"sequenceStart",
|
|
70
|
+
]);
|
|
71
|
+
const MANIFEST_KEYS = new Set([
|
|
72
|
+
"authorityAlgorithm",
|
|
73
|
+
"authorityId",
|
|
74
|
+
"authorityRevision",
|
|
75
|
+
"contentDigest",
|
|
76
|
+
"epoch",
|
|
77
|
+
"eventDigestRoot",
|
|
78
|
+
"eventDigests",
|
|
79
|
+
"issuedAt",
|
|
80
|
+
"ledgerId",
|
|
81
|
+
"manifestDigest",
|
|
82
|
+
"manifestSequence",
|
|
83
|
+
"previousManifestDigest",
|
|
84
|
+
"retainedUntil",
|
|
85
|
+
"schema",
|
|
86
|
+
"segmentRef",
|
|
87
|
+
"sequenceEnd",
|
|
88
|
+
"sequenceStart",
|
|
89
|
+
"signature",
|
|
90
|
+
"storageVersion",
|
|
91
|
+
"tenantId",
|
|
92
|
+
]);
|
|
93
|
+
const HEAD_KEYS = new Set([
|
|
94
|
+
"authorityAlgorithm",
|
|
95
|
+
"authorityId",
|
|
96
|
+
"authorityRevision",
|
|
97
|
+
"epoch",
|
|
98
|
+
"eventDigest",
|
|
99
|
+
"headDigest",
|
|
100
|
+
"issuedAt",
|
|
101
|
+
"ledgerId",
|
|
102
|
+
"manifestDigest",
|
|
103
|
+
"manifestSequence",
|
|
104
|
+
"previousHeadDigest",
|
|
105
|
+
"schema",
|
|
106
|
+
"sequence",
|
|
107
|
+
"signature",
|
|
108
|
+
"tenantId",
|
|
109
|
+
]);
|
|
110
|
+
|
|
111
|
+
export class EvolutionLedgerManifestError extends Error {
|
|
112
|
+
constructor(code, message, options = undefined) {
|
|
113
|
+
super(message, options);
|
|
114
|
+
this.name = "EvolutionLedgerManifestError";
|
|
115
|
+
this.code = code;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function failure(code, message, options = undefined) {
|
|
120
|
+
return new EvolutionLedgerManifestError(code, message, options);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function rejectProxy(
|
|
124
|
+
value,
|
|
125
|
+
label,
|
|
126
|
+
code = EVOLUTION_LEDGER_MANIFEST_INVALID_CODE,
|
|
127
|
+
) {
|
|
128
|
+
if (
|
|
129
|
+
(typeof value === "object" && value !== null) ||
|
|
130
|
+
typeof value === "function"
|
|
131
|
+
) {
|
|
132
|
+
if (utilTypes.isProxy(value))
|
|
133
|
+
throw failure(code, `${label} must not be a Proxy`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function exactRecord(
|
|
138
|
+
value,
|
|
139
|
+
keys,
|
|
140
|
+
label,
|
|
141
|
+
code = EVOLUTION_LEDGER_MANIFEST_INVALID_CODE,
|
|
142
|
+
) {
|
|
143
|
+
rejectProxy(value, label, code);
|
|
144
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
145
|
+
throw failure(code, `${label} must be a record`);
|
|
146
|
+
}
|
|
147
|
+
const prototype = Object.getPrototypeOf(value);
|
|
148
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
149
|
+
throw failure(code, `${label} must use a plain prototype`);
|
|
150
|
+
}
|
|
151
|
+
const fields = Object.getOwnPropertyDescriptors(value);
|
|
152
|
+
const names = Object.keys(fields);
|
|
153
|
+
if (names.length !== keys.size || names.some((name) => !keys.has(name))) {
|
|
154
|
+
throw failure(code, `${label} fields are invalid`);
|
|
155
|
+
}
|
|
156
|
+
for (const name of names) {
|
|
157
|
+
if (!("value" in fields[name])) {
|
|
158
|
+
throw failure(code, `${label}.${name} must be an own data property`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return fields;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function data(fields, name) {
|
|
165
|
+
return fields[name].value;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function identifier(
|
|
169
|
+
value,
|
|
170
|
+
label,
|
|
171
|
+
code = EVOLUTION_LEDGER_MANIFEST_INVALID_CODE,
|
|
172
|
+
) {
|
|
173
|
+
if (
|
|
174
|
+
typeof value !== "string" ||
|
|
175
|
+
value.trim() !== value ||
|
|
176
|
+
value.length < 1 ||
|
|
177
|
+
value.length > 512 ||
|
|
178
|
+
value.includes("\0")
|
|
179
|
+
) {
|
|
180
|
+
throw failure(code, `${label} is invalid`);
|
|
181
|
+
}
|
|
182
|
+
return value;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function signatureValue(
|
|
186
|
+
value,
|
|
187
|
+
label,
|
|
188
|
+
code = EVOLUTION_LEDGER_MANIFEST_INVALID_CODE,
|
|
189
|
+
) {
|
|
190
|
+
if (
|
|
191
|
+
typeof value !== "string" ||
|
|
192
|
+
value.trim() !== value ||
|
|
193
|
+
value.length < 1 ||
|
|
194
|
+
value.length > MAX_SIGNATURE_CHARS ||
|
|
195
|
+
value.includes("\0")
|
|
196
|
+
) {
|
|
197
|
+
throw failure(code, `${label} is invalid`);
|
|
198
|
+
}
|
|
199
|
+
return value;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function digest(value, label, code = EVOLUTION_LEDGER_MANIFEST_INVALID_CODE) {
|
|
203
|
+
if (!DIGEST.test(value || ""))
|
|
204
|
+
throw failure(code, `${label} must be sha256-bound`);
|
|
205
|
+
return value;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function nullableDigest(
|
|
209
|
+
value,
|
|
210
|
+
label,
|
|
211
|
+
code = EVOLUTION_LEDGER_MANIFEST_INVALID_CODE,
|
|
212
|
+
) {
|
|
213
|
+
return value === null ? null : digest(value, label, code);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function positive(value, label, code = EVOLUTION_LEDGER_MANIFEST_INVALID_CODE) {
|
|
217
|
+
if (!Number.isSafeInteger(value) || value < 1) {
|
|
218
|
+
throw failure(code, `${label} must be a positive safe integer`);
|
|
219
|
+
}
|
|
220
|
+
return value;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function timestamp(
|
|
224
|
+
value,
|
|
225
|
+
label,
|
|
226
|
+
code = EVOLUTION_LEDGER_MANIFEST_INVALID_CODE,
|
|
227
|
+
) {
|
|
228
|
+
if (typeof value !== "string")
|
|
229
|
+
throw failure(code, `${label} must be an ISO instant`);
|
|
230
|
+
const milliseconds = Date.parse(value);
|
|
231
|
+
if (
|
|
232
|
+
!Number.isFinite(milliseconds) ||
|
|
233
|
+
new Date(milliseconds).toISOString() !== value
|
|
234
|
+
) {
|
|
235
|
+
throw failure(code, `${label} must be a canonical ISO instant`);
|
|
236
|
+
}
|
|
237
|
+
return Object.freeze({ milliseconds, value });
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function canonical(value) {
|
|
241
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
242
|
+
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
243
|
+
return `{${Object.keys(value)
|
|
244
|
+
.sort()
|
|
245
|
+
.map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`)
|
|
246
|
+
.join(",")}}`;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function sha256(value) {
|
|
250
|
+
return `sha256:${createHash("sha256").update(value).digest("hex")}`;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function synchronously(
|
|
254
|
+
value,
|
|
255
|
+
label,
|
|
256
|
+
code = EVOLUTION_LEDGER_MANIFEST_UNAVAILABLE_CODE,
|
|
257
|
+
) {
|
|
258
|
+
rejectProxy(value, label, code);
|
|
259
|
+
if (utilTypes.isPromise(value))
|
|
260
|
+
throw failure(code, `${label} must be synchronous`);
|
|
261
|
+
return value;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function descriptor(value) {
|
|
265
|
+
const fields = exactRecord(
|
|
266
|
+
value,
|
|
267
|
+
CHAIN_DESCRIPTOR_KEYS,
|
|
268
|
+
"manifest chain descriptor",
|
|
269
|
+
);
|
|
270
|
+
const maximumEventsPerSegment = positive(
|
|
271
|
+
data(fields, "maximumEventsPerSegment"),
|
|
272
|
+
"descriptor.maximumEventsPerSegment",
|
|
273
|
+
);
|
|
274
|
+
if (maximumEventsPerSegment > MAX_EVENTS_PER_SEGMENT) {
|
|
275
|
+
throw failure(
|
|
276
|
+
EVOLUTION_LEDGER_MANIFEST_INVALID_CODE,
|
|
277
|
+
`descriptor.maximumEventsPerSegment exceeds ${MAX_EVENTS_PER_SEGMENT}`,
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
return Object.freeze({
|
|
281
|
+
epoch: identifier(data(fields, "epoch"), "descriptor.epoch"),
|
|
282
|
+
ledgerId: identifier(data(fields, "ledgerId"), "descriptor.ledgerId"),
|
|
283
|
+
maximumEventsPerSegment,
|
|
284
|
+
tenantId: identifier(data(fields, "tenantId"), "descriptor.tenantId"),
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function authorityDescriptor(value) {
|
|
289
|
+
const fields = exactRecord(
|
|
290
|
+
value,
|
|
291
|
+
AUTHORITY_DESCRIPTOR_KEYS,
|
|
292
|
+
"manifest authority descriptor",
|
|
293
|
+
);
|
|
294
|
+
return Object.freeze({
|
|
295
|
+
algorithm: identifier(data(fields, "algorithm"), "authority.algorithm"),
|
|
296
|
+
authorityId: identifier(
|
|
297
|
+
data(fields, "authorityId"),
|
|
298
|
+
"authority.authorityId",
|
|
299
|
+
),
|
|
300
|
+
revision: positive(data(fields, "revision"), "authority.revision"),
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function normalizeDigests(
|
|
305
|
+
value,
|
|
306
|
+
label,
|
|
307
|
+
maximum,
|
|
308
|
+
code = EVOLUTION_LEDGER_MANIFEST_INVALID_CODE,
|
|
309
|
+
) {
|
|
310
|
+
rejectProxy(value, label, code);
|
|
311
|
+
if (!Array.isArray(value) || value.length < 1 || value.length > maximum) {
|
|
312
|
+
throw failure(code, `${label} length is invalid`);
|
|
313
|
+
}
|
|
314
|
+
if (Object.keys(value).length !== value.length) {
|
|
315
|
+
throw failure(code, `${label} must not be sparse or have extra properties`);
|
|
316
|
+
}
|
|
317
|
+
const output = value.map((entry, index) =>
|
|
318
|
+
digest(entry, `${label}[${index}]`, code),
|
|
319
|
+
);
|
|
320
|
+
return Object.freeze(output);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function payload(sequenceStart, eventDigests) {
|
|
324
|
+
const sequenceEnd = sequenceStart + eventDigests.length - 1;
|
|
325
|
+
return Object.freeze({
|
|
326
|
+
eventDigests,
|
|
327
|
+
schema: EVOLUTION_LEDGER_SEGMENT_PAYLOAD_SCHEMA,
|
|
328
|
+
sequenceEnd,
|
|
329
|
+
sequenceStart,
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function payloadBytes(value) {
|
|
334
|
+
return Buffer.from(canonical(value), "utf8");
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function parsePayload(bytes, expected) {
|
|
338
|
+
if (!Buffer.isBuffer(bytes)) {
|
|
339
|
+
throw failure(
|
|
340
|
+
EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE,
|
|
341
|
+
"manifest segment bytes are invalid",
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
let raw;
|
|
345
|
+
try {
|
|
346
|
+
raw = JSON.parse(bytes.toString("utf8"));
|
|
347
|
+
} catch {
|
|
348
|
+
throw failure(
|
|
349
|
+
EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE,
|
|
350
|
+
"manifest segment payload is not JSON",
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
const fields = exactRecord(
|
|
354
|
+
raw,
|
|
355
|
+
PAYLOAD_KEYS,
|
|
356
|
+
"manifest segment payload",
|
|
357
|
+
EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE,
|
|
358
|
+
);
|
|
359
|
+
if (data(fields, "schema") !== EVOLUTION_LEDGER_SEGMENT_PAYLOAD_SCHEMA) {
|
|
360
|
+
throw failure(
|
|
361
|
+
EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE,
|
|
362
|
+
"manifest segment payload schema is invalid",
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
const eventDigests = normalizeDigests(
|
|
366
|
+
data(fields, "eventDigests"),
|
|
367
|
+
"manifest segment payload.eventDigests",
|
|
368
|
+
MAX_EVENTS_PER_SEGMENT,
|
|
369
|
+
EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE,
|
|
370
|
+
);
|
|
371
|
+
const sequenceStart = positive(
|
|
372
|
+
data(fields, "sequenceStart"),
|
|
373
|
+
"manifest segment payload.sequenceStart",
|
|
374
|
+
EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE,
|
|
375
|
+
);
|
|
376
|
+
const sequenceEnd = positive(
|
|
377
|
+
data(fields, "sequenceEnd"),
|
|
378
|
+
"manifest segment payload.sequenceEnd",
|
|
379
|
+
EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE,
|
|
380
|
+
);
|
|
381
|
+
if (sequenceEnd !== sequenceStart + eventDigests.length - 1) {
|
|
382
|
+
throw failure(
|
|
383
|
+
EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE,
|
|
384
|
+
"manifest segment payload range is invalid",
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
if (
|
|
388
|
+
sequenceStart !== expected.sequenceStart ||
|
|
389
|
+
sequenceEnd !== expected.sequenceEnd ||
|
|
390
|
+
canonical(raw) !== canonical(payload(sequenceStart, eventDigests))
|
|
391
|
+
) {
|
|
392
|
+
throw failure(
|
|
393
|
+
EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE,
|
|
394
|
+
"manifest segment payload binding differs",
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
return Object.freeze({ eventDigests, sequenceEnd, sequenceStart });
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function manifestCore(manifest) {
|
|
401
|
+
return Object.fromEntries(
|
|
402
|
+
Object.entries(manifest).filter(
|
|
403
|
+
([field]) => field !== "manifestDigest" && field !== "signature",
|
|
404
|
+
),
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function headCore(head) {
|
|
409
|
+
return Object.fromEntries(
|
|
410
|
+
Object.entries(head).filter(
|
|
411
|
+
([field]) => field !== "headDigest" && field !== "signature",
|
|
412
|
+
),
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function signedMessage(purpose, core) {
|
|
417
|
+
return Buffer.concat([
|
|
418
|
+
Buffer.from(`${purpose}\0`, "utf8"),
|
|
419
|
+
Buffer.from(canonical(core), "utf8"),
|
|
420
|
+
]);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function captureAuthority(value) {
|
|
424
|
+
if (!AUTHORITIES.has(value)) {
|
|
425
|
+
throw new TypeError(
|
|
426
|
+
"a branded Evolution Ledger manifest authority is required",
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
return value;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function sign(authority, purpose, core, digestField) {
|
|
433
|
+
const message = signedMessage(purpose, core);
|
|
434
|
+
const recordDigest = sha256(message);
|
|
435
|
+
let signature;
|
|
436
|
+
try {
|
|
437
|
+
signature = synchronously(
|
|
438
|
+
authority.sign({
|
|
439
|
+
authority: authority.descriptor,
|
|
440
|
+
digest: recordDigest,
|
|
441
|
+
message: Buffer.from(message),
|
|
442
|
+
purpose,
|
|
443
|
+
}),
|
|
444
|
+
`${purpose} signing result`,
|
|
445
|
+
);
|
|
446
|
+
} catch (cause) {
|
|
447
|
+
if (cause instanceof EvolutionLedgerManifestError) throw cause;
|
|
448
|
+
throw failure(
|
|
449
|
+
EVOLUTION_LEDGER_MANIFEST_UNAVAILABLE_CODE,
|
|
450
|
+
`${purpose} signer failed`,
|
|
451
|
+
{ cause },
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
signature = signatureValue(
|
|
455
|
+
signature,
|
|
456
|
+
`${purpose} signature`,
|
|
457
|
+
EVOLUTION_LEDGER_MANIFEST_UNAVAILABLE_CODE,
|
|
458
|
+
);
|
|
459
|
+
const record = Object.freeze({
|
|
460
|
+
...core,
|
|
461
|
+
[digestField]: recordDigest,
|
|
462
|
+
signature,
|
|
463
|
+
});
|
|
464
|
+
verify(authority, purpose, record, digestField);
|
|
465
|
+
return record;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function verify(authority, purpose, record, digestField) {
|
|
469
|
+
const core =
|
|
470
|
+
digestField === "manifestDigest" ? manifestCore(record) : headCore(record);
|
|
471
|
+
const message = signedMessage(purpose, core);
|
|
472
|
+
const recordDigest = sha256(message);
|
|
473
|
+
if (record[digestField] !== recordDigest) {
|
|
474
|
+
throw failure(
|
|
475
|
+
EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE,
|
|
476
|
+
`${purpose} digest is invalid`,
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
let valid;
|
|
480
|
+
try {
|
|
481
|
+
valid = synchronously(
|
|
482
|
+
authority.verify({
|
|
483
|
+
authority: authority.descriptor,
|
|
484
|
+
digest: recordDigest,
|
|
485
|
+
message: Buffer.from(message),
|
|
486
|
+
purpose,
|
|
487
|
+
signature: record.signature,
|
|
488
|
+
}),
|
|
489
|
+
`${purpose} verification result`,
|
|
490
|
+
);
|
|
491
|
+
} catch (cause) {
|
|
492
|
+
if (cause instanceof EvolutionLedgerManifestError) throw cause;
|
|
493
|
+
throw failure(
|
|
494
|
+
EVOLUTION_LEDGER_MANIFEST_UNAVAILABLE_CODE,
|
|
495
|
+
`${purpose} verifier failed`,
|
|
496
|
+
{ cause },
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
if (valid !== true) {
|
|
500
|
+
throw failure(
|
|
501
|
+
EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE,
|
|
502
|
+
`${purpose} signature was rejected`,
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function normalizeManifest(
|
|
508
|
+
value,
|
|
509
|
+
descriptorValue,
|
|
510
|
+
authority,
|
|
511
|
+
code = EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE,
|
|
512
|
+
) {
|
|
513
|
+
const fields = exactRecord(value, MANIFEST_KEYS, "segment manifest", code);
|
|
514
|
+
if (data(fields, "schema") !== EVOLUTION_LEDGER_SEGMENT_MANIFEST_SCHEMA) {
|
|
515
|
+
throw failure(code, "segment manifest schema is invalid");
|
|
516
|
+
}
|
|
517
|
+
const eventDigests = normalizeDigests(
|
|
518
|
+
data(fields, "eventDigests"),
|
|
519
|
+
"manifest.eventDigests",
|
|
520
|
+
descriptorValue.maximumEventsPerSegment,
|
|
521
|
+
code,
|
|
522
|
+
);
|
|
523
|
+
const sequenceStart = positive(
|
|
524
|
+
data(fields, "sequenceStart"),
|
|
525
|
+
"manifest.sequenceStart",
|
|
526
|
+
code,
|
|
527
|
+
);
|
|
528
|
+
const sequenceEnd = positive(
|
|
529
|
+
data(fields, "sequenceEnd"),
|
|
530
|
+
"manifest.sequenceEnd",
|
|
531
|
+
code,
|
|
532
|
+
);
|
|
533
|
+
const issuedAt = timestamp(
|
|
534
|
+
data(fields, "issuedAt"),
|
|
535
|
+
"manifest.issuedAt",
|
|
536
|
+
code,
|
|
537
|
+
);
|
|
538
|
+
const retainedUntil = timestamp(
|
|
539
|
+
data(fields, "retainedUntil"),
|
|
540
|
+
"manifest.retainedUntil",
|
|
541
|
+
code,
|
|
542
|
+
);
|
|
543
|
+
const normalized = Object.freeze({
|
|
544
|
+
authorityAlgorithm: identifier(
|
|
545
|
+
data(fields, "authorityAlgorithm"),
|
|
546
|
+
"manifest.authorityAlgorithm",
|
|
547
|
+
code,
|
|
548
|
+
),
|
|
549
|
+
authorityId: identifier(
|
|
550
|
+
data(fields, "authorityId"),
|
|
551
|
+
"manifest.authorityId",
|
|
552
|
+
code,
|
|
553
|
+
),
|
|
554
|
+
authorityRevision: positive(
|
|
555
|
+
data(fields, "authorityRevision"),
|
|
556
|
+
"manifest.authorityRevision",
|
|
557
|
+
code,
|
|
558
|
+
),
|
|
559
|
+
contentDigest: digest(
|
|
560
|
+
data(fields, "contentDigest"),
|
|
561
|
+
"manifest.contentDigest",
|
|
562
|
+
code,
|
|
563
|
+
),
|
|
564
|
+
epoch: identifier(data(fields, "epoch"), "manifest.epoch", code),
|
|
565
|
+
eventDigestRoot: digest(
|
|
566
|
+
data(fields, "eventDigestRoot"),
|
|
567
|
+
"manifest.eventDigestRoot",
|
|
568
|
+
code,
|
|
569
|
+
),
|
|
570
|
+
eventDigests,
|
|
571
|
+
issuedAt: issuedAt.value,
|
|
572
|
+
ledgerId: identifier(data(fields, "ledgerId"), "manifest.ledgerId", code),
|
|
573
|
+
manifestDigest: digest(
|
|
574
|
+
data(fields, "manifestDigest"),
|
|
575
|
+
"manifest.manifestDigest",
|
|
576
|
+
code,
|
|
577
|
+
),
|
|
578
|
+
manifestSequence: positive(
|
|
579
|
+
data(fields, "manifestSequence"),
|
|
580
|
+
"manifest.manifestSequence",
|
|
581
|
+
code,
|
|
582
|
+
),
|
|
583
|
+
previousManifestDigest: nullableDigest(
|
|
584
|
+
data(fields, "previousManifestDigest"),
|
|
585
|
+
"manifest.previousManifestDigest",
|
|
586
|
+
code,
|
|
587
|
+
),
|
|
588
|
+
retainedUntil: retainedUntil.value,
|
|
589
|
+
schema: EVOLUTION_LEDGER_SEGMENT_MANIFEST_SCHEMA,
|
|
590
|
+
segmentRef: digest(data(fields, "segmentRef"), "manifest.segmentRef", code),
|
|
591
|
+
sequenceEnd,
|
|
592
|
+
sequenceStart,
|
|
593
|
+
signature: signatureValue(
|
|
594
|
+
data(fields, "signature"),
|
|
595
|
+
"manifest.signature",
|
|
596
|
+
code,
|
|
597
|
+
),
|
|
598
|
+
storageVersion: identifier(
|
|
599
|
+
data(fields, "storageVersion"),
|
|
600
|
+
"manifest.storageVersion",
|
|
601
|
+
code,
|
|
602
|
+
),
|
|
603
|
+
tenantId: identifier(data(fields, "tenantId"), "manifest.tenantId", code),
|
|
604
|
+
});
|
|
605
|
+
if (
|
|
606
|
+
normalized.sequenceEnd !==
|
|
607
|
+
normalized.sequenceStart + eventDigests.length - 1
|
|
608
|
+
) {
|
|
609
|
+
throw failure(code, "segment manifest range does not cover its events");
|
|
610
|
+
}
|
|
611
|
+
if (normalized.segmentRef !== normalized.contentDigest) {
|
|
612
|
+
throw failure(code, "segment manifest reference is not content-addressed");
|
|
613
|
+
}
|
|
614
|
+
if (
|
|
615
|
+
normalized.eventDigestRoot !==
|
|
616
|
+
sha256(Buffer.from(canonical(eventDigests), "utf8"))
|
|
617
|
+
) {
|
|
618
|
+
throw failure(code, "segment manifest event digest root is invalid");
|
|
619
|
+
}
|
|
620
|
+
if (retainedUntil.milliseconds <= issuedAt.milliseconds) {
|
|
621
|
+
throw failure(code, "segment manifest retention is invalid");
|
|
622
|
+
}
|
|
623
|
+
for (const [field, expected] of Object.entries({
|
|
624
|
+
authorityAlgorithm: authority.descriptor.algorithm,
|
|
625
|
+
authorityId: authority.descriptor.authorityId,
|
|
626
|
+
authorityRevision: authority.descriptor.revision,
|
|
627
|
+
epoch: descriptorValue.epoch,
|
|
628
|
+
ledgerId: descriptorValue.ledgerId,
|
|
629
|
+
tenantId: descriptorValue.tenantId,
|
|
630
|
+
})) {
|
|
631
|
+
if (normalized[field] !== expected)
|
|
632
|
+
throw failure(code, `segment manifest ${field} binding differs`);
|
|
633
|
+
}
|
|
634
|
+
verify(authority, "ledger-segment-manifest", normalized, "manifestDigest");
|
|
635
|
+
return normalized;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
function normalizeHead(
|
|
639
|
+
value,
|
|
640
|
+
descriptorValue,
|
|
641
|
+
authority,
|
|
642
|
+
code = EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE,
|
|
643
|
+
) {
|
|
644
|
+
const fields = exactRecord(value, HEAD_KEYS, "manifest head", code);
|
|
645
|
+
if (data(fields, "schema") !== EVOLUTION_LEDGER_MANIFEST_HEAD_SCHEMA) {
|
|
646
|
+
throw failure(code, "manifest head schema is invalid");
|
|
647
|
+
}
|
|
648
|
+
const normalized = Object.freeze({
|
|
649
|
+
authorityAlgorithm: identifier(
|
|
650
|
+
data(fields, "authorityAlgorithm"),
|
|
651
|
+
"head.authorityAlgorithm",
|
|
652
|
+
code,
|
|
653
|
+
),
|
|
654
|
+
authorityId: identifier(
|
|
655
|
+
data(fields, "authorityId"),
|
|
656
|
+
"head.authorityId",
|
|
657
|
+
code,
|
|
658
|
+
),
|
|
659
|
+
authorityRevision: positive(
|
|
660
|
+
data(fields, "authorityRevision"),
|
|
661
|
+
"head.authorityRevision",
|
|
662
|
+
code,
|
|
663
|
+
),
|
|
664
|
+
epoch: identifier(data(fields, "epoch"), "head.epoch", code),
|
|
665
|
+
eventDigest: digest(data(fields, "eventDigest"), "head.eventDigest", code),
|
|
666
|
+
headDigest: digest(data(fields, "headDigest"), "head.headDigest", code),
|
|
667
|
+
issuedAt: timestamp(data(fields, "issuedAt"), "head.issuedAt", code).value,
|
|
668
|
+
ledgerId: identifier(data(fields, "ledgerId"), "head.ledgerId", code),
|
|
669
|
+
manifestDigest: digest(
|
|
670
|
+
data(fields, "manifestDigest"),
|
|
671
|
+
"head.manifestDigest",
|
|
672
|
+
code,
|
|
673
|
+
),
|
|
674
|
+
manifestSequence: positive(
|
|
675
|
+
data(fields, "manifestSequence"),
|
|
676
|
+
"head.manifestSequence",
|
|
677
|
+
code,
|
|
678
|
+
),
|
|
679
|
+
previousHeadDigest: nullableDigest(
|
|
680
|
+
data(fields, "previousHeadDigest"),
|
|
681
|
+
"head.previousHeadDigest",
|
|
682
|
+
code,
|
|
683
|
+
),
|
|
684
|
+
schema: EVOLUTION_LEDGER_MANIFEST_HEAD_SCHEMA,
|
|
685
|
+
sequence: positive(data(fields, "sequence"), "head.sequence", code),
|
|
686
|
+
signature: signatureValue(
|
|
687
|
+
data(fields, "signature"),
|
|
688
|
+
"head.signature",
|
|
689
|
+
code,
|
|
690
|
+
),
|
|
691
|
+
tenantId: identifier(data(fields, "tenantId"), "head.tenantId", code),
|
|
692
|
+
});
|
|
693
|
+
for (const [field, expected] of Object.entries({
|
|
694
|
+
authorityAlgorithm: authority.descriptor.algorithm,
|
|
695
|
+
authorityId: authority.descriptor.authorityId,
|
|
696
|
+
authorityRevision: authority.descriptor.revision,
|
|
697
|
+
epoch: descriptorValue.epoch,
|
|
698
|
+
ledgerId: descriptorValue.ledgerId,
|
|
699
|
+
tenantId: descriptorValue.tenantId,
|
|
700
|
+
})) {
|
|
701
|
+
if (normalized[field] !== expected)
|
|
702
|
+
throw failure(code, `manifest head ${field} binding differs`);
|
|
703
|
+
}
|
|
704
|
+
verify(authority, "ledger-manifest-head", normalized, "headDigest");
|
|
705
|
+
return normalized;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
function previousHead(value, descriptorValue, authority) {
|
|
709
|
+
return value === null
|
|
710
|
+
? null
|
|
711
|
+
: normalizeHead(value, descriptorValue, authority);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
function storeFailure(cause, action) {
|
|
715
|
+
if (cause instanceof EvolutionLedgerManifestError) throw cause;
|
|
716
|
+
const code =
|
|
717
|
+
cause?.code === "CC_EVOLUTION_LEDGER_IMMUTABLE_STORE_UNAVAILABLE"
|
|
718
|
+
? EVOLUTION_LEDGER_MANIFEST_UNAVAILABLE_CODE
|
|
719
|
+
: EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE;
|
|
720
|
+
throw failure(code, `immutable segment store ${action} failed`, { cause });
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
export function createEvolutionLedgerManifestAuthority(options = undefined) {
|
|
724
|
+
const fields = exactRecord(
|
|
725
|
+
options,
|
|
726
|
+
AUTHORITY_CONFIG_KEYS,
|
|
727
|
+
"manifest authority configuration",
|
|
728
|
+
);
|
|
729
|
+
const signFn = data(fields, "sign");
|
|
730
|
+
const verifyFn = data(fields, "verify");
|
|
731
|
+
rejectProxy(signFn, "manifest authority.sign");
|
|
732
|
+
rejectProxy(verifyFn, "manifest authority.verify");
|
|
733
|
+
if (typeof signFn !== "function" || typeof verifyFn !== "function") {
|
|
734
|
+
throw failure(
|
|
735
|
+
EVOLUTION_LEDGER_MANIFEST_INVALID_CODE,
|
|
736
|
+
"manifest authority sign and verify functions are required",
|
|
737
|
+
);
|
|
738
|
+
}
|
|
739
|
+
const authority = Object.freeze({
|
|
740
|
+
descriptor: authorityDescriptor(data(fields, "descriptor")),
|
|
741
|
+
sign: Object.freeze((request) =>
|
|
742
|
+
Reflect.apply(signFn, undefined, [request]),
|
|
743
|
+
),
|
|
744
|
+
verify: Object.freeze((request) =>
|
|
745
|
+
Reflect.apply(verifyFn, undefined, [request]),
|
|
746
|
+
),
|
|
747
|
+
});
|
|
748
|
+
AUTHORITIES.add(authority);
|
|
749
|
+
return authority;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
export function captureEvolutionLedgerManifestAuthority(value) {
|
|
753
|
+
return captureAuthority(value);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
export function sealEvolutionLedgerManifestSegment(options = undefined) {
|
|
757
|
+
const fields = exactRecord(
|
|
758
|
+
options,
|
|
759
|
+
SEAL_CONFIG_KEYS,
|
|
760
|
+
"manifest segment seal configuration",
|
|
761
|
+
);
|
|
762
|
+
const descriptorValue = descriptor(data(fields, "descriptor"));
|
|
763
|
+
const authority = captureAuthority(data(fields, "authority"));
|
|
764
|
+
const store = captureImmutableLedgerSegmentStorePort(
|
|
765
|
+
data(fields, "segmentStore"),
|
|
766
|
+
{
|
|
767
|
+
epoch: descriptorValue.epoch,
|
|
768
|
+
ledgerId: descriptorValue.ledgerId,
|
|
769
|
+
tenantId: descriptorValue.tenantId,
|
|
770
|
+
},
|
|
771
|
+
);
|
|
772
|
+
const previous = previousHead(
|
|
773
|
+
data(fields, "previousHead"),
|
|
774
|
+
descriptorValue,
|
|
775
|
+
authority,
|
|
776
|
+
);
|
|
777
|
+
const eventDigests = normalizeDigests(
|
|
778
|
+
data(fields, "eventDigests"),
|
|
779
|
+
"eventDigests",
|
|
780
|
+
descriptorValue.maximumEventsPerSegment,
|
|
781
|
+
);
|
|
782
|
+
const now = data(fields, "now");
|
|
783
|
+
rejectProxy(now, "manifest clock");
|
|
784
|
+
if (typeof now !== "function")
|
|
785
|
+
throw failure(
|
|
786
|
+
EVOLUTION_LEDGER_MANIFEST_INVALID_CODE,
|
|
787
|
+
"manifest clock is required",
|
|
788
|
+
);
|
|
789
|
+
const nowMs = Number(now());
|
|
790
|
+
if (!Number.isFinite(nowMs)) {
|
|
791
|
+
throw failure(
|
|
792
|
+
EVOLUTION_LEDGER_MANIFEST_INVALID_CODE,
|
|
793
|
+
"manifest clock returned an invalid time",
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
const issuedAt = timestamp(
|
|
797
|
+
new Date(nowMs).toISOString(),
|
|
798
|
+
"manifest issuedAt",
|
|
799
|
+
).value;
|
|
800
|
+
const sequenceStart = (previous?.sequence || 0) + 1;
|
|
801
|
+
const segmentPayload = payload(sequenceStart, eventDigests);
|
|
802
|
+
let receipt;
|
|
803
|
+
try {
|
|
804
|
+
receipt = store.retain({
|
|
805
|
+
bytes: payloadBytes(segmentPayload),
|
|
806
|
+
minimumRetainedUntil: timestamp(
|
|
807
|
+
data(fields, "minimumRetainedUntil"),
|
|
808
|
+
"minimumRetainedUntil",
|
|
809
|
+
).value,
|
|
810
|
+
sequenceEnd: segmentPayload.sequenceEnd,
|
|
811
|
+
sequenceStart,
|
|
812
|
+
});
|
|
813
|
+
} catch (cause) {
|
|
814
|
+
storeFailure(cause, "retain");
|
|
815
|
+
}
|
|
816
|
+
if (
|
|
817
|
+
receipt?.schema !== EVOLUTION_IMMUTABLE_LEDGER_SEGMENT_RECEIPT_SCHEMA ||
|
|
818
|
+
receipt.authenticated !== true ||
|
|
819
|
+
receipt.immutable !== true ||
|
|
820
|
+
receipt.readbackVerified !== true
|
|
821
|
+
) {
|
|
822
|
+
throw failure(
|
|
823
|
+
EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE,
|
|
824
|
+
"immutable segment store did not return a verified receipt",
|
|
825
|
+
);
|
|
826
|
+
}
|
|
827
|
+
const manifest = sign(
|
|
828
|
+
authority,
|
|
829
|
+
"ledger-segment-manifest",
|
|
830
|
+
Object.freeze({
|
|
831
|
+
authorityAlgorithm: authority.descriptor.algorithm,
|
|
832
|
+
authorityId: authority.descriptor.authorityId,
|
|
833
|
+
authorityRevision: authority.descriptor.revision,
|
|
834
|
+
contentDigest: receipt.contentDigest,
|
|
835
|
+
epoch: descriptorValue.epoch,
|
|
836
|
+
eventDigestRoot: sha256(Buffer.from(canonical(eventDigests), "utf8")),
|
|
837
|
+
eventDigests,
|
|
838
|
+
issuedAt,
|
|
839
|
+
ledgerId: descriptorValue.ledgerId,
|
|
840
|
+
manifestSequence: (previous?.manifestSequence || 0) + 1,
|
|
841
|
+
previousManifestDigest: previous?.manifestDigest || null,
|
|
842
|
+
retainedUntil: receipt.retainedUntil,
|
|
843
|
+
schema: EVOLUTION_LEDGER_SEGMENT_MANIFEST_SCHEMA,
|
|
844
|
+
segmentRef: receipt.segmentRef,
|
|
845
|
+
sequenceEnd: segmentPayload.sequenceEnd,
|
|
846
|
+
sequenceStart,
|
|
847
|
+
storageVersion: receipt.storageVersion,
|
|
848
|
+
tenantId: descriptorValue.tenantId,
|
|
849
|
+
}),
|
|
850
|
+
"manifestDigest",
|
|
851
|
+
);
|
|
852
|
+
const head = sign(
|
|
853
|
+
authority,
|
|
854
|
+
"ledger-manifest-head",
|
|
855
|
+
Object.freeze({
|
|
856
|
+
authorityAlgorithm: authority.descriptor.algorithm,
|
|
857
|
+
authorityId: authority.descriptor.authorityId,
|
|
858
|
+
authorityRevision: authority.descriptor.revision,
|
|
859
|
+
epoch: descriptorValue.epoch,
|
|
860
|
+
eventDigest: eventDigests.at(-1),
|
|
861
|
+
issuedAt,
|
|
862
|
+
ledgerId: descriptorValue.ledgerId,
|
|
863
|
+
manifestDigest: manifest.manifestDigest,
|
|
864
|
+
manifestSequence: manifest.manifestSequence,
|
|
865
|
+
previousHeadDigest: previous?.headDigest || null,
|
|
866
|
+
schema: EVOLUTION_LEDGER_MANIFEST_HEAD_SCHEMA,
|
|
867
|
+
sequence: segmentPayload.sequenceEnd,
|
|
868
|
+
tenantId: descriptorValue.tenantId,
|
|
869
|
+
}),
|
|
870
|
+
"headDigest",
|
|
871
|
+
);
|
|
872
|
+
return Object.freeze({
|
|
873
|
+
head,
|
|
874
|
+
manifest,
|
|
875
|
+
segmentReceipt: receipt,
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
export function verifyEvolutionLedgerManifestHead(options = undefined) {
|
|
880
|
+
const fields = exactRecord(
|
|
881
|
+
options,
|
|
882
|
+
VERIFY_HEAD_CONFIG_KEYS,
|
|
883
|
+
"manifest head verification configuration",
|
|
884
|
+
);
|
|
885
|
+
const descriptorValue = descriptor(data(fields, "descriptor"));
|
|
886
|
+
const authority = captureAuthority(data(fields, "authority"));
|
|
887
|
+
return normalizeHead(data(fields, "head"), descriptorValue, authority);
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
export function verifyEvolutionLedgerSegmentManifest(options = undefined) {
|
|
891
|
+
const fields = exactRecord(
|
|
892
|
+
options,
|
|
893
|
+
VERIFY_MANIFEST_CONFIG_KEYS,
|
|
894
|
+
"segment manifest verification configuration",
|
|
895
|
+
);
|
|
896
|
+
const descriptorValue = descriptor(data(fields, "descriptor"));
|
|
897
|
+
const authority = captureAuthority(data(fields, "authority"));
|
|
898
|
+
return normalizeManifest(
|
|
899
|
+
data(fields, "manifest"),
|
|
900
|
+
descriptorValue,
|
|
901
|
+
authority,
|
|
902
|
+
);
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
export function verifyEvolutionLedgerManifestChain(options = undefined) {
|
|
906
|
+
const fields = exactRecord(
|
|
907
|
+
options,
|
|
908
|
+
VERIFY_CONFIG_KEYS,
|
|
909
|
+
"manifest chain verification configuration",
|
|
910
|
+
);
|
|
911
|
+
const descriptorValue = descriptor(data(fields, "descriptor"));
|
|
912
|
+
const authority = captureAuthority(data(fields, "authority"));
|
|
913
|
+
const store = captureImmutableLedgerSegmentStorePort(
|
|
914
|
+
data(fields, "segmentStore"),
|
|
915
|
+
{
|
|
916
|
+
epoch: descriptorValue.epoch,
|
|
917
|
+
ledgerId: descriptorValue.ledgerId,
|
|
918
|
+
tenantId: descriptorValue.tenantId,
|
|
919
|
+
},
|
|
920
|
+
);
|
|
921
|
+
const manifests = data(fields, "manifests");
|
|
922
|
+
rejectProxy(manifests, "manifests", EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE);
|
|
923
|
+
if (
|
|
924
|
+
!Array.isArray(manifests) ||
|
|
925
|
+
manifests.length < 1 ||
|
|
926
|
+
Object.keys(manifests).length !== manifests.length
|
|
927
|
+
) {
|
|
928
|
+
throw failure(
|
|
929
|
+
EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE,
|
|
930
|
+
"manifests must be a non-empty dense array",
|
|
931
|
+
);
|
|
932
|
+
}
|
|
933
|
+
let previous = null;
|
|
934
|
+
for (const rawManifest of manifests) {
|
|
935
|
+
const manifest = normalizeManifest(rawManifest, descriptorValue, authority);
|
|
936
|
+
if (
|
|
937
|
+
manifest.manifestSequence !== (previous?.manifestSequence || 0) + 1 ||
|
|
938
|
+
manifest.previousManifestDigest !== (previous?.manifestDigest || null) ||
|
|
939
|
+
manifest.sequenceStart !== (previous?.sequenceEnd || 0) + 1
|
|
940
|
+
) {
|
|
941
|
+
throw failure(
|
|
942
|
+
EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE,
|
|
943
|
+
"manifest chain linkage is invalid",
|
|
944
|
+
);
|
|
945
|
+
}
|
|
946
|
+
let resolution;
|
|
947
|
+
try {
|
|
948
|
+
resolution = store.resolve({
|
|
949
|
+
contentDigest: manifest.contentDigest,
|
|
950
|
+
minimumRetainedUntil: manifest.retainedUntil,
|
|
951
|
+
segmentRef: manifest.segmentRef,
|
|
952
|
+
sequenceEnd: manifest.sequenceEnd,
|
|
953
|
+
sequenceStart: manifest.sequenceStart,
|
|
954
|
+
storageVersion: manifest.storageVersion,
|
|
955
|
+
});
|
|
956
|
+
} catch (cause) {
|
|
957
|
+
storeFailure(cause, "resolve");
|
|
958
|
+
}
|
|
959
|
+
if (
|
|
960
|
+
resolution?.schema !==
|
|
961
|
+
EVOLUTION_IMMUTABLE_LEDGER_SEGMENT_RESOLUTION_SCHEMA ||
|
|
962
|
+
resolution.authenticated !== true ||
|
|
963
|
+
resolution.immutable !== true
|
|
964
|
+
) {
|
|
965
|
+
throw failure(
|
|
966
|
+
EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE,
|
|
967
|
+
"manifest segment resolution is not authenticated immutable storage",
|
|
968
|
+
);
|
|
969
|
+
}
|
|
970
|
+
const parsed = parsePayload(resolution.bytes, manifest);
|
|
971
|
+
if (canonical(parsed.eventDigests) !== canonical(manifest.eventDigests)) {
|
|
972
|
+
throw failure(
|
|
973
|
+
EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE,
|
|
974
|
+
"manifest event digests differ from immutable bytes",
|
|
975
|
+
);
|
|
976
|
+
}
|
|
977
|
+
previous = manifest;
|
|
978
|
+
}
|
|
979
|
+
const head = normalizeHead(data(fields, "head"), descriptorValue, authority);
|
|
980
|
+
if (
|
|
981
|
+
head.manifestSequence !== previous.manifestSequence ||
|
|
982
|
+
head.manifestDigest !== previous.manifestDigest ||
|
|
983
|
+
head.sequence !== previous.sequenceEnd ||
|
|
984
|
+
head.eventDigest !== previous.eventDigests.at(-1)
|
|
985
|
+
) {
|
|
986
|
+
throw failure(
|
|
987
|
+
EVOLUTION_LEDGER_MANIFEST_CORRUPT_CODE,
|
|
988
|
+
"manifest head does not bind the final manifest",
|
|
989
|
+
);
|
|
990
|
+
}
|
|
991
|
+
return Object.freeze({
|
|
992
|
+
authenticated: true,
|
|
993
|
+
head,
|
|
994
|
+
manifestCount: manifests.length,
|
|
995
|
+
sequence: head.sequence,
|
|
996
|
+
});
|
|
997
|
+
}
|