I hope everyone’s had a great time with the hackathon and am really looking forward to seeing what fellow builders have come up with. Today, I’m sharing a brand new project that I’m likely to be throwing myself into over the coming months.
Myelin in one paragraph
Myelin is an off-chain Cell session runtime initially inspired by xuejie’s earlier post. It runs high-throughput, finite state transitions outside CKB and keeps every transition projectable back to a CKB-style transaction. It schedules independent chunks in parallel, wraps a batch of verified chunks into a finalised session block, and emits a self-contained court bundle (a packaged evidence file a future on-chain verifier can consume to adjudicate a single disputed chunk) for any disputed chunk. The idea is that a future on-chain verifier can adjudicate a single chunk without re-running the whole session. The closed-validator fast path ships today as a prototype; the permissionless path remains an item in the roadmap.
Myelin is not a new L1, and neither a finished permissionless L2, but rather e a protocol seed: the execution, state, evidence, and session-finality pieces needed to test the shape of an off-chain Cell ledger.
The problem
CKB-VM is powerful enough to run real, complex logic. A single chunk of a real-time game, a metering window, or a settlement batch can execute inside the VM and verify correctly. What it cannot do on its own, is to answer the questions that turn “this chunk executed correctly” into “this session is a finalised, contestable state transition with a path back to L1.” A layer above the chunk has to handle five things:
- Scheduling. How do many chunks in a batch execute together, and which
can run in parallel? - Finality. When is a batch committed, and by whom?
- Projection. Can each chunk be mapped to a CKB-style transaction?
- Dispute. If a chunk is wrong, what does a court re-run, and what is
the input shape? - Data availability. Where does the evidence live?
I built Myelin to prototype parts of that layer.
The isomorphism principle: why I leave the VM alone
CKB uses the Cell Model, and Myelin follows it to the letter. A transaction consumes live Cells and creates new Cells. State changes happen through Cell replacement. Cells carry data, a lock script, and an optional type script. Scripts run in CKB-VM. Myelin does not hide session state inside an account-style contract, and it does not modify CKB-VM. The VM is a fixed oracle.
Myelin runs the same CKB-VM, with the same RISC-V ISA, the same script semantics, and the same Molecule transaction serialisationas L1. That means a Myelin CellTx is structurally projectable into a CKB transaction. The projection layer asks a simple question: can this CellTx be serialised with the CKB Molecule transaction layout, and do its script and witness assumptions match a CKB-strict profile? When the answer is yes, the chunk is ckb_compatible. A future on-chain court verifier can re-run the same bytes through the same VM and reach the same verdict.
Therefore every host-side optimisation I add (a cache, a parallel scheduler, a different finality engine) is transparent. It changes how Myelin reaches an answer but does not change what the answer is. The VM result is the ground truth both off-chain and on-chain.
If I changed the VM (added an opcode, relaxed a cycle limit, swapped the ISA), that isomorphism would break. A chunk that verifies under a modified VM might fail under CKB’s, and the projection path would be worthless.
Because it follows the Cell Model directly, a Myelin session can always report five things about any transition:
- what Cells were consumed or created,
- which lock and type-script-like rules were checked,
- which VM and profile assumptions were used,
- whether the transition can be projected into a CKB-style context,
- and which evidence would be relevant during a dispute.
How Myelin works
The pipeline below runs from source to evidence. CellScript is the DSL that compiles Cell-model programs (actions, resources, flows) into typed-cell metadata and a RISC-V VM artefact. The CellDAG is Myelin’s dependency scheduler: it figures out which CellTxs in a batch can run in parallel and which must be ordered.
Every box is a real crate in the workspace: cellscript, myelin-exec, myelin-state, myelin-mempool, myelin-consensus, myelin-cli. Support crates live under core-utils/, crypto/, and math/.
What is in the repository
| Path | Role |
|---|---|
exec/ |
Cell transactions, script verification, VM and syscall glue, scheduler witnesses, and CellDAG conflict scheduling. |
state/ |
Live Cell state roots (incremental MuHash, a multiplicative hash accumulator that lets the root update in O(1) per cell change) and data-availability proof primitives. |
mempool/ |
Cell transaction pool and deterministic conflict scoring. |
consensus/ |
Static closed-committee and Tendermint-shaped weighted-precommit certificate verification with deterministic fixture signatures; not a complete Tendermint state machine. |
cli/ |
Command-line fixtures and report generation for CellTx, session, DA, settlement, and submission flows. |
cellscript/ |
CellScript compiler, vendored in sync with upstream (0.21.1). The typed-cell model lives in exec/, separate from the compiler. |
docs/ and MYELIN_*.md |
Architecture notes, evidence reports, positioning, and rehearsal records. |
website/ |
Marketing and docs landing site (Astro). |
What I built
1. The typed-cell model
A Cell in CKB carries capacity, data, a lock script, and an optional type script. The type script gives a Cell its kind: token cell, order cell, game-state cell. CKB verifies type scripts on chain, but the runtime has no structured way to reason about typed-cell identity, conflict dimensions, ownership, or mutability before the VM runs. I added that layer.
The typed-cell model is a runtime-side type system. For each type script, a TypedCellDecl declares its ownership (one-of-a-kind vs fungible), its mutability, and its conflict key (ConflictKeySpec: by cell id, by field, by composite key, or none). The conflict key is the crucial bit. It lets the scheduler decide whether two transactions touch the same state and must be ordered, or touch disjoint state and can run in parallel.
The typed-cell runtime types (TypedCellDecl, ConflictKeySpec, TypedCellStore, CellScriptSchedulerWitness, CellScriptSchedulerAccessWitness, compute_conflict_hash) all live in Myelin’s own exec crate (exec/src/celltx/types.rs). A witness bridge decodes the compiler’s generic witness at runtime and recomputes Myelin’s stronger conflict_hash and typed_data_hash from the transaction’s concrete cells. The compiler cannot emit these directly because it does not know the deployed type-script identity at compile time. Only the runtime does.
2. Inter-transaction conflict scheduling (CellDAG)
Given typed cells with conflict keys, the CellDAG builds a read/write dependency graph over the transactions in a session batch and schedules independent transactions across topological layers, parallelised with Rayon (a Rust data-parallelism library). Two transactions that read the same conflict domain stay in the same layer (parallel). A read/write or write/write pair on the same domain creates a dependency edge (serial).
The conflict edges come from the typed-cell model, so the scheduler understands semantic conflicts (two transactions touching the same logical resource), which is a good deal more useful than only seeing structural OutPoint-level chaining.
3. Closed-validator finality with dual engines
A batch of verified chunks is wrapped into a MyelinBlock and checked under a pluggable committee. Today that is a static closed committee plus a stripped, Tendermint-shaped weighted-precommit certificate verifier. Both use deterministic BLAKE3-derived fixture signatures.
(This is session-finality scaffolding for deterministic demos, not a complete BFT protocol or a permissionless consensus claim.)
4. CKB-style projection and the court bundle
For each chunk, Myelin emits a projection report: is this chunk projectable into a CKB-style transaction? For a disputed chunk, it emits a self-contained court bundle that packages the witness layout, the molecule transaction, the chunk data, and the committee finality evidence. The bundle passes 22 verification checks today. This is the input shape a future on-chain court verifier would consume. The court script itself is not deployed yet, but the bundle is real, the shape is fixed, and the path is documented end to end.
5. Data-availability evidence path
Myelin emits a DA manifest over sealed segments (Merkle-rooted, parallel leaf hashing), with a replicated-committee availability layer and a hook for an external DA receipt. The DA path is local-only today (no external provider), but the commitment shape is there.
Optimisations: what each one buys, and why none of them touch the VM
Every optimisation below lives on the host side. The VM is never modified. This is the isomorphism contract I described above, and each item states the effect it achieves.
Already shipping
| Optimisation | What it achieves | Why it preserves isomorphism |
|---|---|---|
CellDAG parallel inter-tx verification (exec/src/scheduler/executor.rs) |
Independent transactions in a batch verify concurrently across Rayon topological layers. A session of N independent chunks finishes in O(depth) sequential verification rounds instead of O(N). |
Scheduling changes when each transaction is verified, never whether it passes. Every transaction still runs through the unmodified CKB-VM verifier. The parallel layers just run disjoint transactions at the same time, and the union of results is identical to serial. |
Within-tx script-group parallelism (exec/src/vm/verifier.rs) |
The lock and type script groups within one transaction are verified in parallel (script_groups.par_iter()). A transaction with K script groups finishes in O(1) rounds instead of O(K). |
Same VM, same scripts, same cycle accounting. Only the order of independent group evaluations changes. Cycle totals are summed deterministically. |
Incremental MuHash state root (state/src/cell_tree.rs) |
Each cell insert or remove updates the session state root in O(1) (a single 384-byte modular operation) instead of re-hashing the entire cell set. A session that commits thousands of cells pays no O(n) root cost per commit. |
MuHash is an associative, order-independent accumulator. The root is identical whether computed incrementally or from scratch. The VM never sees the root computation; it is host-side accounting. |
Parallel DA Merkle leaf hashing (state/src/store/proof.rs) |
Sealing a 1 GB DA segment hashes its leaves in parallel (par_chunks(2) per Merkle level) instead of serially. Seal latency drops near-linearly with core count. |
Merkle hashing is a pure, deterministic function. Parallelising it yields a byte-identical root that the on-chain court would verify from the same leaves. |
Segment-reader lock release (state/src/store/segment.rs) |
The DA segment reader releases its file-handle cache lock before doing disk I/O (it clones the handle under the lock and reads outside it). One slow disk read no longer serialises all concurrent readers. | Pure host-side I/O scheduling. The bytes read are identical; only the locking discipline changes. |
Serialization cache (exec/src/serialization/cache.rs) |
A thread-safe LRU caches serialised bytes of versioned values, avoiding redundant re-serialisation of the same structures across a session. | The cached bytes are the exact Molecule encoding the VM and chain would see. Caching avoids recomputing an identical byte string. |
Planned
| Optimisation | What it will achieve | Status |
|---|---|---|
| Mempool batch admission | Admit a batch of transactions under one write lock, with conflict keys computed in parallel. Turns N serial O(pool) scans into one parallel pass plus one critical section, and closes a size-check race. |
Planned (M) |
| Sighash reused-values cache | Fill the NoCache placeholder for CKB’s StandardSigHashReusedValues, caching repeated sighash sub-computations across inputs of the same transaction. |
Planned (M) |
| Content-addressable VM-result cache | Cache (script_code_hash, args, inputs_hash) to (cycles, exit_code) so re-verification of unchanged script groups (court replays, re-runs) is a lookup instead of a full VM run. This is the biggest throughput win for dispute workloads. |
Planned (L) |
| Parallel consensus signature verification | Once real secp256k1/BLS replaces the current deterministic-blake3 stubs, verify committee precommit signatures in parallel. | Planned (waits on real crypto) |
None of the above changes a single VM instruction, cycle budget, or serialisation rule. The off-chain path can be made as fast as host hardware allows, without diverging from what the chain would verify. The full list lives in the concurrency and optimisation plan.
Acknowledgements
Myelin’s flagship reference workload uses Xuejie Xiao’s Teeworlds-on-CKB replayer unchanged. The replayer, fixture tooling and in-VM game optimisations are his work; Myelin uses them as a demanding public CKB-VM workload for testing execution, projection and dispute evidence.
His writings on Teeworlds, One Hour One Life and Archipelagos were also useful prior references when surveying persistent and partitioned game workloads on CKB.
Myelin’s session runtime, typed-cell model, conflict scheduler, state commitments, finality machinery, witness bridge and court-bundle design were developed independently.
From a single chunk to a session
Xuejie’s Teeworlds design treats one game session as a chunk validated by one CKB transaction; the OHOL follow-up uses one minute of a persistent world as a chunk linked by world-state hashes.
Myelin asks a different question: how can several Myelin CellTx values be scheduled and committed inside an off-chain session while retaining a CKB-shaped projection and an explicit evidence trail? That is a prototype extension around the chunk model, not a stronger proof than direct CKB execution.
The model gains seven dimensions the single-chunk demonstration did not carry:
| Dimension | Single-chunk model | Myelin session model |
|---|---|---|
| Inter-chunk scheduling | None. Each chunk is verified in isolation. | CellDAG builds a typed read/write dependency graph and schedules independent chunks across parallel topological layers. |
| State continuity | A world-state hash is threaded manually across chunks. | An incremental MuHash accumulator (CellStateTree) maintains the session state root in O(1) per cell transition. Every commit produces a state_root_before to state_root_after pair. |
| Conflict reasoning | binding_hash: a hash of the source-level variable name, carrying no type-script identity. |
ConflictKeySpec and compute_conflict_hash bind the type-script identity into the conflict domain. Two transactions conflict iff they touch the same typed resource. |
| Projection to L1 | Execution is the endpoint. No notion of “can this land on CKB?” | A projection report tests whether each chunk serialises to a valid CKB Molecule transaction under CkbStrict semantics, producing a ckb_compatible verdict per chunk. |
| Dispute shape | The chunk-in-one-tx philosophy (no bisection). | Adopted unchanged, then wrapped in a self-contained court bundle (22 verification checks) that packages the witness layout, molecule transaction, chunk data, and finality evidence a future on-chain verifier would consume. |
| Finality | One-shot execution. No notion of a committed block. | A batch of verified chunks is finalised into a MyelinBlock under a pluggable committee (static closed committee plus Tendermint precommit, domain-separated). |
| Data availability | None. | Sealed Merkle segments with a replicated-committee availability layer and a hook for an external DA receipt. |
A future court still re-runs a single disputed chunk through the same CKB-VM, under the same single-chunk replay model. What changes is that the chunk now exists inside a session that has been scheduled, state-rooted, projected, finalised, and made data-available. That is the layer he deferred, and it is the layer Myelin provides.
The reference workload
The flagship workload runs a real CKB-VM binary through Myelin’s verifier end to end. Xuejie’s Teeworlds on CKB replayer is a RISC-V ELF that runs a full multiplayer game tick loop. Myelin runs it through its own CKB-strict verifier, chunks the game tape, projects each chunk to CKB, and produces a court bundle. The measured run is fully reproducible from the runbook: tape_bytes: 2162, vm_cycles: 15,139,695, court_checks: 22.
Demos
Two runnable demos, from zero-dependency to the full reference workload:
| Demo | What it shows | Needs | |
|---|---|---|---|
| 1 | First run | CellTx to session open to commit to court bundle to DA manifest, all local |
Rust only |
| 2 | Teeworlds end-to-end (flagship) | xuejie’s CKB-VM replayer through Myelin’s verifier, chunked, projected to CKB, court bundle (22 checks) | teeworlds fork plus built replayer |
To see the CellDAG and parallel VM verification path in action, run session commit-multi after the first-run demo (see the concurrency plan).
What ships today
- The full off-chain runtime spine:
CellTx, CellDAG with parallel VM
verification, incremental MuHash state root, mempool, dual-engine finality. - The typed-cell model and the witness bridge: real compiler metadata drives
typed conflict edges in the CellDAG. - The reference workload running end to end (numbers above).
- A zero-dependency session demo
(first run). - A published concurrency and optimisation plan
documenting every host-side optimisation and its effect.
Roadmap
Two near-term directions, both internal to Myelin’s architecture:
-
Per-participant state commitment. Today a session commit rolls the full
session state root. For workloads with many independent participants (a game with many players, an IoT batch with many gateways, a sharded order book), that is heavier than necessary. Each participant’s state could be committed and scheduled independently via its own typed conflict domain, so the CellDAG runs participant-local transitions in parallel without re-committing the whole world. TheCellTxshape andConflictKeySpecmodel already support scoping a conflict key to a single participant. The work is to make that a first-class, validated commit path. The generality of this problem was surfaced concretely by persistent-world workloads such as OHOL port. -
Session-level composition evidence. When a session spans multiple typed
domains (different type scripts with different logic and conflict rules), the interesting unit of audit is the set of domains the session touched and the transitions between them, rather than a single chunk. The typed-cell model already models each domain as aTypedCellDecland schedules cross-domain transactions by conflict hash. The work is to aggregate that into a session-level manifest a court or auditor can read as a unit, at the same evidence tier as the single-chunk court bundle. The value of explicit domain-composition evidence was reinforced by partitioned-world designs such as Archipelagos post, but the manifest design and its court-visible shape are my own.
Both build on substrate Myelin already ships. Neither requires changing CKB-VM, the CellTx shape, or the typed-cell model.
What Myelin does not claim
This is a positioning statement, no production-readiness claim.
- Closed-validator finality only. The committee is static and known.
Permissionless validator entry is out of scope today. Static committee finality must never be marketed as permissionless L2 security. - No on-chain court yet. The court bundle is the input shape for a future
on-chain verifier. The verifier itself is not deployed (l1_court_implemented: false). Myelin sits at Tier 2 of the claim ladder (executable disputed-chunk input shape), short of Tier 3 (exercised court). - No mainnet, no external DA, no custody. All evidence today is
fixture-backed or local-devnet-backed. - The typed-cell model is not in upstream CellScript. It is a Myelin
runtime-side development. Whether it gets proposed back upstream as a compiler emission target is a separate, open decision.
Quick Start
Prerequisites: a Rust toolchain (1.85+), Python 3, and optionally Node.js/npm for the website.
# verify the workspace builds and tests pass
cargo check --locked --workspace --all-targets
cargo test --locked --workspace
cargo clippy --locked --workspace --all-targets -- -D warnings
# generate a simple CellTx report
cargo run -p myelin-cli -- celltx simple-report
# open a deterministic session, commit a chunk, build + verify a court bundle
cargo run -p myelin-cli -- session open-fixture --consensus static-closed-committee --out /tmp/open.json
cargo run -p myelin-cli -- session commit-fixture --session /tmp/open.json --out /tmp/commit.json
cargo run -p myelin-cli -- session court-bundle --commit /tmp/commit.json --chunk-index 0 --out /tmp/court.json
cargo run -p myelin-cli -- session verify-court-bundle --bundle /tmp/court.json --out /tmp/court-verify.json
The full local production gate (broad; includes the Teeworlds acceptance gate when the teeworlds checkout is present):
scripts/myelin_production_gate.sh
For the flagship workload, the teeworlds end-to-end runbook builds the RISC-V replayer and runs it through Myelin end to end.



