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):
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.
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:
Acquire advisory lock for the ledger.
Retrieve the most recent log entry (to get its hash).
Compute the hash of the new log by chaining it with the previous hash.
Insert the new log entry (with the hash) into the ledger.
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 |