Log Hash feature and Advisory Locks

Last updated: July 23, 2025

One of the features of the Formance Ledger is its log hashing mechanism—a way to cryptographically chain all log entries together, similar to how a blockchain works.

  • This ensures tamper-evidence - If you check the logs and verify the hashes, you can cryptographically confirm that no entries were modified or injected.

  • This is especially useful for auditability or compliance purposes.

We use a PostgreSQL advisory lock, to lock the entire ledger (or bucket) for the purpose of the hash & log update. This mechanism allows us to serialize access to the hashing operation without blocking other database activity unrelated to that ledger.


How It Works

When the log hash feature is enabled on a ledger (a ledger is created on bucket _default if none specified upon creation, if it is, then 1 ledger = 1 bucket. cf. Data isolation w/ buckets):

  1. Before inserting a log, the system must compute the hash of the new log using:

    • The contents of the current entry.

    • The hash of the previous log entry.

  2. To ensure this operation is safe in concurrent environments, we must serialize writes. That is, we must prevent parallel writes that could break the hash chain.

🔒 Advisory Locking in PostgreSQL

Since we aren't locking a particular row or table (we’re locking the entire ledger for the purpose of the hash), we use a PostgreSQL advisory lock:

SELECT pg_advisory_lock(<ledger_id>);
  • This lock is application-defined: it’s not tied to a specific table or row.

  • The ledger_id (or similar unique identifier) is used to represent the scope of the lock. This means: writes to that specific bucket will be serialized (PG blocks concurrent writes within the same bucket/ledger), but writes to other buckets can proceed concurrently without interference.

  • Once acquired, it prevents any other concurrent session from acquiring the same lock until it's released.

  • It's session-level—the lock is automatically released at the end of the transaction.

This mechanism allows us to serialize access to the hashing operation without blocking other database activity unrelated to that ledger.

🔁 What Happens During a Hashed Log Insert

Here’s the high-level flow:

  1. Acquire advisory lock for the ledger.

  2. Retrieve the most recent log entry (to get its hash).

  3. Compute the hash of the new log by chaining it with the previous hash.

  4. Insert the new log entry (with the hash) into the ledger.

  5. Release the advisory lock (automatically at the end of the transaction).

This guarantees that no two writers can insert a hashed log in parallel, thus preserving the integrity of the hash chain.


📌 Summary: When and Why Hashing Matters

Feature

SYNC(default)

DISABLED

Hash Chain

Logs chained via previous hash

No chaining

Advisory Lock

Used to serialize writes

Not used

Write Throughput

Lower (due to lock and serialization)

Higher

Use Case

Auditable, compliant systems

High-throughput systems where tamper-proofing isn’t required