Skip to main content
BlockX is a function execution layer. It stores no data and orchestrates no jobs: BlockDB handles table storage, access, and subscriptions; the Client generates tasks, orchestrates DAGs, and triggers them; BlockX only does the computation in the middle. It receives a task, expands the trigger data into a set of mutually independent function calls, runs them in parallel in the Python Executor process pool on the Worker’s own machine, and then hands all the return values to the Writer Plugin in one shot to persist or return. The core computation model is single-row state computation from onchain table -> onchain table: each row in one block of the source table goes through one lightweight function on its own and yields one row of the target table.

Function execution layer

In the whole data pipeline, BlockX takes on only the “compute” step:
  • Upstream: BlockDB block tables, normal tables, or parquet partitions on S3 split by bundle provide the input rows; the Client (a notebook, the blockx-py Pipeline, or a scheduling system) decides when to compute what for which block.
  • BlockX: receives the task, scans or receives the trigger data, turns each row into one function call, executes the calls in parallel in the Executor pool, and aggregates the return values.
  • Downstream: the Writer Plugin writes the aggregated results back to a BlockDB block table or normal table, or returns them to the Client as is.
User-written functions are read-only. A function can read BlockDB through the SDK, call chain node RPC, and call other functions, but all writes are done in one place by the Writer Plugin the task declares, after the functions finish executing.

The three phases of a task

Only flat results pass between the three phases: the Builder does not know what the function will return, and the Writer Plugin does not care which call a given row came from. See Task and call for details.

Three kinds of input and three kinds of result handling

A task declares “what to compute” and “how to handle the result” with two (type, config) pairs. type is a name in the Worker’s registry; config is JSON that only the corresponding implementation parses. The Call Builder decides where the input comes from: The Writer Plugin decides where the result goes: Each task has exactly one Call Builder and at most one Writer Plugin. See Call Builder and Writer Plugin for details.

Two invocation entry points

Both share the same Python Executor, Function Code View, and read-only IO subsystem. The Sync Invoker does not go through the Coordinator, and has no slot and no Writer Plugin.

Two clusters

BlockX deploys the same code as two clusters with different process profiles: blockx-py picks the cluster automatically based on the task’s config and handler; tasks that need results returned (ReturnValueHandler) always go to the block cluster. See Runtime for details.

Summary

  • BlockX is a function execution layer: it stores no data and does no orchestration; it only expands a task into calls, computes them in parallel, and writes back in one place.
  • A task goes through three phases, Builder → Calls → Plugin, and only the flat call list and outputs pass between phases.
  • Three kinds of Call Builder decide where input comes from, and three kinds of Writer Plugin decide where results go; the user function itself is read-only.
  • Asynchronous tasks and synchronous Invoke are two entry points; block and bundle are two clusters distinguished by profile.
Continue reading:
  • Task and call: task fields, states, results, and invariants.
  • Function code: entry point conventions, arguments and return values, available SDKs, and static auditing.
  • Call Builder and Writer Plugin: the config shapes of the three kinds of input and three kinds of result handling.
  • Runtime: Coordinator, Worker, slot, Executor, and the two clusters.
  • Architecture overview: component diagram, core constraints, and the reading order for contributors.