Discover our latest AI-powered innovations around faster payments, smarter workflows, and real-time visibility.Learn more →

Journal

How to Scale a Ledger, Part III

In the third part of this series, we'll look at how Transaction models enable atomic money movement and enforce double-entry.

Matt McNierneyEngineering

Note: This post is the third chapter of a broader technical paper on How to Scale a Ledger.

A Transaction Model

Some ledger databases stop with just Accounts and Entries. We already have a way to store an immutable history of balance changes with the first two models. However, a robust ledger system should also have a Transaction model to enable atomic movement of money between Accounts and enforce double-entry rules.

Transaction
Transaction fields and descriptions

Consider a simple transfer of money between two digital wallets, one owned by Alice and one by Bob. If Bob sends Alice $10, we can represent that transfer as two Entries.

Two Digital Wallet Entries
Two entries showing a $10 digital wallet transfer from Bob to Alice

Imagine that bob_entry was successfully created, but alice_entry failed to create (maybe the database was having network issues). Now the ledger is in an inconsistent state—Bob was debited money, but Alice didn’t get anything.

Transactions solve this consistency problem by allowing us to specify groups of Entries that either must all succeed or all fail. In order to guarantee atomicity, all the non-discarded Entries on a Transaction must share the status of the Transaction. This ensures that all Entries progress in status at the same time, all-or-nothing.

A Ledger API should only allow clients to directly create Transactions, not Entries. This limitation helps ensure clients don’t run into consistency problems. That means a Ledger API must manage creating Entries itself. There are three operations to implement, corresponding to the possible states of the Transaction.

Creating a Pending Transaction

This is generally the first step in the lifecycle of a Transaction. We simply need to persist the Entries.

Persisting the two entries
Persisting the $10 digital wallet transfer from Bob to Alice to create a Transaction

Posting a Pending Transaction

Since Entries are immutable, when we move a Transaction from pending to posted, we need to discard and then create new Entries.

1. Discard bob_entry_1 and alice_entry_1.

Discard entry_1
Discarding pending entries bob_entry_1 and alice_entry_1

2. Create posted Entries.

Create posted entries
Posted entries to show the posted $10 transaction

Archive a Pending Transaction

Posted Transactions are immutable, and so cannot be archived. Pending Transactions can be archived, following a similar process to posting.

1. Discard bob_entry_1 and alice_entry_1.

Discard pending transactions to be archived
Discarding pending transactions bob_entry_1 and alice_entry_1 to be archived

2. Create archived entries.

Create archived entries
Archived entries for the $10 transaction from Bob to Alice

Next Steps

This is the third chapter of a broader technical paper with a more comprehensive overview of the importance of solid ledgering and the amount of investment it takes to get right. If you want to learn more, download the paper, or get in touch.

Read the rest of the series:

Part I | Part II | Part IV | Part V | Part VI

Try Modern Treasury

See how smooth payment operations can be.

Talk to sales