Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

machine.gno

3.76 Kb · 100 lines
  1// Package vmkit is the host ABI shared by every guest virtual machine that
  2// runs inside a gno realm: a stepping contract with an explicit fuel budget,
  3// a capability-scoped [Host], and a snapshot format that lets a guest program
  4// outlive the transaction that started it.
  5//
  6// A guest VM implements [Machine]. Everything else in this package is the
  7// machinery a VM should not have to write twice: the [Meter], the [Codec] the
  8// snapshots are built from, an in-memory [TestHost], and the avl-backed
  9// [Store] a realm keeps its instances in.
 10//
 11// The three things the ABI exists to fix:
 12//
 13//   - Fuel is the interface, not the backstop. Running out of fuel yields
 14//     [OutOfFuel] plus a machine that can be snapshotted, never a panic. Gas
 15//     still bounds the transaction, but a guest that stops is a normal outcome.
 16//   - Continuations. Snapshot and Restore mean a program runs across blocks.
 17//     The realm stores the bytes, and the next caller pays for the next slice.
 18//     Gno realm code itself cannot pause; a guest can.
 19//   - Capabilities, not ambient authority. A guest gets exactly the [Host] it
 20//     was handed. No Send without a grant, no storage outside its own scope.
 21//
 22// Live demo: [r/moul/x/vm/bfdemo](/r/moul/x/vm/bfdemo/v0), running the
 23// [p/moul/x/vm/bf](/p/moul/x/vm/bf/v0) guest.
 24package vmkit
 25
 26// Status is the outcome of a call to [Machine.Step].
 27type Status int
 28
 29const (
 30	// Running means the machine stopped because it ran out of the fuel
 31	// handed to this slice, but the program has not finished. It is
 32	// resumable: snapshot it, and step it again later.
 33	Running Status = iota
 34
 35	// Halted means the program reached its end. Terminal.
 36	Halted
 37
 38	// Trapped means the guest did something the machine refuses to do:
 39	// an invalid instruction, an out-of-range access, a capability it was
 40	// not granted. Terminal.
 41	Trapped
 42
 43	// OutOfFuel means the instance exhausted its total budget, not just the
 44	// fuel for this slice. Terminal unless the owner raises the budget.
 45	OutOfFuel
 46)
 47
 48// String renders the status as the lowercase word used in realm output.
 49func (s Status) String() string {
 50	switch s {
 51	case Running:
 52		return "running"
 53	case Halted:
 54		return "halted"
 55	case Trapped:
 56		return "trapped"
 57	case OutOfFuel:
 58		return "out of fuel"
 59	}
 60	return "unknown"
 61}
 62
 63// Done reports whether the status is terminal, i.e. stepping again is
 64// pointless without operator intervention.
 65func (s Status) Done() bool { return s != Running }
 66
 67// Machine is one guest virtual machine, mid-execution.
 68//
 69// Step runs until the program halts, traps, or burns `fuel` units, whichever
 70// comes first, and reports how much fuel it actually used. A Machine must
 71// charge at least one unit per guest instruction so that a fuel budget is a
 72// real bound on work; beyond that the unit is the VM's own business, and
 73// [r/moul/x/vm/bfdemo](/r/moul/x/vm/bfdemo/v0) compares them by measurement
 74// rather than by trusting the number.
 75//
 76// Snapshot must round-trip through Restore: a machine stepped to exhaustion,
 77// snapshotted, restored and stepped again must produce exactly what the same
 78// machine stepped in one go would have. That property is what makes a guest
 79// program a contract instead of a function call.
 80type Machine interface {
 81	Step(h Host, fuel int64) (used int64, status Status)
 82	Snapshot() []byte
 83	Restore(b []byte) error
 84}
 85
 86// Trapper is an optional refinement of [Machine]: a machine that can explain
 87// why it trapped. Kept out of [Machine] so the core ABI stays three methods.
 88type Trapper interface {
 89	// Trap returns the reason for a [Trapped] status, or "" when the
 90	// machine has not trapped.
 91	Trap() string
 92}
 93
 94// TrapReason returns m's trap reason when m implements [Trapper], else "".
 95func TrapReason(m Machine) string {
 96	if t, ok := m.(Trapper); ok {
 97		return t.Trap()
 98	}
 99	return ""
100}