bal

package
v0.16.13 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 21, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package bal is the conservation primitive (@B): an append-only double-entry journal over bounded accounts, where conservation is an arithmetic identity — every transfer writes two signed entries (−a, +a) in one transaction, so the system total always equals the sum of its boundary accounts.

Identity (@B09a): the substrate-preferred two-identity split. The external account_id is a namespaced STRING at every boundary — no numeric width exists to truncate, so the /ts id-boundary bug class is structurally impossible here (@C04d the strong way). The internal account key is a dense uint32, engine-internal, fixed-width codec, never on any wire struct.

Numerics (@B04): amounts are int64 minor units through the account's scale. No float64 touches an amount anywhere, ever — ParseAmount is the only sanctioned string→amount crossing.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func EncodeAccountKey

func EncodeAccountKey(k AccountKey) [4]byte

EncodeAccountKey writes the key with an explicit fixed-width codec (4 bytes, big-endian) — the sanctioned byte crossing.

func FormatAmount

func FormatAmount(v int64, scale uint8) string

FormatAmount renders minor units back to the canonical decimal string at the account's scale.

func ParseAmount

func ParseAmount(s string, scale uint8) (int64, error)

ParseAmount converts a decimal string to int64 minor units under the account's scale — the ONLY string→amount crossing. It refuses anything that is not an exact integer of minor units at that scale (XOLU-BAL004 territory), and never passes through float64.

func ValidateAccountID

func ValidateAccountID(id string) error

ValidateAccountID enforces the external-id shape: non-empty, ≤256, no whitespace; '/' and ':' and '.' are the namespace vocabulary.

Types

type AccountDef

type AccountDef struct {
	ID       string // namespaced external id, e.g. "warehouse:A/widget" or "1.1.9.10"
	Unit     string // "EUR", "widget", "gram"
	Scale    uint8  // decimal places of the minor unit
	Floor    int64  // minimum balance (default 0)
	Ceiling  *int64 // optional maximum balance
	Postable bool   // only leaf (imputable) accounts accept entries (@B03a)
}

AccountDef defines an account (@B03, @B03a).

func (AccountDef) Validate

func (d AccountDef) Validate() error

Validate checks a definition.

type AccountKey

type AccountKey uint32

AccountKey is the engine-internal dense identity: uint32, the wave-1 per-primitive width. It never appears in JSON.

const MaxAccountKey AccountKey = 0xFFFFFFFF

MaxAccountKey is the codec ceiling; it fits uint32 exactly.

func DecodeAccountKey

func DecodeAccountKey(b [4]byte) AccountKey

DecodeAccountKey reads the fixed-width codec back, losslessly across the full uint32 span.

type AmountScaleError

type AmountScaleError struct{ Detail string }

func (*AmountScaleError) Error

func (e *AmountScaleError) Error() string

type BoundsError

type BoundsError struct {
	AccountID string
	Side      string // "floor" or "ceiling"
}

func (*BoundsError) Error

func (e *BoundsError) Error() string

type ChainBreak

type ChainBreak struct {
	AccountKey int64
	EntryID    int64
	Detail     string
}

ChainBreak localises a violation of the per-account arithmetic chain.

type NotPostableError

type NotPostableError struct{ AccountID string }

func (*NotPostableError) Error

func (e *NotPostableError) Error() string

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store is bal's SQL plane (@B05): the append-only journal and the balances table, maintained in the same transaction as each entry. The bounds guard's input commits-or-aborts with the entry it guards (@C04a); no rollup is ever consulted by a guard.

The db handle must carry the house SQLite contract: WAL + busy_timeout + _txlock=immediate. Immediate matters specifically for bal: Transfer reads account rows before its first UPDATE, and a deferred transaction upgrading read→write under WAL fails SQLITE_BUSY without consulting the busy handler (snapshot invalidation). Taking the write lock at BEGIN makes contending transfers queue under busy_timeout — the serialised-writer behaviour the admission guard's correctness argument assumes.

func NewStore

func NewStore(db *sql.DB, tablePrefix string) *Store

NewStore binds bal to a database with a tenant table prefix.

func (*Store) Balance

func (s *Store) Balance(ctx context.Context, accountID string) (value int64, version int64, err error)

Balance returns the current balance and version for an account.

func (*Store) ChainOracle

func (s *Store) ChainOracle() chronicle.RebuildOracle

ChainOracle wraps VerifyChains as a rebuild oracle for iolu db check.

func (*Store) DefineAccount

func (s *Store) DefineAccount(ctx context.Context, def AccountDef) (AccountKey, error)

DefineAccount creates an account and its zero balance row. The internal key is allocated densely (MAX+1) inside the transaction.

func (*Store) GlobalFoldOracle

func (s *Store) GlobalFoldOracle() chronicle.RebuildOracle

GlobalFoldOracle: SELECT SUM per account from the journal, compared row-for-row against balances — derive(journal) == current, exactly.

func (*Store) Init

func (s *Store) Init(ctx context.Context) error

Init creates the bal tables. Idempotent. The journal's `state` column (default 'committed') leaves room for holds (@B10) without migration.

func (*Store) Transfer

func (s *Store) Transfer(ctx context.Context, transferID, from, to string, amount int64, memo string, at time.Time) error

Transfer moves amount minor units from `from` to `to` as two signed journal entries (−a, +a) in ONE transaction (@B03). Admission is the house CAS discipline (@B06, T-34): the decision lives inside each UPDATE's predicate, rows-affected is the verdict — never read-decide-write. The chain triple is captured from the same guarded statement via RETURNING.

func (*Store) VerifyChains

func (s *Store) VerifyChains(ctx context.Context) ([]ChainBreak, error)

VerifyChains is the local verifier (@B08): per account, every entry satisfies previous+amount=current, entryₙ.previous = entryₙ₋₁.current, and versions are contiguous. A lost, duplicated, or altered entry is not merely detected but LOCALISED to the exact break.

type UnknownAccountError

type UnknownAccountError struct{ AccountID string }

func (*UnknownAccountError) Error

func (e *UnknownAccountError) Error() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL