Why compute one input at a time
BlockX primarily processes many inputs by splitting them into independent function calls. A call can process one source record and make a small number of table reads, on-chain reads, or child function calls. It can also return multiple records; input and output row counts do not have to match. This lets the platform process many inputs in parallel and continue executing other calls while one waits for data access. Work suited to a Function usually has a clear boundary, such as field conversion, event parsing, or object-state calculation. Use a driver script for historical traversal, continuous listening, and task orchestration. Use SQL analytics for aggregation across many records.How a call executes
Console tests and OpenAPI use synchronous entry points that wait for the result within the request. A Notebook can also submit a group of calls as a Task for BlockX to schedule and execute:- The caller describes the inputs and compute function. A task can carry inputs directly or specify which source records should generate calls.
- A Worker receives the task and distributes independent calls to its local pool of Python executors. One Worker manages a given task; different tasks can run on different Workers.
- An executor runs the function. When it accesses BlockDB, a chain node, or another Function, the SDK passes the request back to BlockX, then returns the result to the function so it can continue.
- Once all calls initiated directly by the task (root calls) finish successfully, the task collects their return values and runs the configured result handler. A child function’s return value first goes back to its parent function and contributes to that computation.
Inputs and outputs
Python Functions in the console use_ as the entry point. Parameter configuration defines names, types, and order. Calls match arguments to the entry point by position. See Data types for value formats.
Return values should be representable as JSON: numbers, strings, booleans, lists, dictionaries, or None. Extract the fields you need from SDK objects before returning them; do not return table objects, iterators, or client instances directly.
Use print() for debugging. Return data needed by the caller with return.
Independent calls and code versions
Independent calls within a task have no guaranteed execution order. Do not rely on a previous input having already been processed or use module globals to accumulate results across calls. Have the caller aggregate data that must survive across calls, or write it to a table. A task fixes its function code versions when it starts, including child functions called within the task. Saving new code during execution does not make the task switch versions partway through; subsequent tasks can use the new version. Within a task, BlockX can combine calls with identical code and arguments, reuse return values, and retry some failed calls. Functions should therefore compute from explicit inputs rather than depend on call counts, the current time, or implicit mutable state. For repeatable on-chain computation, pass the block ID as an input and use it for the relevant data reads. Fixing the code version alone does not fix the data being read.Execution environment and access boundaries
Functions run in a restricted Python environment. Supported operations include data computation, platform SDK reads, on-chain queries, and calls to other Functions. Write functions for this environment:- Use supported SDKs to read tables, query chain state, and call other Functions. Do not rely on installing arbitrary packages or directly accessing the operating system or external networks.
- Compute functions defined in a Notebook must also import their own dependencies and receive data through arguments. Avoid relying on the driver script’s globals or closures.
- An SDK interface available in a Notebook is not necessarily available inside a Function. Submit tasks, maintain subscriptions, and manage runs in the driver script.
Call budgets and task deadlines
Console tests, OpenAPI, and task calls use different time controls. Success through one entry point does not guarantee success through another.
Child function calls share the outer time constraints; nesting does not provide an unlimited new budget. Use batch interfaces for reads that can be combined, and split computation by independent input to control each call’s duration.
Retrying a call within a task is different from resubmitting an entire task. BlockX does not automatically rerun a failed task. The caller must decide what to do based on the task result and account for writes that have already occurred.
Computation and result handling
The same Function can serve different callers. What happens to its result depends on how it is called:
A Pipeline compute function typically returns a record, a list of records, or
None. None produces no record for that input. Returned records must match the target table schema and are written by the Pipeline’s configured result handler. A return completes the computation; it does not by itself confirm a successful write to the target table.
Task results are not guaranteed to follow input order. Include a business ID in each returned record when the caller needs to match results to inputs.