PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/p/moul/x/vm/vmkit/v0

Package
Open in gnoweb ↗

Overview

Kind
Pure package
Name
v0
Namespace
moul / x / vm / vmkit
Files
9 (README)(gnomod.toml)
Exported functions
n/a — not supported for pure packages by the node (vm/qfuncs)
Module
gno.land/p/moul/x/vm/vmkit/v0
gno
0.9

Files (9)

  • README.mdmarkdown
  • gnomod.tomltoml
  • codec.gnogno
  • fuel.gnogno
  • host.gnogno
  • instance.gnogno
  • machine.gnogno
  • testhost.gnogno
  • vmkit_test.gnogno
  • instance.gnogno
    1package vmkit23import (4	"errors"56	"gno.land/p/nt/avl/v0"7)8

    Functions

    not supported for pure packages by the node (vm/qfuncs)

    Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.

    9// ErrNoInstance is returned when an id names nothing.
    10var ErrNoInstance = errors.New("vmkit: no such instance")
    11
    12// ErrBudgetExhausted is returned when an instance has already spent its total
    13// fuel budget, so there is nothing left to step.
    14var ErrBudgetExhausted = errors.New("vmkit: instance fuel budget exhausted")
    15
    16// Instance is one guest program as a realm stores it: the code, the machine
    17// state between slices, and the accounting that survives the transaction.
    18//
    19// It holds a snapshot rather than a [Machine], on purpose. A realm keeps
    20// bytes; the machine is rebuilt for the slice that needs it and thrown away
    21// after. That is what makes the storage cost of a paused program measurable,
    22// which is the whole kill criterion for continuations: if resuming costs more
    23// than re-running, continuations are theater.
    24type Instance struct {
    25 ID string
    26 Owner address
    27 VM string // which guest machine the Program is for
    28
    29 Program []byte
    30 Snapshot []byte
    31
    32 Status Status
    33 Trap string
    34
    35 // FuelUsed is the total across every slice run so far.
    36 FuelUsed int64
    37 // FuelBudget caps FuelUsed across the instance's whole life, or is
    38 // [Unmetered] for no cap.
    39 FuelBudget int64
    40
    41 // Slices counts how many transactions have stepped this instance.
    42 Slices int64
    43
    44 Output []byte
    45}
    46
    47// NewInstance returns an instance ready for its first slice.
    48func NewInstance(id string, owner address, vm string, program []byte, budget int64) *Instance {
    49 if budget < 0 {
    50 budget = Unmetered
    51 }
    52 prog := make([]byte, len(program))
    53 copy(prog, program)
    54 return &Instance{
    55 ID: id,
    56 Owner: owner,
    57 VM: vm,
    58 Program: prog,
    59 Status: Running,
    60 FuelBudget: budget,
    61 }
    62}
    63
    64// Remaining reports the fuel left in the instance's total budget, or
    65// [Unmetered].
    66func (i *Instance) Remaining() int64 {
    67 if i.FuelBudget == Unmetered {
    68 return Unmetered
    69 }
    70 left := i.FuelBudget - i.FuelUsed
    71 if left < 0 {
    72 return 0
    73 }
    74 return left
    75}
    76
    77// Slice returns how much fuel the next call to [Instance.Run] may spend when
    78// the caller asks for `want`: `want` clamped to what the budget still allows.
    79func (i *Instance) Slice(want int64) int64 {
    80 left := i.Remaining()
    81 if left == Unmetered {
    82 return want
    83 }
    84 if want == Unmetered || want > left {
    85 return left
    86 }
    87 return want
    88}
    89
    90// Run steps m for one slice of at most `fuel` units and folds the result back
    91// into the instance: the new snapshot, the status, the fuel spent, and
    92// anything the guest wrote to h.
    93//
    94// m must be a fresh machine loaded from i.Program; Run restores i.Snapshot
    95// into it when there is one, so the caller never has to remember the order.
    96// The instance is left untouched when Restore fails, which means a snapshot
    97// that cannot be decoded costs the caller gas but never corrupts the stored
    98// program.
    99func (i *Instance) Run(m Machine, h Host, fuel int64) error {
    100 if i.Status.Done() && i.Status != Running {
    101 return ErrBudgetExhausted
    102 }
    103 if len(i.Snapshot) > 0 {
    104 if err := m.Restore(i.Snapshot); err != nil {
    105 return err
    106 }
    107 }
    108 slice := i.Slice(fuel)
    109 if slice == 0 {
    110 i.Status = OutOfFuel
    111 return ErrBudgetExhausted
    112 }
    113
    114 used, status := m.Step(h, slice)
    115
    116 i.FuelUsed += used
    117 i.Slices++
    118 i.Snapshot = m.Snapshot()
    119 i.Status = status
    120 i.Trap = TrapReason(m)
    121 if status == Running && i.Remaining() == 0 {
    122 i.Status = OutOfFuel
    123 }
    124 return nil
    125}
    126
    127// Store is the avl-backed set of instances a realm owns, keyed by id.
    128type Store struct {
    129 tree *avl.Tree
    130}
    131
    132// NewStore returns an empty store.
    133func NewStore() *Store { return &Store{tree: avl.NewTree()} }
    134
    135// Set writes an instance, replacing any instance with the same id.
    136func (s *Store) Set(i *Instance) {
    137 if i == nil {
    138 return
    139 }
    140 s.tree.Set(i.ID, i)
    141}
    142
    143// Get returns the instance with this id, or nil.
    144func (s *Store) Get(id string) *Instance {
    145 v := s.tree.Get(id)
    146 if v == nil {
    147 return nil
    148 }
    149 inst, ok := v.(*Instance)
    150 if !ok {
    151 return nil
    152 }
    153 return inst
    154}
    155
    156// Remove deletes an instance and reports whether it existed.
    157func (s *Store) Remove(id string) bool {
    158 _, removed := s.tree.Remove(id)
    159 return removed
    160}
    161
    162// Size returns how many instances are stored.
    163func (s *Store) Size() int { return s.tree.Size() }
    164
    165// Iterate walks every instance in key order, stopping early when fn returns
    166// true.
    167func (s *Store) Iterate(fn func(*Instance) bool) {
    168 s.tree.Iterate("", "", func(_ string, v any) bool {
    169 inst, ok := v.(*Instance)
    170 if !ok {
    171 return false
    172 }
    173 return fn(inst)
    174 })
    175}
    176
    177// ReverseIterate walks every instance in descending key order, which is how a
    178// realm renders newest-first when ids are zero-padded and ascending.
    179func (s *Store) ReverseIterate(fn func(*Instance) bool) {
    180 s.tree.ReverseIterate("", "", func(_ string, v any) bool {
    181 inst, ok := v.(*Instance)
    182 if !ok {
    183 return false
    184 }
    185 return fn(inst)
    186 })
    187}
    188