Skip to content

DAR Backup

HardlyDifficult edited this page Jul 13, 2026 · 18 revisions

DAR File Backup System

The repo dars/ tree preserves versioned DAR (DAML Archive) files for OpenCapTable uploads. Since DAML builds are only deterministic when using the exact same compiler version, we store the exact bytes of published packages here.

As of #217, dars/ and dars.lock keep only OpenCapTable-vNN backups (currently v34 on-chain, v35 0.0.2 local backup with networks: []). Older OCP DARs and packages maintained in fairmint/daml are not backed up in this tree—use that repo (and its lockfiles / release process) for those artifacts. #216 moved non-OCP sources out of this repo; #217 aligns checked-in backups with the OCP-only layout.

Not the same as the npm DAR: The published JS package @fairmint/open-captable-protocol-daml-js also ships a copy of the current OpenCapTable DAR under a stable export path (opencaptable.darpublished-dars/OpenCapTable.dar; see the NPM Publishing section on Home, including getOpenCapTableDarPath() / resolveOpenCapTableDarPath(), env var OPEN_CAP_TABLE_DAR_PATH, and sibling overrides). That artifact is for downstream tooling tied to the npm release, while dars/ is the canonical backup of deployed OpenCapTable package/version pairs for verification and rollback.

Why We Need This

  1. Package verification - Canton validates package hashes; rebuilt packages have different hashes
  2. Reproducibility - Ensures we can always redeploy the exact same artifact
  3. Rollback safety - Allows redeploying a known-good version if needed

Directory Structure

The exact set of backed-up artifacts is defined by dars/dars.lock (and the matching paths under dars/). Example layout:

dars/
├── dars.lock                          # Hash manifest for CI verification
├── OpenCapTable-v34/
│   └── 0.0.1/
│       └── OpenCapTable-v34.dar       # On-chain (devnet + mainnet)
├── OpenCapTable-v35/
│   ├── 0.0.1/
│   │   └── OpenCapTable-v35.dar       # Superseded local backup
│   └── 0.0.2/
│       └── OpenCapTable-v35.dar       # Current local backup (not yet uploaded)
└── …                                  # Additional OpenCapTable-vNN/<version>/ rows per dars.lock

There is no dars/README.md in the repo — this wiki page and dars.lock are the references.

Related archives: Historical DAR backups for packages that are no longer stored under this repo’s dars/ tree may also be maintained in Fairmint/daml alongside its lockfile.

Using the Backup System

Before an Upload

Build and back up the candidate in the PR before running the release workflow:

npm run backup-dar -- --package OpenCapTable-v35 --version 0.0.2

This will:

  1. Copy the DAR from .daml/dist/ to dars/{package}/{version}/
  2. Compute and store the SHA256 hash in dars.lock
  3. Replace that exact version only when it is the expected undeployed candidate

The release workflow does not create or refresh DAR backups. It uploads only when a fresh build is byte-identical to the committed candidate.

Verifying DAR Integrity

Check that all DAR files match their recorded hashes:

npm run verify-dars

CI Integration

  • check-dars.yml — runs on pushes that change dars/** (or the workflow file). Executes npm run verify-dars to ensure hashes match dars.lock.
  • ci.yml — reads Git tags and committed files only. It verifies the candidate version and exact build-to-backup hash without querying Canton.
  • release.yml — uploads the already committed candidate and records annotated deployment tags after successful network uploads. It refuses to continue if release execution changes dars/.

PRs that modify DAR files without a matching dars.lock update will fail verification.

dars.lock Format

The dars.lock file contains SHA256 hashes and metadata for all backed-up DARs:

{
  "version": 1,
  "packages": {
    "OpenCapTable-v34/0.0.1/OpenCapTable-v34.dar": {
      "sha256": "abc123...",
      "size": 12345,
      "sdkVersion": "3.4.10",
      "uploadedAt": "2026-01-09T12:00:00Z",
      "networks": ["mainnet", "devnet"]
    }
  }
}

The networks array is retained as legacy deployment history. New successful deployments are recorded by annotated Git tags:

dar-deploy/devnet/OpenCapTable-v34/v0.0.2
dar-deploy/mainnet/OpenCapTable-v34/v0.0.2

The latest DevNet tag is the only candidate anchor. If the current DAR differs, its version must be exactly one patch higher; with no DevNet tag, the candidate is 0.0.1. Legacy networks markers are retained as immutable history but are never used to choose a candidate. Mainnet requires the exact same-version DevNet tag and locked DAR hash.

The Immutable DAR deployment tags repository ruleset permits creation of new dar-deploy/** tags but rejects updates and deletion of an existing deployment tag. The initial OpenCapTable-v34 DevNet baseline is dar-deploy/devnet/OpenCapTable-v34/v0.0.1.

Git LFS

DAR files are stored using Git LFS to keep the repository performant. The .gitattributes file configures this automatically.

Modifying DARs

Never modify a DAR file directly. If you need to deploy a new version:

  1. Update the DAML source code
  2. Set daml.yaml to the shared candidate version: latest DevNet success tag plus one patch
  3. Build and back up the candidate with npm run backup-dar
  4. Commit the source, DAR, and dars.lock before releasing

Parallel PRs may replace the same undeployed candidate slot. CI rejects changes to tagged, legacy network-marked, or other historical rows.

Rerunning npm run backup-dar also restores the candidate backup from the fresh build when the committed DAR file is missing or corrupt but its lock entry is still correct.

Troubleshooting

Mainnet upload: NOT_VALID_UPGRADE_PACKAGE (Splice / lineage)

Canton’s default upload path vets new packages immediately. If the new DAR is not an LF-valid upgrade of an already-vetted same package name (often because embedded splice-amulet changed between builds), upload fails with NOT_VALID_UPGRADE_PACKAGE.

Sketch of the escape hatch: upload with --no-vet, then vet the new package id via POST /v2/package-vetting with operator force flags when your topology allows it. Regenerate JS (npm run codegen) after any splice-amulet data-dependency change so bundled imports match the built DAR. For CantonPayments and other multi-package lineages, follow the playbooks documented with fairmint/daml. In this repo, npm run vet-package-allow-incompatible-upgrade is a thin helper around forced vetting (see script header in scripts/vet-package-allow-incompatible-upgrade.ts).

"Deployed DAR is immutable" error

The version is already recorded by a successful deployment tag or a legacy network marker. Use exactly one patch above the latest DevNet deployment instead of replacing it.

"Hash mismatch" error in CI

This means a DAR file has been modified without updating dars.lock. Either:

  1. Restore the original DAR file
  2. If intentional, update dars.lock with npm run verify-dars -- --update

Git LFS not working

Make sure Git LFS is installed and initialized:

git lfs install
git lfs pull

References

Clone this wiki locally