6. Decentralized Evidence Storage

Summary: on-chain we keep hashes and IDs; off-chain we keep the actual evidence files. The chain stores evidenceHash and links; storage systems hold the canonical JSON and any raw artifacts under access control with integrity checks. This makes PoV auditable without leaking private data.

What goes where

On-chain: only proofs and pointers — evidenceHash, claimId, attestation UIDs, and a small set of link fields (for example evidence_uri, source_file_hash).

Off-chain: the canonical JSON (the exact bytes that hashed to evidenceHash) and optional raw exports (CSV/Parquet, photos, lab PDFs), stored in a system that can prove immutability and availability.

Storage options

Use what fits the evidence type and confidentiality, but keep a single rule: the bytes you fetch must reproduce the on-chain evidenceHash.

S3/Cloud object store (with versioning & WORM): best for private or regulated artifacts; serves short-lived signed URLs.

IPFS (CID v1, optional pinning providers): good for public or semi-public artifacts; use CAR files for large attachments.

Arweave (permanent): for public proofs that must never disappear; expect higher cost, strong immutability.

You can mix them: for example, canonical JSON on IPFS; raw grid export in S3; an Arweave receipt for the JSON CID.

Evidence package

Each window or claim has exactly one canonical JSON. If there are extra files, describe them via a tiny manifest so auditors know what to fetch.

Canonical JSON (single source of truth): minified, sorted, UTF-8, includes batch_id, device_id, start_ts, end_ts, quantity_wh, nonce.

Manifest (optional, JSON):

{
  "canonical_uri": "ipfs://bafy.../window.json",
  "canonical_sha256": "0xdca11c7b4c9347db3134f5cced0610541b863c22cc26325d9c28e7e41870c34d",
  "attachments": [
    {"name":"grid_export.csv","sha256":"0x...","uri":"s3://edma-evidence/.../grid_export.csv"},
    {"name":"meter_photo.jpg","sha256":"0x...","uri":"ipfs://bafy.../meter_photo.jpg"}
  ]
}

On-chain you reference evidenceHash (the SHA-256 of the canonical JSON bytes) and, if used, a manifest_uri and manifest_sha256.

Use stable, typed link fields in attestations or proofs:

evidence_uri: where to fetch the canonical JSON (for example ipfs://…, s3://…, ar://…)

evidence_sha256: identical to on-chain evidenceHash

manifest_uri and manifest_sha256 (optional)

source_file_hash: SHA-256 of the raw export (CSV/Parquet) if present

Explorers should render links but never assume public access; if a link requires a signed URL, show a “request access” button.

Access control and privacy

Keep PII off-chain. Gate private artifacts with short-lived signed URLs; log access. Do not embed secrets in URIs.

Example (Node, S3 presign):

For IPFS, pin the CID with at least two providers; for Arweave, record the transaction id and optional gateway URL.

Integrity checks

  1. Fetch canonical_json via evidence_uri (or via the manifest).

  2. Compute local SHA-256; compare to on-chain evidenceHash.

  3. Recompute claimId from device_id, start_ts, end_ts, quantity_wh, and the evidenceHash.

  4. Ensure the on-chain proof and One-Claim finalization used that same tuple.

TypeScript (verify):

Enable object versioning and a WORM (write-once, read-many) or legal-hold mode where policy requires. Never overwrite canonical_json; if there is a correction, it should appear as a new window with a new batch_id and its own evidenceHash. For regulated programs, document retention periods and keep region-appropriate replicas.

Failure modes and how to handle them

If a link breaks, you still have the on-chain evidenceHash. Operators should republish the exact same bytes (same hash) under a new URI and update the off-chain registry that your Explorer reads. If an artifact becomes confidential after the fact, move it behind signed URLs; the hash remains public and unchanged.

Conformance

Store canonical JSON off-chain; publish only its evidenceHash and a stable evidence_uri. Keep optional files referenced in a manifest with their own hashes. Use short-lived signed URLs for private data. Always verify the fetched bytes reproduce the on-chain evidenceHash, then re-derive claimId to confirm One-Claim aligns.

Drawing

Last updated