Accounts
An Account
is a record storing the cumulative effect of committed
transfers.
TigerBeetle uses the same data structures internally and externally. This means that sometimes you need to set temporary values for fields that TigerBeetle, not you (the user), are responsible.
Updates
Account fields cannot be changed by the user after creation. However, debits and credits fields are updated by TigerBeetle as transfers move money to and from an account.
Fields
id
This is a unique, client-defined identifier for the account.
Constraints:
- Type is 128-bit unsigned integer (16 bytes)
- Must not be zero or
2^128 - 1
(the highest 128-bit unsigned integer) - Must not conflict with another account
user_data
This is an optional secondary identifier to link this account to an external entity.
As an example, you might use a random id that ties together a group of accounts.
For more information, see Data Modeling.
Constraints:
- Type is 128-bit unsigned integer (16 bytes)
reserved
This space may be used for additional data in the future.
Constraints:
- Type is 48 bytes
- Must be zero
ledger
This is an identifier that partitions the sets of accounts that can
transact with each other. Put another way, money cannot transfer
between two accounts with different ledger
values. See:
accounts_must_have_the_same_ledger
.
Currency exchange is implemented with two or more linked transfers.
In a typical use case:
- Map each asset or currency tracked within the database to a distinct ledger. And,
- Tag each account with the
ledger
indicating the currency in which the balance is denominated.
Constraints:
- Type is 32-bit unsigned integer (4 bytes)
- Must not be zero
code
This is a user-defined enum denoting the category of the account.
As an example, you might use codes 1000
-3340
to indicate asset
accounts in general, where 1001
is Bank Account and 1002
is Money
Market Account and 2003
is Motor Vehicles and so on.
Constraints:
- Type is 16-bit unsigned integer (2 bytes)
- Must not be zero
flags
A bitfield that toggles additional behavior.
Constraints:
- Type is 16-bit unsigned integer (2 bytes)
flags.linked
When the linked
flag is specified, it links an account with the next
account in the batch, to create a chain of accounts, of arbitrary
length, which all succeed or fail in creation together. The tail of a
chain is denoted by the first account without this flag. The last
account in a batch may therefore never have flags.linked
set as
this would leave a chain open-ended (see linked_event_chain_open
).
Multiple chains or individual accounts may coexist within a batch to
succeed or fail independently. Accounts within a chain are executed
in order, or are rolled back on error, so that the effect of each
account in the chain is visible to the next, and so that the chain is
either visible or invisible as a unit to subsequent accounts after the
chain. The account that was the first to break the chain will have a
unique error result. Other accounts in the chain will have their error
result set to
linked_event_failed
.
After the link has executed, the association of each event is lost. To save the association, it must be encoded into the data model.
flags.debits_must_not_exceed_credits
When set, transfers will be rejected that would cause this account's
debits to exceed credits. Specifically when account.debits_pending +
account.debits_posted + transfer.amount > account.credits_posted
.
This cannot be set when credits_must_not_exceed_debits
is also set.
flags.credits_must_not_exceed_debits
When set, transfers will be rejected that would cause this account's
credits to exceed debits. Specifically when account.credits_pending +
account.credits_posted + transfer.amount > account.debits_posted
.
This cannot be set when debits_must_not_exceed_credits
is also set.
debits_pending
debits_pending
counts debits reserved by pending transfers. When a pending transfer posts, voids,
or times out, the amount is removed from debits_pending
.
Money in debits_pending
is reserved — that is, it cannot be spent until the corresponding pending
transfer resolves.
Constraints:
- Type is 64-bit unsigned integer (8 bytes)
- Must be zero when the account is created
debits_posted
Amount of posted debits.
Constraints:
- Type is 64-bit unsigned integer (8 bytes)
- Must be zero when the account is created
credits_pending
Amount of pending credits.
Constraints:
- Type is 64-bit unsigned integer (8 bytes)
- Must be zero when the account is created
credits_posted
Amount of posted credits.
Constraints:
- Type is 64-bit unsigned integer (8 bytes)
- Must be zero when the account is created
timestamp
This is the time the account was created, as nanoseconds since UNIX epoch.
It is set by TigerBeetle to the moment the account arrives at the cluster.
Additionally, all timestamps are unique, immutable and totally ordered. So an account that is created before another account is guaranteed to have an earlier timestamp. In other systems this is also called a "physical" timestamp, "ingestion" timestamp, "record" timestamp, or "system" timestamp.
Constraints:
- Type is 64-bit unsigned integer (8 bytes)
- User sets to zero on creation
Internals
If you're curious and want to learn more, you can find the source code
for this struct in
src/tigerbeetle.zig. Search
for const Account = extern struct {
.
You can find the source code for creating an account in
src/state_machine.zig. Search
for fn create_account(
.