Skip to main content

Overview

After consensus produces a CommittedBatch, every validator independently processes it through the same deterministic execution pipeline. No further communication is needed - identical inputs produce identical outputs across every validator.

Executor Pipeline

The executor processes each committed batch through the following stages:

1. Receive TickProcess

The consensus output is packaged as a TickProcess containing:
  • The committed transactions
  • The round number (slot)
  • The batch timestamp (used as the shuffle seed)

2. Shuffle and Queue Separation

The SlotQueue receives the transactions and:
  1. Reseeds the Fisher-Yates shuffler with the batch timestamp
  2. Shuffles all transactions in the batch
  3. Separates transactions into priority queues:
  • Config/data actions (oracle updates, settings changes)
  • Liquidation orders (from the risk engine)
  • Cancels (cancel-one and cancel-all)
  • Post-only (ALO) maker orders
  • Regular orders (market, limit GTC, IOC)

3. Execution Order

Actions are dequeued and executed in strict priority order:
  1. Config and data updates
  2. Liquidations (if any accounts breached maintenance margin)
  3. Cancels
  4. Post-only maker orders
  5. Regular orders
Within each queue, execution follows the shuffled order from step 2.

4. Pre-Flight Margin Check

Before any order touches the book, the executor runs a precheck_order validation:
  • Verifies the account has sufficient available equity for the new position
  • Checks leverage limits
  • Validates order parameters (size, price, side)
  • For reduce-only orders, verifies the order would actually reduce the position
Orders that fail pre-flight checks are rejected with a specific reason code (e.g., rejectedRiskLimit, rejectedInvalid).

5. Book Matching

Orders that pass pre-flight are submitted to the matching engine, which operates as a standard central limit order book (CLOB) with price-time priority:
  • Aggressive orders (market, or limit orders that cross the spread) are matched immediately against resting liquidity at the best available prices
  • Passive orders (limit orders that don’t cross) are placed on the book and wait for a counterparty
  • Post-only orders that would cross the spread are rejected (rejectedCrossing) instead of filling
During matching, the risk engine is called back at each fill to verify that the resulting position remains within margin limits. If a fill would cause a margin breach, the remainder of the order is cancelled (cancelledRiskLimit).

6. State Updates

After each fill, the executor updates:
  • Position sizes and entry prices
  • Account collateral and PnL
  • Order status (working, filled, partially filled)
  • Book state (remove filled levels, update partial fills)
All updates are applied atomically per fill event.

Deterministic Execution

The entire pipeline - shuffle, queue separation, margin checks, book matching, state updates - is deterministic. Given the same CommittedBatch, every validator produces:
  • The same fills at the same prices
  • The same order statuses
  • The same position and margin state
  • The same book state
Any validator that produces a different output is immediately detectable by comparing state hashes. This property is what makes BULK’s execution verifiable without requiring re-execution by an observer - you only need to compare the output digest.

Self-Trade Prevention

When an order would match against another order from the same account, BULK’s Self-Trade Prevention mechanism activates. The resting order is cancelled rather than allowing a self-trade, protecting market makers who operate on both sides of the book.