Build OpenHL — from cargo init to a single-validator devnet
Question
Build openhl — the open-source reference Hyperliquid implementation — from cargo init to a running single-validator devnet that produces real blocks via a real Malachite consensus + real Reth execution. The keystone of the openhl track.
Principle (minimum model)
- 16 lessons across 8 modules: Orientation → Foundations → Contract types → EL test double → CL types → Engine integration → Live Reth → Capstone.
- Three sub-systems integrated. Reth (execution engine) + Malachite (Tendermint-style BFT consensus) + the openhl orchestration glue.
- Pinned to openhl SHAs at each stage. Stages 1-3 (workspace + Malachite setup), Stage 4 (contracts), Stage 5 (CL types), Stage 6+ (live Reth integration).
- Outcome. A single-validator devnet that boots, produces blocks via BFT consensus, executes via Reth, and survives restart.
- Prerequisites. openhl Funding + CLOB + Precompiles + perp primer + consensus-engineering Advanced course.
- Production parallel. Hyperliquid HyperBFT + HyperEVM use this exact pattern (different code, same shape).
Worked example + steps
Build OpenHL — from cargo init to a single-validator devnet
This is not a course you read. This is a course you build.
Over the next 16 lessons, you'll start from cargo init on an empty directory and end with a Rust workspace that compiles, passes a real BFT-consensus integration test, and drives a complete block end-to-end through a real Reth + a real Malachite. The codebase you end with is your own — written by you, line by line — and it will look almost exactly like psyto/openhl at the same Stage. That repo is your answer key.
Hyperliquid moved $300B+ of perp volume in 2025 on a fully closed-source stack — HyperBFT consensus, HyperCore matching engine, HyperEVM execution. There is no public Rust reference. OpenHL is what the open-source version looks like, and this course is how you build the Module 1 substrate of it yourself.
Why a CLOB? Hyperliquid's design choice is price-time-priority order book matching because its target market — top-tier crypto-native perps — has enough continuous retail flow for the order book to do real local price discovery. RFQ systems (Variational, Paradigm) win the long tail of assets by quoting just-in-time and hedging on a primary venue; AMMs (GMX-era) optimize cold-start at the cost of tail economics. You're about to build the engine for the slice of the market where CLOB is the right answer. The CLOB course (Course 7) capstone reflects on this tradeoff in depth — for now, the design context is enough to start.
1. What you'll have at the end
A 30-second BFT primer first. BFT consensus runs in rounds of three phases:
- propose — one chosen validator broadcasts a block proposal
- prevote — every validator broadcasts a yes/no/nil vote on the proposal
- precommit — validators lock their vote
A block is decided (= final) once ≥ 2/3 of validators have precommitted it. Within each round the proposer is selected deterministically from the validator set; if the round fails (no quorum), the protocol advances to the next round with a different proposer.
Malachite is the Rust BFT engine that drives this state machine; your job in this course is to wire your application (header construction, EVM execution) into it via a Context trait.
Keep five words in hand — propose, prevote, precommit, decided, proposer — and the rest of the course vocabulary lands cleanly.
By the end of Lesson 15, on your own machine, cargo test first_block_via_engine_actors will produce a passing single-validator BFT consensus round in roughly 0.02 seconds against real Reth as the EVM layer and real Malachite as the BFT layer. The code path is:
your code →
Malachite Driver →
proposer election →
build_payload (your bridge) →
Reth dev-node provider →
header construction →
EthBeaconConsensus validator →
validate_payload →
forkchoice_updated →
decided block
Every line of that path is code you wrote. None of it is magic; all of it is open. By the time you finish, you can:
- Read any line of
psyto/openhlModule 1 code and explain why it's there - Modify any part of the bridge contract and run the tests to see what breaks
- Fork the substrate to start your own Hyperliquid-shape chain —
psyto/openhlbecomes your reference implementation, not your dependency
2. What you won't have at the end
This course covers openhl Build arc Module 1 only — the consensus substrate. It does NOT cover:
- Module 2: the CLOB matching engine
- Module 3: custom EVM precompiles that read CLOB state
- Module 4: funding, oracle, liquidations
- Module 5: protocol-native vault primitive
Those each become their own rethlab course later in the L1 Architect tier. When you finish this course you have the substrate — the BFT-EVM contract, the actor wiring, the live-Reth integration. You do not have a working perp DEX. The perp DEX is Modules 2 through 5 on top of what you build here.
This is honest scoping. A "build your own Hyperliquid" course that promises everything in 16 lessons would be lying to you.
3. How this course works
Every lesson has the same shape:
- Goal. "By the end of this lesson,
cargo test <name>will pass." That test does not pass right now. You will make it pass. - Recap. Where you are in the workspace. What the last lesson built. What the test landscape looks like as of now.
- Plan. What you're about to build, and what design choices the openhl maintainers made when they built it the first time.
- Walk-through. Step-by-step code. Type it, save it, run
cargo checkafter each step. - Test. Run
cargo test <name>. It should pass. If it doesn't, here are the typical mistakes. - Design reflection. One or two load-bearing decisions you just encoded. We come back to these in later lessons.
- Answer key. Git-checkout point in
psyto/openhlwhere the same code lives. Diff your code against that SHA if you want to verify. - Next lesson. What gets built next, and why.
The lesson is the instruction set. The code you write is the artifact. psyto/openhl at the matching SHA is the answer key.
4. Prerequisites
You need:
- Rust 1.95+.
rustup default 1.95.0or newer. - Git. You'll clone
psyto/openhlonce as the answer key. - Basic comfort with cargo workspaces, async/await, and trait impls. If
#[async_trait]andimpl Trait for Foo { ... }are new vocabulary, this course will move too fast. Take the rethlab Fundamentals or Advanced courses first. - An editor that handles Rust well. VS Code + rust-analyzer is fine. Vim/Helix/Emacs are fine.
- About 4 GB free disk space. Reth's compile graph is large.
You do not need:
- Any prior consensus-protocol knowledge (we explain BFT as we go)
- Any prior Reth knowledge (lesson 1 introduces the dep)
- Any prior Malachite knowledge (lesson 1 introduces it too)
- A multi-machine setup (everything runs single-process on your laptop)
5. Setup (do this now)
You will have two directories on your machine:
~/code/my-openhl/— your workspace. You write code here. This is yours.~/code/openhl-reference/— a clone ofpsyto/openhl. You read code here when you want to compare. This is read-only.
# Your workspace
mkdir -p ~/code/my-openhl && cd ~/code/my-openhl
cargo init --lib
# (the package name will default to `my-openhl` from the directory name. Lesson 1
# restructures this into a workspace where the inner crates are `openhl-types`
# / `openhl-consensus` / …, so the root package name disappears at that point.
# We'll also delete the default lib.rs in Lesson 1 — this `cargo init` only exists
# to give git a starting commit to track against.)
# Pin the same Rust toolchain in your own workspace too
echo -e '[toolchain]\nchannel = "1.95.0"' > rust-toolchain.toml
# Answer-key reference
mkdir -p ~/code && cd ~/code
git clone https://github.com/psyto/openhl.git openhl-reference
cd openhl-reference
cargo check # this WILL take a long time the first time — Reth is big
If cargo check in openhl-reference passes, you have the right toolchain. Move on. If it fails, fix toolchain version first — rust-toolchain.toml in that repo pins Rust 1.95.0, and you've just dropped the same pin into my-openhl/, so rustup should auto-install the required toolchain for both.
6. The 16-lesson map
Each row is one lesson. Each lesson ends with a passing cargo test.
| # | Module | What you build | End-of-lesson test |
|---|---|---|---|
| Lesson 0 | Orientation | (this lesson) | setup confirmed |
| Lesson 1 | Foundations | workspace + Reth & Malachite pinned | cargo check --workspace clean |
| Lesson 2 | Contract types | openhl-types primitives (BlockHash, PayloadId, ...) | cargo test -p openhl-types |
| Lesson 3 | Contract trait | ConsensusBridge trait — 4 messages as async fns | cargo check -p openhl-consensus |
| Lesson 4 | EL test double | InMemoryEvmBridge — fake EVM for testing | InMemoryEvmBridge tests pass |
| Lesson 5 | Reth-typed bridge | RethEvmBridge — same contract, real Reth types | RethEvmBridge tests pass |
| Lesson 6 | CL types | OpenHlContext + 10 Context sub-types | context compiles |
| Lesson 7 | Signing | OpenHlSigningProvider — Ed25519 sign/verify | sign/verify round-trip |
| Lesson 8 | Codec | OpenHlCodec — the codec slot the engine demands | codec round-trip |
| Lesson 9 | Node | OpenHlNode + the first start_engine call | engine start/stop smoke |
| Lesson 10 | App loop | run_engine_app — the actor pipeline that ties it all together | first_block_via_engine_actors — Module 1 milestone, BFT round closes |
| Lesson 11 | Live Reth | bootstrap a real Reth dev-node in a test | reth_dev_node_bootstraps |
| Lesson 12 | Live bridge — build path | LiveRethEvmBridge (build_payload side) reads parent from a live provider | live_bridge_builds_on_real_genesis |
| Lesson 13 | Live bridge — validate path | LiveRethEvmBridge (validate_payload side) wires EthBeaconConsensus for real header validation | validate-path tests |
| Lesson 14 | Live bridge — commit path | LiveRethEvmBridge (commit side) wires forkchoice_updated via Reth's in-process Engine API | commit_sends_forkchoice_to_engine |
| Lesson 15 | Capstone | write the end-to-end test that openhl doesn't have yet — run_engine_app + LiveRethEvmBridge together | your own integration test |
Lesson 10 is the major milestone. Finishing Lesson 10, you have BFT consensus producing a block end-to-end through your actor system. Lessons 11–14 swap your stub Reth for real Reth. Lesson 15 lets you exercise the combined whole — something psyto/openhl itself hasn't built yet (at SHA 0844d58), so you'll be ahead of the reference at the end.
7. The answer-key discipline
Every lesson cites a psyto/openhl SHA — the commit where the same code first appeared. After you finish the lesson and your test passes:
cd ~/code/openhl-reference
git checkout <SHA-from-lesson>
# Now compare. Your code in ~/code/my-openhl/ should be ~equivalent.
diff -ru ~/code/my-openhl/crates/types ./crates/types
Your code will differ in trivial ways (whitespace, variable names, comment wording). What matters: types, signatures, control flow are equivalent. If those diverge meaningfully, the lesson didn't land; re-read the design-reflection section and adjust.
8. Setup confirmation — the actual Lesson 0 exercise
Before you move to Lesson 1, run all of this and confirm it all passes:
# 1. Rust version
rustc --version # expect: rustc 1.95.x or later
# 2. Your workspace exists
ls ~/code/my-openhl # expect: Cargo.toml, src/
# 3. Reference exists and compiles
cd ~/code/openhl-reference && cargo check # expect: "Finished" eventually
If all three pass, you are set up correctly. Move to Lesson 1.
💡 Self-check before moving on
In one sentence, can you state the difference between
~/code/my-openhland~/code/openhl-reference?If you can't say in your own words "one is the real workspace I write line by line, the other is the mirror I only consult when I'm stuck," re-read §5 before starting Lesson 1. If you blur this distinction now, you'll eventually write code into
openhl-referenceby mistake and lose the boundary between what you wrote and what you borrowed. Make the boundary muscle memory before moving on.
Summary (3 lines)
- Build openhl = single-validator devnet integrating Reth + Malachite. 16 lessons / 8 modules.
- Pinned to openhl SHAs at each stage; outcome is a running devnet with real BFT + real Reth.
- Prerequisites: openhl other courses + consensus-engineering. Production parallel: Hyperliquid HyperBFT + HyperEVM.