Execution pipeline¶
myelin-exec is the crate that owns the CellTx shape, the script
groups, the VM/syscall glue, the CellDAG scheduler, and the
projection layer. This page walks through what happens to a CellTx
once it lands in the runtime.
The flow inside myelin-exec¶
%%{init: {
"theme": "base",
"themeVariables": {
"primaryColor": "#A5B4FC",
"primaryTextColor": "#1E293B",
"primaryBorderColor": "#4F46E5",
"lineColor": "#6366F1",
"secondaryColor": "#C7D2FE",
"tertiaryColor": "#C7D2FE"
}
}}%%
flowchart TB
A["Admitted CellTx"]:::in
B["load_script_groups()"]:::stage
C["resolve deps<br/>(cell_deps, header_deps)"]:::stage
D["apply CellDAG<br/>+ parallel batches"]:::stage
E["build VM image<br/>(RISC-V ELF + args)"]:::stage
F["spawn VM<br/>(CKB-VM + Myelin syscalls)"]:::vm
G["collect cycle count<br/>+ exit code"]:::stage
H["apply CellTx delta<br/>to CellDB"]:::stage
I["recompute state root"]:::stage
J["emit MyelinExecutionReport"]:::out
A --> B --> C --> D --> E --> F --> G --> H --> I --> J
J --> K["project to CKB-style tx<br/>emit CkbProjectionReport"]:::proj
classDef in fill:#C7D2FE,stroke:#6366F1,color:#1E293B;
classDef stage fill:#A5B4FC,stroke:#4F46E5,color:#1E293B;
classDef vm fill:#C7D2FE,stroke:#7C3AED,color:#1E293B;
classDef out fill:#C7D2FE,stroke:#7C3AED,color:#1E293B;
classDef proj fill:#C7D2FE,stroke:#D97706,color:#1E293B;
Each stage has a small, named function in the crate. None of them touch the wall clock; all of them take their inputs by reference and emit pure outputs.
Script groups¶
A script group is the set of inputs and outputs that share the
same type script. CKB verifies script groups in parallel. Myelin
does the same — once the scheduler has built the CellDAG, the
executor can fan out by script group.
script_group {
type_script: Script, // shared type script for the group
input_indices: Vec<usize>, // which inputs share this type
output_indices: Vec<usize>, // which outputs share this type
}
Two CellTxs that share no script groups and no read/write domains can be executed in the same parallel batch. See CellDAG scheduler.
VM image construction¶
For each script group, the executor builds a VM image:
- Resolve the script binary from the CellTx's
cell_deps[]. The binary is a RISC-V ELF — usually a strippedreplayerbinary in the case of Teeworlds. - Build the VM args — the standard CKB VM contract:
-f <cell-deps-file>to read the dep Cells from witness slot 0,-i <input-index>to pick which input this group is verifying, witness slots1..nfor the script's data, and so on. - Set the cycle limit to the per-script-group cap (depends on the network's VM version).
- Wire the syscalls —
LOAD_TRANSACTION,LOAD_CELL,LOAD_SCRIPT_HASH, etc., all under Myelin's deterministic syscall surface.
The Teeworlds replayer, for instance, reads its game tape from
witness slot 1, the map from slot 2, and the config from slot
3. The executor's witness-wiring code is what makes this work
end-to-end.
Syscall surface¶
Myelin exposes the CKB syscall set, plus a small Myelin-only
extension. The extension is what produces myelin-native profile
transitions (see Semantic profiles).
| Category | Syscalls |
|---|---|
| Transaction / cell | load_transaction, load_transaction_group, load_cell, load_cell_data, load_cell_by_field, load_input_by_field, load_cell_capacity, load_actual_type_witnesses |
| Script | load_script, load_script_hash, load_proof |
| Header | load_header, load_header_by_field, load_header_dep |
| VM control | vm_version, current_cycles, exec, spawn, pipe |
| Myelin-only | myelin_state_root, myelin_session_id, myelin_chunk_index |
The Myelin-only syscalls carry no semantics on CKB; the projection
layer flags any CellTx that uses them with semantic_profile =
"myelin-native" and lists each syscall in unsupported_features.
[!WARNING] Using Myelin-only syscalls deliberately means the CellTx cannot be projected to a CKB-style transaction. That's fine for engineering experiments; it is not fine for public CKB-alignment demos.
LOAD_TRANSACTION is Molecule¶
The load_transaction syscall returns the Molecule-encoded
transaction bytes, both for the standard CKB layout and for
Myelin-extended layouts. Non-Molecule VM object ABI versions are
rejected at admission.
Concretely:
myelin-extended LOAD_TRANSACTION -> Molecule bytes, Myelin extended fields
ckb-strict LOAD_TRANSACTION -> Molecule bytes, CKB-only fields
The strict variant is the one every public demo should default to; the extended variant exists so Myelin can carry its own typed-cell metadata into the VM when needed.
Execution report¶
Every CellTx or chunk produces a MyelinExecutionReport:
pub struct MyelinExecutionReport {
pub accepted: bool,
pub vm_exit_code: i8,
pub cycles: u64,
pub consumed_cells: Vec<OutPoint>,
pub created_cells: Vec<CellOutput>,
pub read_refs: Vec<OutPoint>,
pub witness_hashes: Vec<[u8; 32]>,
pub script_deps: Vec<CellDep>,
pub conflict_hashes: Vec<[u8; 32]>,
pub typed_data_hashes: Vec<[u8; 32]>,
pub scheduler_report_hash: [u8; 32],
pub state_root_before: [u8; 32],
pub state_root_after: [u8; 32],
pub semantic_profile: SemanticProfile,
}
This is the executor's signed contract: state_root_after is the
result of applying state_root_before through the CellTx in this
exact VM context, with cycles and vm_exit_code measured.
What's in a parallel batch¶
The scheduler emits parallel_batches: Vec<Vec<CellTxId>>. Two
CellTxs in the same batch are guaranteed to:
- share no script group,
- share no read set element,
- share no write set element.
The executor iterates batches in order. Within a batch, the order
is deterministic — fee_density then wtxid — so every validator
arrives at the same state root transition.
The role of state_root_before¶
Every CellTx commits to a state_root_before in its
MyelinExecutionReport. The executor checks this against the current
state root at execution time. If they disagree, the CellTx is
rejected — this prevents stale CellTxs from applying on top of a
state the producer didn't see.
This is the equivalent of CKB's since-based time-lock protection,
but at the state-root level rather than the timestamp level.
What's deliberately not in the executor¶
- No consensus state. The executor doesn't know about committee
certificates, validator sets, or block numbers beyond what the
block header carries. Those belong to
myelin-consensus. - No mempool state. The executor takes already-admitted
CellTxs and runs them. Mempool logic lives in
myelin-mempool. - No DA logic. The executor emits CellDB deltas; DA manifests
are emitted by
myelin-statefrom those deltas.
Keeping these boundaries clean is what makes the executor auditable.
Where to look next¶
- CellDAG scheduler — what runs before the executor.
- State & data availability — what the executor's output feeds.
- CKB-style projection — what runs after the executor on every chunk.