On The Ledger logo

The source of truth for modern financial systems

About How It Works

Guide ยท Developers

Audit & trust (Developers)

How our hash-chain audit trail keeps your ledger tamper-evident, replayable, and provable.

What is the audit chain?

Every transaction stores a content hash and a link to the prior transaction (by recorded_at order). This forms a forward-only chain โ€” any change would break the links, so tampering is evident.

How it works

  • Deterministic hashing: the transaction payload (metadata + entries) is hashed consistently.
  • Linking: each new transaction records the previous transaction's hash as its pointer.
  • Append-only: recorded_at enforces chain order; backdated effective dates are allowed without breaking continuity.
  • Replayable: you can recompute the chain end-to-end to verify integrity.

Why it matters

  • Trust: partners and auditors can verify no silent edits occurred.
  • Safety: retries are safe โ€” idempotent posting returns the same result for the same payload.
  • Transparency: clear ordering and linking make investigations straightforward.

Running an audit

From the Rails console, run the audit service to verify the chain:

result = Ledger::Public::Services::AuditManager.audit_chain(ledger_id: "your-ledger-id")
if result.success?
  puts "Chain intact across #{result.checked_count} transactions"
else
  puts "Divergence at #{result.divergence_at}: #{result.errors.first[:message]}"
end

You can scope audits to a point in time or run full history to support compliance reviews.

Independently verifying a hash

You can reproduce any transaction's strong_content_hash without trusting our system. The hash is a SHA-256 digest over a canonical JSON payload. The event log preserves the exact payload used at posting time โ€” replay it to confirm our stored hash matches what you compute independently.

What strong_content_hash covers

  • sequence_number, ledger_id, effective_at_epoch_us, description, reference_number, idempotency_key, metadata, adjusting
  • entries โ€” sorted array of: account_id, direction, amount_cents, currency
  • previous_hash โ€” the hash of the immediately preceding transaction

Note: effective_at is converted to microseconds since Unix epoch (effective_at_epoch_us) before hashing. transaction_id is not included in the hash.

sequence_number guarantees

Every domain event carries a ledger-scoped sequence_number assigned at write time. Numbers are monotonically increasing and never reused. A gap or duplicate in the sequence would indicate a missing or injected event.