blockdb. Use writes and subscriptions in Chaintable Notebooks; Functions can use permitted read interfaces. See the source for the full implementation.
Normal Tables
NormalTable(table_id)
table_id is the full table ID. Returns a Normal Table object.
filter() and select() only collect conditions and columns. The read happens in query(), scan(), or scan_iter(), and the same query object can be run more than once. query() is the online read: it takes sort order and paging and always returns every column. scan() is for reading many rows: it takes no ordering or paging, but select() applies to it.
find() takes a hand-written SQL condition without the WHERE keyword, for conditions the column expressions cannot express yet. Passing sql to scan() runs that statement as-is: the FROM clause is yours to write, with the full table ID in backticks, and the SDK fills in nothing from the table object. This is the BlockDB scan interface, whose supported SQL differs from the analytics engine.
Conditional writes
condition is (column_name, mode). IF_LARGER updates an existing record only when the new value is larger; IF_SMALLER updates only when it is smaller. Missing records are still inserted. The condition column cannot be the primary key, and all rows in a batch share one condition.
Every row in batch_write() needs the same field set. Success does not guarantee an immediately visible write. To check batch-write status, see Inspect asynchronous write jobs.
Block Event and Block State Tables
EventTable(table_id, block_id=None) / StateTable(table_id, block_id=None)
table_id identifies the table; block_id sets the read position. Event tables read by event ID, while state tables read a business ID’s state at that block. Without block_id, reads return each ID’s latest record and do not fall back to the consensus height. When you specify a block, the server checks that the table’s consensus height covers it.
None and [] mean different things for get_block_rows(): [] means the block was processed and holds no records, while None means the chain has no such block, or this table has not processed that height yet.
For per-block write(), the server fills in block fields. batch_write() replaces one block bundle wholesale, and every row must include block_id, block_height, and block_timestamp. A bundle number is not a block height.
Time Tables
TimeTable(table_id, time_at=None)
time_at sets the read time; omit it for the latest value. It accepts RFC3339 strings or Python datetime values. Times without a timezone are interpreted as UTC.
write() uses its timestamp argument, ignoring any row-level time_at. Use batch_write() for multiple timestamps, with each row containing only the three fixed fields.
The server groups time points into buckets and keeps the latest point in each bucket. Resolution changes with data age; see How tables work.
Block subscriptions
Alignment is built into the subscription:
listen() yields a height only once every table in tables has written it and every table in requires has reached consensus at or above it. Subscribe separately to tables that should not be aligned with each other. Both tables and requires accept a single table object, a table ID, or a list of either.
lookback is a number of blocks, counting the chain head itself: 100 starts at the 100th block back from the head, and 0 receives new events only. The server resolves that window against each table’s own chain, rejects a request reaching past the replay window, and historical data still needs a backfill.
readiness defaults to RowsReady, which counts a height as soon as the block’s rows can be read; Committed accepts committed announcements only. Dependency tables are always judged on commit. See Subscribe to block events for a runnable example.
Filter expressions and types
Column and filter() build filters for Pipeline sources. Combine expressions with parenthesized & and |, use in_() and not_in() for set conditions, and chain dedup(*cols) after filter() to deduplicate by column. C is the column shorthand: C.name is Column('name').
Filters run on the source record’s raw values: UINT256 columns compare as decimal strings, so write constants as strings, such as Column('amount') == '1500000'. Ordering comparisons follow string order, not numeric order.
filter() is imported from blockdb.operator because it shadows the builtin filter; a table’s own filter() is a query method and needs no import. Do not pass a filter expression to find(), which expects a SQL condition string.
LogicalType provides type names, and restore_value(logical_type, raw) restores Python values according to metadata. For example, restore_value('UINT256', '1500000') retains a decimal string; use int() for computation. See Data types.