state.h
Architecture
Asynchronous Execution Model
This module implements an asynchronous state machine for proof generation and verification. The state object (c4_state_t) is typically part of a context struct (prover_ctx_t or verify_ctx_t) and manages external data requests that cannot be fulfilled synchronously.
Execution Flow
The main execution function (e.g., c4_prover_execute) is called repeatedly in a loop until it returns either C4_SUCCESS or C4_ERROR. When external data is needed, the function:
Creates a
data_request_tand adds it to the stateReturns
C4_PENDINGto signal that data is requiredThe host system fetches the required data
The host system calls the execution function again
The function resumes and processes the now-available data
This design allows the host system to use native async technologies (promises, async/await, futures, etc.) in the language bindings while keeping the C core synchronous and portable.
Request Lifecycle

Host System Implementation
The host system is responsible for executing data requests. When C4_PENDING is returned, the host system should iterate through all pending requests using c4_state_get_pending_request() and execute them according to the following rules:
Request Execution
For each data_request_t, the host system must:
Select Node: The host system maintains a list of nodes (max 16) for each
data_request_type_tBeacon API nodes for
C4_DATA_TYPE_BEACON_APIEthereum RPC nodes for
C4_DATA_TYPE_ETH_RPCCheckpointz servers for
C4_DATA_TYPE_CHECKPOINTZetc.
Apply Filters:
Skip nodes where
node_exclude_mask & (1 << node_index)is setPrefer nodes matching
preferred_client_type(if set, 0 = any client)
Build Request:
Use
methodfield for HTTP method (C4_DATA_METHOD_GET,POST, etc.)Use
urlfield for the endpoint path (if set)Use
payloadfor POST body (if set, typically JSON-RPC forC4_DATA_TYPE_ETH_RPC)Set Content-Type and Accept headers based on
encoding:C4_DATA_ENCODING_JSON: application/jsonC4_DATA_ENCODING_SSZ: application/octet-stream
Execute Request:
Try the selected node
On failure: try next available node (respecting exclude mask)
On success: set
responseandresponse_node_indexIf all nodes fail: set
error
Caching:
If
ttlis set (> 0), the response may be cached for the specified durationCache key should include request type, URL, and payload
Set Result:
Success: Allocate memory for
response.data, copy data, setresponse.lenandresponse_node_indexFailure: Allocate memory for
errorstring describing the failureImportant: Both
response.dataanderrorwill be freed byc4_state_free()- usemalloc/strdup
Example Implementation
See bindings/emscripten/src/index.ts function handle_request() for a complete TypeScript implementation.
Best Practices
To minimize the number of execution cycles, developers should:
Collect all required data requests as early as possible in the execution
Use
TRY_ADD_ASYNCto queue multiple requests before returningC4_PENDINGThe host system should fetch all pending requests in parallel when possible
Cache responses according to
ttlto avoid redundant network requestsImplement smart node selection (e.g., prefer faster nodes, track reliability)
Example Usage
Macros for Async Control Flow
The TRY_ASYNC family of macros simplifies error handling and control flow:
TRY_ASYNC(fn): Execute function, return immediately if not C4_SUCCESSTRY_ADD_ASYNC(status, fn): Queue multiple requests, only fail on C4_ERRORTRY_2_ASYNC(fn1, fn2): Execute two functions in parallelTRY_ASYNC_FINAL(fn, cleanup): Always run cleanup regardless of resultTRY_ASYNC_CATCH(fn, cleanup): Run cleanup only on failure
These macros handle the repetitive pattern of checking status codes and allow the developer to focus on the business logic.
data_request_type_t
Defines the type of data source for a request.
data_request_encoding_t
Defines the encoding format for request/response data.
data_request_method_t
HTTP methods for data requests.
c4_status_t
Status codes for asynchronous operations.
data_request_t
Represents a single asynchronous data request in the state machine.
This structure encapsulates all information needed to make, track, and retry external data requests. Requests can be to various data sources (Beacon API, Eth RPC, etc.) and support retry logic with node exclusion.
c4_state_t
Global state container for asynchronous operations.
Contains all pending data requests and accumulated error messages. Used by the async state machine to track operations that require external data.
c4_state_free
Frees all resources associated with a state object.
Releases all memory allocated for data requests, URLs, payloads, responses, and error messages. Safe to call with partially initialized state objects.
Parameters
state: Pointer to the state object to free
c4_state_get_data_request_by_id
Finds a data request by its unique identifier.
Performs a linear search through the request list to find a request with the matching 32-byte ID.
Parameters
state: Pointer to the state objectid: 32-byte identifier to search for
Returns
Pointer to the matching request, or NULL if not found
c4_state_get_data_request_by_url
Finds a data request by its URL.
Performs a linear search through the request list to find a request with the matching URL string.
Parameters
state: Pointer to the state objecturl: URL string to search for
Returns
Pointer to the matching request, or NULL if not found
c4_state_is_pending
Checks if a request is still pending.
A request is considered pending if it has no error and no response data yet.
Parameters
req: Pointer to the request to check
Returns
true if pending, false if completed or failed
c4_state_add_request
Adds a new data request to the state.
Automatically generates a unique ID for the request if not already set (hash of payload or URL). Adds the request to the front of the linked list.
Parameters
state: Pointer to the state objectdata_request: Pointer to the request to add (ownership transfers to state)
c4_state_get_pending_request
Gets the first pending request from the state.
Searches through the request list and returns the first request that is still pending (has no error and no response).
Parameters
state: Pointer to the state object
Returns
Pointer to the first pending request, or NULL if none pending
c4_state_add_error
Adds an error message to the state.
Appends the error message to any existing error messages, separated by newlines. Handles NULL error parameter gracefully by using a generic message.
Parameters
state: Pointer to the state objecterror: Error message to add (can be NULL)
Returns
Always returns C4_ERROR
c4_req_mockname
Generates a mock filename for a request (test mode only).
Creates a sanitized filename based on the request URL or payload, suitable for storing mock responses. Characters that are invalid in filenames are replaced with underscores.
Note: Only available when compiled with TEST flag.
Parameters
req: Pointer to the data request
Returns
Allocated string with the mock filename (caller must free)
Last updated