FABRKNT
Step 2. CLOB — マッチングエンジンの追加とステートマシンの統合
Orientation
レッスン 1 / 13·CONTENT15 分50 XP
コース
Step 2. CLOB — マッチングエンジンの追加とステートマシンの統合
レッスンの役割
CONTENT
順序
1 / 13

レッスン0 — OpenHL CLOB を作る(Reth 基盤の上に matching engine を載せる)

問い

前コース(Consensus)は実 Reth EVM を通じて 0.02 秒で block を確定する chain で終わった。だが確定していたのは 空の block — トランザクションもマッチングも価格発見もない。どうやって約定(取引)を生成し、それを committed block に流すか?

注: OpenHL コースのコードブロックは原則として手元で実行可能な形で示す。ただし <file> などのプレースホルダや答え合わせ用コマンドは、各レッスンの指示に従って置換してから実行すること。

原理(最小モデル)

  • CLOB(Central Limit Order Book)= price-time-priority の matching engine。 価格優先・時間優先で板を管理し、「HYPE を 25 USD で 10 buy」と「25 USD で 5 sell」を実際の約定(fill)に変換する。Hyperliquid の核となる仕組み。
  • pure state machine — I/O なし、完全に deterministic。 マイクロ秒で走り、同じ入力列から必ず同じ約定列を生む。これが consensus に載せられる前提。
  • 約定は bridge 経由で payload に流す。 matching engine が生成した fill を LiveRethEvmBridge::build_payload が拾い、consensus が commit する block に運ぶ。
  • スコープは 2 段(openhl の Stage 名)。 Stage 8a = CLOB 本体(pure state machine)、Stage 8d = それを bridge に接続し payload へ約定を流す段。本コースはこの 2 つを再現する。

具体例

maker: HYPE 25 USD で 5 sell(先に book に置かれた resting order)
taker: HYPE 25 USD で 10 buy(その流動性を消費する incoming order)
   ↓ matching engine
Fill { price: 25, qty: 5 }(taker の残り 5 は book に resting)

ゴールは cargo test clob_fills_flow_into_payload — 実際の約定が matching engine → build_payload → payload に流れ、consensus が commit する。

失敗例(誤解)

psyto/openhl を clone してそのコードベースで進めればいい」は誤り。本コースは build-along — matching engine を my-openhl/ でゼロから書き、reference に diff する。reference から start すると「答え合わせを写経する」モードに逆戻りし、摩擦から得られる学び(逆順 bid / FIFO / cancel-then-cleanup invariant)を取りこぼす。


ここまでで「CLOB は何で、なぜ pure state machine か」は着地した。ここから先はスコープ・前提・13レッスンのロードマップに入る。L1 以降は実際に Rust を書く。

🛑 セルフチェック。 次に進む前に 1 文で言えるか:本コースが Consensus になかった何を追加するのか? 答えに「約定を生成する matching engine、その約定が committed block に流れる」が入らなければ、下の「終了時に手にするもの」を読み直す。

終了時に手にするもの

新規 crates/clob/ crate:

  • マイクロ秒で走る price-time-priority matching engine(pure state machine、I/O なし、deterministic)
  • Book + Order + Fill 型(CEX が「order book」と呼ぶものに対応)
  • テスト 12 個合格: hand-trace シナリオ 9 個(空 book / FIFO 優先 / market order の流動性枯渇 / partial 約定 / cancel / マッチ後の no-crossed-book)+ proptest invariant 3 個(256 ケース × 3 = 768 ランダムシナリオ — quantity conservation / no-crossed-book always / determinism = replayability)

加えて crates/evm/ に integration test clob_fills_flow_into_payload — 実 Reth node を bootstrap し、bridge の CLOB に maker bid + crossing taker sell を submit、結果の約定が次の build_payload 出力に現れることを assert、かつ 過去の payload に遡って約定が attach されない(drain は forward-only)ことを assert。

終了時にも手にしないもの(意図的な scope cut)

  • custom EVM precompile(CLOB state を read/write、= Step 3)
  • funding rate state machine(= Step 4)
  • 約定を EVM-executable トランザクションとして encode(openhl の Stage 9 より先)
  • liquidation / mark-vs-index pricing / レバレッジ上限

約定は生成され committed block に運ばれるが、まだ parallel list — スマートコントラクトから読める Ethereum トランザクションではない。それを足すのが Step 3。

前提

  • Consensus(Step 1)完了crates/evm/src/live_node.rsLiveRethEvmBridge<P>provider / chain_spec / validator / optional engine_handle)が存在すること。
  • Rust 1.95+(rust-toolchain.toml で pin 済み)。
  • BTreeMap / VecDeque / Reverse<T> / proptest に慣れていること(「最高値から辿る reverse-ordering trick」が初耳なら std::collections::BTreeMap の doc を一読)。

不要: matching-engine 経験 / order book 読解スキル / multi-validator(引き続き single-validator)。

セットアップ確認(今やる)

cd ~/code/openhl-reference
git fetch origin
git log --oneline | grep -E "(55a9dff|428cc26)"   # Stage 8a / 8d の SHA が見えるはず

cd ~/code/my-openhl
cargo test -p openhl-evm --release 2>&1 | tail -10
# 期待: reth_dev_node_bootstraps / live_bridge_builds_on_real_genesis /
#       commit_sends_forkchoice_to_engine_when_handle_installed が pass

これらが pass すれば start point として正しい。pass しなければ先に Consensus(Step 1)を完了させる。

13レッスンのロードマップ

#build するもの終了時テスト
0Orientation(本レッスン)セットアップ確認
1CLOB newtype(AccountId/OrderId/Price/Qty/Side/OrderTypecargo check -p openhl-clob
2Order / Fill / FillResult型がコンパイル
3Book struct + Reverse<Price> trickcargo check -p openhl-clob
4submit_order — Limit order、in-book matchingresting order とマッチ
5submit_order — Market order + crossing + partialエッジケース挙動
6cancel + 空 level の cleanupcancel-by-id が動く
7hand-trace unit test 9 個9 個 pass
8proptest invariant 3 個768 ランダムシナリオ pass
9LiveRethEvmBridgeclob + pending_fills + submit_orderbridge がコンパイル
10build_payload が pending fill を drain約定が payload に現れる
11clob_fills_flow_into_payload integration testフルパイプライン pass
12Capstone(振り返り)

レッスン11 がマイルストーン — matching engine の約定が BFT engine を通って実 block に流れる。レッスン12 で「まだ何が足りないか(約定がスマートコントラクトから読めない = Step 3)」を明示する。

答え合わせの規律

各レッスン(1〜11)は SHA 55a9dff(Stage 8a)または 428cc26(Stage 8d)を cite する。テストが pass した後:

cd ~/code/openhl-reference
git checkout 55a9dff    # レッスン 9〜11 では 428cc26
diff -u ~/code/my-openhl/crates/clob/src/types.rs ./crates/clob/src/types.rs

本質(型・制御フロー)が一致していればよい。空白・命名は違って OK。

合格基準

  • cargo test clob_fills_flow_into_payload を通せる(コース完走時)。
  • CLOB の price-time-priority を説明できる。
  • maker / taker と、約定を buffer する matching engine と同期 emit する engine のトレードオフを推論できる。

まとめ(3行)

  • CLOB は price-time-priority の pure state machine — deterministic だから consensus に載せられる。
  • 約定(fill)を生成し、bridge 経由で build_payload から committed block に流す。
  • 本コースは Stage 8a(CLOB 本体)+ 8d(bridge 接続)。約定の EVM 実行可能化(precompile)は Step 3。