Order Book
The GX Core order book is a high-performance, deterministic matching engine that processes orders using price-time priority. It is implemented in native Rust using BTreeMap data structures for sorted price levels and achieves sub-microsecond match latency.
Design
Price-Time Priority
The order book follows strict price-time priority (also called FIFO matching):
- Price priority — The best-priced order is always matched first. For bids, the highest price has priority. For asks, the lowest price has priority.
- Time priority — At the same price level, the order that arrived first is matched first.
This is the same matching model used by all major stock exchanges and centralized crypto exchanges (Binance, CME, NYSE).
Data Structure
Each market maintains two sides of the order book:
BTC-USD Order Book:
ASKS (sell orders, sorted ascending by price):
$67,420: [Order A: 1.5 BTC, Order B: 0.8 BTC]
$67,410: [Order C: 2.0 BTC] <-- Best Ask
BIDS (buy orders, sorted descending by price):
$67,400: [Order D: 3.0 BTC] <-- Best Bid
$67,390: [Order E: 1.0 BTC, Order F: 2.5 BTC]Internally, each side is a BTreeMap<Price, VecDeque<Order>>:
BTreeMapprovides O(log n) insertion and lookup by price levelVecDequeat each price level provides O(1) FIFO ordering- The spread is
best_ask - best_bid($67,410 - $67,400 = $10 in this example)
Semantic Ordering
GX Core uses semantic ordering within blocks to ensure fair and safe execution:
| Priority | Operation | Rationale |
|---|---|---|
| 1 | Liquidations | Protocol solvency — must execute before new risk is added |
| 2 | Cancellations | Remove stale orders before they can match |
| 3 | Reduce-only orders | Risk reduction takes priority over new exposure |
| 4 | New orders | Standard matching flow |
Within each priority class, orders are processed in the sequence they were received by the validator (FIFO).
Order Types
| Type | Behavior |
|---|---|
| Limit (GTC) | Rests on the book at the specified price until filled or cancelled |
| Market | Matches immediately against the best available price; any unfilled remainder is cancelled |
| IOC (Immediate-or-Cancel) | Matches as much as possible immediately; unfilled remainder is cancelled |
| FOK (Fill-or-Kill) | Must fill entirely at the specified price or better, or is cancelled entirely |
| Post Only | Guaranteed to add liquidity; if the order would cross the spread and take, it is rejected |
| Reduce Only | Can only reduce an existing position; rejected if it would increase exposure |
Integer Arithmetic
All price and size calculations use integer arithmetic to eliminate floating-point precision errors. This is critical for deterministic consensus — every validator must compute identical results.
| Field | Representation | Example |
|---|---|---|
| Price | Fixed-point integer, 6 decimals | $67,400.50 = 67400500000 |
| Size | Fixed-point integer, market-specific | 1.5 BTC = 1500000000 (9 decimals) |
| Notional | price * size / precision_factor | Integer multiplication and division |
| PnL | Computed in integer space, rounded at settlement | No floating-point at any stage |
This approach mirrors how traditional financial exchanges handle arithmetic. Floating-point is never used in the matching or settlement path.
Matching Algorithm
When a new order arrives, the matching engine executes the following:
fn match_order(incoming: Order, book: &mut OrderBook) -> Vec<Fill> {
let mut fills = vec![];
loop {
// Get the best opposing price level
let best = match incoming.side {
Buy => book.asks.first(), // lowest ask
Sell => book.bids.last(), // highest bid
};
// Check if the incoming order can match
if !can_match(incoming.price, best.price, incoming.side) {
break; // No match possible
}
// Match against orders at this price level (FIFO)
let resting = best.orders.front();
let fill_size = min(incoming.remaining, resting.remaining);
fills.push(Fill {
price: resting.price, // Resting order's price
size: fill_size,
maker: resting.address,
taker: incoming.address,
});
// Update remaining sizes
incoming.remaining -= fill_size;
resting.remaining -= fill_size;
if resting.remaining == 0 {
best.orders.pop_front(); // Remove fully filled order
}
if incoming.remaining == 0 {
break; // Incoming order fully filled
}
}
// If incoming has remainder and is GTC, add to book
if incoming.remaining > 0 && incoming.time_in_force == GTC {
book.insert(incoming);
}
fills
}Performance
| Operation | Latency | Throughput |
|---|---|---|
| Single match | Sub-microsecond | Millions of operations/sec |
| Resting order insertion | Sub-microsecond | Millions of operations/sec |
| Cancel | Sub-microsecond | Millions of operations/sec |
| Match at 100 price levels | 7.9 us | — |
| Match at 1,000 price levels | 43.6 us | — |
| Match at 10,000 price levels | 662 us | — |
Performance degrades gracefully with order book depth. Even at 10,000 price levels (an extremely deep book), match latency remains sub-millisecond.
Determinism
The order book is fully deterministic: given the same initial state and the same sequence of operations, every validator produces an identical final state. This is enforced by:
- Integer arithmetic — No floating-point rounding variance
- Deterministic sorting —
BTreeMapwith a consistent comparator - State hashing — After each block, a Merkle hash of the order book state is computed and included in the block header
- Consensus verification — Validators compare state hashes; divergent validators are flagged