# p/moul/x/vm/vmkit The host ABI shared by every guest virtual machine that runs inside a gno realm: a stepping contract with an explicit fuel budget, a capability-scoped `Host`, and a snapshot format that lets a guest program outlive the transaction that started it. A guest VM implements `Machine`. Everything else here is the machinery a VM should not have to write twice: the `Meter`, the canonical `Writer`/`Reader` snapshots are built from, an in-memory `TestHost`, and the avl-backed `Store` a realm keeps its instances in. First consumer: [`p/moul/x/vm/bf`](../bf). Live demo: [`r/moul/x/vm/bfdemo`](/r/moul/x/vm/bfdemo/v0). ```go type Machine interface { Step(h Host, fuel int64) (used int64, status Status) Snapshot() []byte Restore(b []byte) error } ``` `Status` is one of `Running`, `Halted`, `Trapped`, `OutOfFuel`. ## What the ABI is for **Fuel is the interface, not the backstop.** Running out of fuel yields `OutOfFuel` plus a machine that can be snapshotted, never a panic. Gas still bounds the transaction; it is just not the thing a guest program is written against. **Continuations.** `Snapshot` and `Restore` mean a program runs across blocks. The realm stores the bytes, the next caller pays for the next slice. Gno realm code cannot pause itself; a guest can. The property that makes this real is tested rather than asserted: five slices of one fuel unit must produce exactly what one slice of five produces, for every program in `bf`'s corpus. **Capabilities, not ambient authority.** A guest gets exactly the `Host` it was handed. `Send` returns `ErrNotGranted` unless the deploying realm funded a budget, storage is scoped to the instance, and nothing is looked up. Gno itself has ambient authority through the realm frame, so the guest is where the capability-secure version can actually be tried. ## Meter is not a hot-path type `Meter` exists for the API boundary: compute a slice budget, charge it once, report what was used. Calling `Meter.Charge` once per guest instruction was measured at **+86% on top of an entire interpreter dispatch loop**, and more than tripled its allocation count. A machine should count fuel in a local and settle up with the caller. The numbers are in [`bf`'s README](../bf/README.md). `Charge` spends nothing when the budget cannot cover the request, so a machine that stops for lack of fuel is exactly at the instruction it could not pay for, and resuming re-executes that instruction and no other. ## The snapshot codec `Writer` and `Reader` are fixed-width big-endian with length-prefixed bytes, so the encoding is canonical: the same machine state always produces the same bytes, on every node. A snapshot is consensus state, so two nodes encoding it differently is a fork, and a short read is a hard error rather than a zero value. Machines are not required to use it, but a machine that invents its own layout owes the zoo an explanation: the cross-VM snapshot cost comparison only means something when the encodings match. ## Instance and Store `Instance` is one guest program as a realm stores it: code, snapshot between slices, status, and the fuel accounting that survives the transaction. It holds bytes rather than a `Machine` on purpose, which is what makes the storage cost of a paused program measurable. `Instance.Run` folds one slice back into the instance and leaves it untouched when `Restore` fails, so a snapshot that cannot be decoded costs the caller gas but never corrupts the stored program. --- Part of **[moul/gno-contracts](https://github.com/moul/gno-contracts)** โ€” moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage. **Dependency graph:** ![gno.land/p/moul/x/vm/vmkit/v0 dependency graph](https://raw.githubusercontent.com/moul/gno-contracts/main/_assets/gno.land/p/moul/x/vm/vmkit/v0/deps.png) > ๐Ÿงช **Highly experimental โ€” potentially vibe-coded.** Not audited; may break, change, or be removed at any time. Do not use with anything of value. Full disclaimer: [DISCLAIMER](https://github.com/moul/gno-contracts/blob/main/DISCLAIMER.md).