RealmPath
untyped stringRealmPath is this realm's own path, used to build Render links.
Value
"/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/books"
MaxAccountsPerBook
untyped bigintMaxAccountsPerBook caps one owner's chart. Far below journal's MaxAccountsLimit of 10000: IsBalanced sums the whole chart, and this bound is what keeps that read cheap for everyone.
Value
(128 <untyped> bigint)
MaxEntriesPerBook
untyped bigintMaxEntriesPerBook caps one owner's journal. Far below journal's MaxEntriesLimit of 1000000, because that limit's interaction with RederiveFromJournal is unmeasured — see the package doc. A book that fills up refuses further entries rather than dropping history. The remedy is a fresh book with opening balances carried forward; there is deliberately no Archive, because it would destroy history and needs more design than it has had.
Value
(4096 <untyped> bigint)
MaxLegsPerEntry
untyped bigintMaxLegsPerEntry caps one entry's postings. journal permits 64; this is lower because an entry is parsed from a single string argument and rendered in full, and both of those costs are linear in the leg count.
Value
(16 <untyped> bigint)
MaxCodeLen
untyped bigintMaxCodeLen and MaxNameLen bound an account's identifiers. Both are at or below journal's own limits, so the engine's validation is a backstop here rather than the only check.
Value
(16 <untyped> bigint)
MaxNameLen
untyped bigintMaxCodeLen and MaxNameLen bound an account's identifiers. Both are at or below journal's own limits, so the engine's validation is a backstop here rather than the only check.
Value
(128 <untyped> bigint)
MaxMemoLen
untyped bigintMaxMemoLen bounds an entry's free text. Below journal's MaxMemoLen of 1024 because every memo is a candidate for Render output.
Value
(256 <untyped> bigint)
RenderEntryLimit
untyped bigintRenderEntryLimit caps how many entries one Render call emits. A book may hold MaxEntriesPerBook of them and rendering all of them would make the page cost grow without bound.
Value
(25 <untyped> bigint)
books
*v0.Treebooks maps an owner's address string to that owner's \*journal.Book. The value is a POINTER and is never returned by any exported function — journal consumer obligation 4: a \*Book is a mutable handle, and handing one across a realm boundary would hand out the right to post and reverse.
- OID
- 06569f…d399:4
books details
openedAt
*v0.TreeopenedAt records the height each book was created, for Render.
- OID
- 06569f…d399:7
openedAt details
bookCount
intbookCount is maintained alongside the tree so the index page never has to iterate it.
Value
1
refuseCoins
func()refuseCoins panics if a user call arrives carrying coins. This realm has no withdrawal path, so accepted coins would be stranded permanently. The guard is on IsUserCall rather than IsUser deliberately: OriginSend is only meaningful for a direct MsgCall, and the MsgRun ephemeral can consume the envelope before forwarding control, so IsUser would be the wrong predicate. See p/journal's audit note and security.md.
- OID
- 06569f…d399:10
refuseCoins details
kindFromCode
func(code string) (journal.Kind, bool)kindFromCode maps a code's leading digit to its account kind. The second result is false for any code that does not begin 1-5. This is the whole of the realm's answer to journal obligation 7. See the package doc for what it does and does not buy.
- OID
- 06569f…d399:12
kindFromCode details
KindOf
func(code string) stringKindOf reports the kind a code would be given, without opening anything. A consumer can call this before OpenAccount to check its own numbering.
- OID
- 06569f…d399:13
KindOf details
OpenBook
func()OpenBook creates the caller's book. It panics if the caller already has one. Separating this from OpenAccount is deliberate: creating a book is the call that pays the storage deposit for the owner's record, and a caller should see that cost on its own rather than hidden inside their first account.
- OID
- 06569f…d399:14
OpenBook details
OpenAccount
func(code string, name string)OpenAccount adds an account to the caller's book. The KIND IS DERIVED from the code's leading digit; there is no kind parameter. See the package doc.
- OID
- 06569f…d399:15
OpenAccount details
PostSimple
func(debitCode string, creditCode string, amount int64, memo string) uint64PostSimple posts the two-leg entry that is the overwhelmingly common case: debit one account, credit another, for the same amount. It exists beside PostMulti because the two-leg form cannot be mis-encoded. A caller who wants one debit and one credit should never have to get a leg specification's syntax right.
- OID
- 06569f…d399:16
PostSimple details
PostMulti
func(legs string, memo string) uint64PostMulti posts an entry of up to MaxLegsPerEntry legs, specified as a comma-separated list of colon-separated triples: "1000:D:500,4000:C:300,4100:C:200" Side is D or C, case-insensitive. Amounts are positive integers in the owner's chosen unit. The string form is used because a crossing function cannot usefully take a slice over MsgCall; treasury\_board encodes a list the same way. Debits must equal credits, and journal names which side is short. A leg may name an account another leg already named — journal folds them, and "1000:D:500,1000:C:200,4000:C:300" is a legitimate net +300 to 1000. What is refused is an entry in which EVERY leg names the same account: it balances only by netting to exactly zero, so it is the PostSimple mistake wearing the multi-leg syntax. The narrow rule is deliberate — a blanket "no repeated account" would reject the legitimate fold above.
- OID
- 06569f…d399:17
PostMulti details
Reverse
func(id uint64, memo string) uint64Reverse posts the mirror image of an existing entry in the caller's book, dated now. The original is left exactly as it was: this is a correction, not an edit. An entry may be reversed at most once. The reversal is itself an entry and may itself be reversed once.
- OID
- 06569f…d399:18
Reverse details
CloseThrough
func(through int64)CloseThrough seals the caller's book up to and including a height: no entry may afterwards be dated at or before it. The seal only ever moves forward. Passing a height at or beyond the current one seals the present and makes the book immediately unpostable until the chain advances past it. That is permitted — it is the owner's own book — and it is called out because it is the one way to brick a book without filling it.
- OID
- 06569f…d399:19
CloseThrough details
Rederive
func() (debits int64, credits int64, agrees bool)Rederive runs journal's STRONG invariant check over the caller's own book: it replays every posting of every entry and compares the result against both accumulators. It is a crossing function rather than a getter on purpose. The check is O(all postings ever) and the owner is the party who should pay for it — exposing it as a free read would let anyone make an owner's book expensive to query. IsBalanced is the cheap check and is a free read. Returns the replayed totals and whether they agree.
- OID
- 06569f…d399:20
Rederive details
mustOwnBook
func() *journal.BookmustOwnBook returns the CALLER'S book, and there is no variant that returns anyone else's. Authorization is structural rather than a check: the owner is derived from cur.Previous().Address() and no mutating function takes an owner parameter, so there is no address for a caller to forge. journal obligation 5. "No address to forge" is true of the SIGNATURE and was never true of the realm VALUE, which is the second half of the same Class 2 shape refuseCoins carries above — and the more consequential half, because this is the function that decides who owns the book rather than one that only refuses coins. The guard is a no-op today for the same reason as refuseCoins's: every call site forwards a crossing entrypoint's own first cur. It is kept for the same reason too, and its call-site count is likewise not written down. See AUDIT.md § O.
- OID
- 06569f…d399:21
mustOwnBook details
book
func(owner .uverse.address) (*journal.Book, bool)book returns an owner's book for READ-ONLY use by the getters below. The pointer never leaves this file: every exported getter copies scalars or journal's by-value Account/Entry out of it. Obligation 4. avl.Tree.Get returns ONE value, not (any, bool): it cannot distinguish a nil-valued key from an absent one, which is the same trap journal's \`reversed\` field comment names from the other side. The two-value TYPE ASSERTION is what carries the existence answer here, in one traversal — \`ok\` is false for an absent key and for a present-but-wrong-typed value alike, and the second is impossible because only this file ever Sets. Do not "fix" this into Has-then-Get: that is two traversals for the same answer, and a reader would then owe themselves a proof that nothing can change between them.
- OID
- 06569f…d399:22
book details
mustBook
func(owner .uverse.address) *journal.Book- OID
- 06569f…d399:23
mustBook details
allOneAccount
func(postings []journal.Posting) boolallOneAccount reports whether every posting names the same account. parseLegs has already refused a list shorter than two, so this is never asked of a single-element slice and the loop below always compares.
- OID
- 06569f…d399:24
allOneAccount details
checkMemo
func(memo string)- OID
- 06569f…d399:25
checkMemo details
parseLegs
func(legs string) []journal.PostingparseLegs decodes the "code:side:amount,..." form of PostMulti. Every failure is a panic naming the offending leg by its 1-based position, because a caller who mistyped one triple in a list of eight needs to know which one. A silently-dropped leg would produce an unbalanced entry and the error would surface as "debits do not equal credits", which points at the wrong thing.
- OID
- 06569f…d399:26
parseLegs details
HasBook
func(owner .uverse.address) boolHasBook reports whether an address has opened a book.
- OID
- 06569f…d399:27
HasBook details
Books
func() intBooks is the number of books that exist. It is a count and nothing more: there is deliberately no way to enumerate them or aggregate across them.
- OID
- 06569f…d399:28
Books details
OpenedAt
func(owner .uverse.address) int64OpenedAt is the height an owner's book was created.
- OID
- 06569f…d399:29
OpenedAt details
Balance
func(owner .uverse.address, code string) (int64, bool)Balance returns an account's balance in its NORMAL direction: positive means a debit balance for an asset or expense, and a credit balance for a liability, equity or revenue account. The second result distinguishes "no such account" from "zero".
- OID
- 06569f…d399:30
Balance details
RawBalance
func(owner .uverse.address, code string) (int64, bool)RawBalance returns an account's debits minus credits, without the normal- direction sign convention. Exposed because a consumer reconciling against an external system usually wants the raw figure.
- OID
- 06569f…d399:31
RawBalance details
AccountInfo
func(owner .uverse.address, code string) (name string, kind string, debits int64, credits int64, balance int64)AccountInfo returns an account's full state. journal returns Account BY VALUE, so this hands out a copy and no pointer into stored state.
- OID
- 06569f…d399:32
AccountInfo details
HasAccount
func(owner .uverse.address, code string) boolHasAccount reports whether an owner's chart contains a code.
- OID
- 06569f…d399:33
HasAccount details
Accounts
func(owner .uverse.address) intAccounts is the number of accounts in an owner's chart.
- OID
- 06569f…d399:34
Accounts details
Codes
func(owner .uverse.address, from string, limit int) []stringCodes lists an owner's account codes in ascending code order, beginning at from INCLUSIVE and returning at most limit of them. A limit \<= 0 returns nothing; a limit above the chart cap is clamped to it. Page by passing the last code received back as from, which re-reads that one code. ### Why this exists, and why a counter was not enough {#hdr-Why_this_exists__and_why_a_counter_was_not_enough} Accounts above returns HOW MANY accounts a chart holds, and AccountInfo answers for a code the caller already knows. Neither lets a caller DISCOVER a code. Without this, a trial balance, a balance sheet and an income statement are all unbuildable from outside this realm however many times the chart is interrogated — a consumer could only report on accounts it had independently been told about, which for a chart the OWNER defines is no guarantee at all. ### Why not simply export journal's iterator {#hdr-Why_not_simply_export_journal_s_iterator} journal.Book has IterateAccounts(fn func(Account) bool), and exporting a realm entrypoint that takes fn from the caller would be the shortest code here and a security defect. A caller-supplied callback is the "callback params" class, and journal's own doc records the sharp edge: fn runs under the CALLING REALM'S STORAGE AUTHORITY, because the receiver is stamped with this realm's PkgID and a top-level fn has no declaring realm to anchor it elsewhere. A hostile fn would execute holding r/books' own authority. So the iterator stays internal and this returns VALUES. The closure below is written by this realm, appends to a local slice, and re-enters no mutator — which is exactly the condition journal's doc attaches to it. Codes is a free read and NOT a crossing function, so an owner does not pay for a consumer's paging. The cost ceiling is the chart cap: the underlying iterator has no seek, so \`from\` is honoured by skipping, and one call walks the whole chart however small limit is. A caller paging a 128-account chart 8 codes at a time therefore does 16 full walks, not one. That is a deliberate trade for not touching p/journal, whose Codes-with-seek would have re-opened Gate A and the sabotage sweeps for all three of its importers.
- OID
- 06569f…d399:35
Codes details
EntryCount
func(owner .uverse.address) intEntryCount is the number of entries in an owner's journal.
- OID
- 06569f…d399:36
EntryCount details
EntryInfo
func(owner .uverse.address, id uint64) (at int64, memo string, legs int, reversalOf uint64, total int64)EntryInfo returns one entry's header. Postings are returned separately by EntryLegs, because an entry's leg count is variable and a crossing-function return cannot carry a slice usefully.
- OID
- 06569f…d399:37
EntryInfo details
EntryLegs
func(owner .uverse.address, id uint64) stringEntryLegs returns one entry's postings in the "code:side:amount,..." form PostMulti accepts, so an entry can be read and re-posted without a separate encoding.
- OID
- 06569f…d399:38
EntryLegs details
IsReversed
func(owner .uverse.address, id uint64) boolIsReversed reports whether an entry has already been reversed. An entry may be reversed at most once, so this is also "may this still be reversed".
- OID
- 06569f…d399:39
IsReversed details
Totals
func(owner .uverse.address) (debits int64, credits int64)Totals returns an owner's running debit and credit totals.
- OID
- 06569f…d399:40
Totals details
IsBalanced
func(owner .uverse.address) boolIsBalanced is the CHEAP invariant and this realm's live-verification probe. It compares two independently-maintained accumulators: the per-account totals summed across the chart, against the book's own running totals. They are written by different code paths, so a drift between them is a real defect and this finds it. What it does NOT do is re-read the journal, so a defect that corrupted both accumulators identically would survive it. That is Rederive's job, and Rederive is a crossing function because the owner should pay for it. And the ceiling on both: this proves the book is self-consistent, never that its entries describe real events. See the package doc.
- OID
- 06569f…d399:41
IsBalanced details
Equation
func(owner .uverse.address) (debitNormal int64, creditNormal int64, offsets bool)Equation partitions an owner's chart BY ACCOUNT KIND: the summed raw delta of every debit-normal account (Asset, Expense), the same for every credit-normal one (Liability, Equity, Revenue), and whether the two offset. The two FIGURES are why this exists. They are the balance-sheet and income-statement partition of the chart, and no other accessor on this realm exposes it — Totals sums debits and credits without regard to kind, and AccountInfo answers one code at a time. ### \`offsets\` IS A VACUOUS TRUE ON THIS REALM — do not quote it as a check {#hdr-_offsets__IS_A_VACUOUS_TRUE_ON_THIS_REALM___do_not_quote_it_as_a_check} Read this before using the third result for anything. The kind partition is TOTAL: journal's Kind is 1..5, IsDebitNormal is \`k == Asset || k == Expense\`, so every account lands in exactly one of the two sums and neither can omit one. Therefore debitNormal + creditNormal == sum of RawDelta over ALL accounts == totalDebits - totalCredits and this realm refuses an entry that does not balance, so that difference is always zero. \`offsets\` is consequently TRUE for every book this realm can produce, and it is true for a chart whose accounts are classified nonsensically just as readily as for a correct one. This is the \`HasValidSignature\` shape §7b already names: a predicate that is a constant under current conditions, and so is evidence of nothing. The suite pins the vacuity deliberately rather than asserting true and reading green — a test that cannot fail is the thing that makes this dangerous. What \`offsets\` DOES still distinguish is arithmetic overflow, where journal returns (0, 0, false). So the honest reading is \*\*"the two sums are trustworthy"\*\*, never "the classification is right". A consumer wanting a genuine classification check must compare the kinds against its own expectation, which is the statement consumer's job and not this realm's. Both figures are RAW deltas (debits - credits), not normalised balances, so a debit-normal total is normally positive and a credit-normal total normally negative. A credit-normal account carrying a positive raw delta is a contra account, which is legitimate, and is why neither figure is forced non-negative.
- OID
- 06569f…d399:42
Equation details
ClosedThrough
func(owner .uverse.address) (int64, bool)ClosedThrough returns the height an owner's book is sealed to, and whether it has ever been closed. The second result matters: a book closed through height 0 is not the same as a book that has never been closed.
- OID
- 06569f…d399:43
ClosedThrough details
Capacity
func(owner .uverse.address) (accountsLeft int, entriesLeft int)Capacity returns an owner's remaining headroom, so a consumer can see a full book coming rather than discovering it on a refused entry.
- OID
- 06569f…d399:44
Capacity details
Height
func() int64Height is the chain height this realm dates entries with. Exposed so a caller can predict what CloseThrough will seal.
- OID
- 06569f…d399:45
Height details
Render
func(path string) stringRender serves the index at "" and one owner's book at "\<address>". Every caller-supplied string — account names and entry memos — goes through the ecosystem sanitizer. Free text reaching Render unescaped is the one injection-shaped surface a realm with no custody still has.
- OID
- 06569f…d399:46
Render details
renderIndex
func() string- OID
- 06569f…d399:47
renderIndex details
cell
func(s string) stringcell prepares caller-supplied text for a GFM table cell, truncating it for display first. It is the \`invoices\` helper of the same name, adopted verbatim rather than re-derived, because the two realms face the identical slot. TableCell rather than InlineText, and the SLOT is the reason: these bytes land between two \`|\` delimiters, and an unescaped \`|\` opens a new column and shifts every column to its right. InlineText does not escape the pipe — deliberately, per the sanitizer's own doc, so that TableCell can escape it without double-escaping. Measured on onyx-1 with chain\_id\_bound: true: InlineText("Cash | **forged** | x") -> `Cash | \*\*forged\*\* | x` pipes LIVE TableCell ("Cash | **forged** | x") -> `Cash \| \*\*forged\*\* \| x` escaped This realm shipped InlineText here first and an adversarial audit found it. An owner could forge columns in their own book's chart or journal — and the victim is a THIRD PARTY reading that book, which attacks the one thing this realm exists to provide. The account CODE needs this as much as the name does: a GFM row is split before inline parsing runs, so a \`|\` inside the backtick span at the code column is not protected by the backticks, and kindFromCode constrains only code\[0]. Applied to caller-supplied text only. \`Kind.String()\` and the \`note\` column are realm-constructed from an enum and a uint64, so sanitizing them would be noise rather than slot-matching — unlike \`invoices\`, which passes a bech32 address through this helper precisely because that value IS caller-derived. TRUNCATE BEFORE ESCAPING, and on a RUNE boundary. Escaping first and cutting afterwards can slice a \`\\|\` in half and leave the cell ending in a bare backslash; cutting on a byte boundary can split a multi-byte rune and emit invalid UTF-8. By the time the sanitizer sees the string the damage is upstream of it, so neither is something it is asked to repair.
- OID
- 06569f…d399:48
cell details
renderBook
func(owner .uverse.address) string- OID
- 06569f…d399:49