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/bf/v0

Package
Open in gnoweb ↗

Overview

Kind
Pure package
Name
v0
Namespace
moul / x / vm / bf
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/bf/v0
gno
0.9

Files (9)

  • README.mdmarkdown
  • gnomod.tomltoml
  • bf.gnogno
  • compile.gnogno
  • machine.gnogno
  • bf_test.gnogno
  • ladder_test.gnogno
  • machine_test.gnogno
  • micro_test.gnogno
  • machine_test.gnogno
    1package bf23import (4	"testing"56	"gno.land/p/moul/x/vm/vmkit/v0"7	"gno.land/p/nt/uassert/v0"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
    10// oneShot runs src to completion and returns what it wrote.
    11func oneShot(t *testing.T, src string) string {
    12 t.Helper()
    13 h := vmkit.NewTestHost()
    14 status, err := Run(src, h)
    15 uassert.NoError(t, err)
    16 uassert.Equal(t, "halted", status.String())
    17 return h.OutString()
    18}
    19
    20// TestSlicedRunEqualsOneShot is the property that makes a guest program a
    21// contract rather than a function call: chopping the execution into fuel
    22// slices, snapshotting between each, must produce exactly the single run.
    23func TestSlicedRunEqualsOneShot(t *testing.T) {
    24 for _, slice := range []int64{1, 2, 7, 64} {
    25 prog, err := CompileDefault(hello)
    26 uassert.NoError(t, err)
    27
    28 h := vmkit.NewTestHost()
    29 snap := []byte(nil)
    30 status := vmkit.Running
    31 slices := 0
    32 for status == vmkit.Running && slices < 10000 {
    33 m := NewMachine(prog) // a realm holds bytes, not a machine
    34 if snap != nil {
    35 uassert.NoError(t, m.Restore(snap))
    36 }
    37 _, status = m.Step(h, slice)
    38 snap = m.Snapshot()
    39 slices++
    40 }
    41 uassert.Equal(t, "halted", status.String())
    42 uassert.Equal(t, "Hello World", h.OutString())
    43 }
    44}
    45
    46func TestSlicedRunAgreesAcrossTheCorpus(t *testing.T) {
    47 for _, tc := range corpus {
    48 prog, err := CompileDefault(tc.src)
    49 uassert.NoError(t, err)
    50 if prog == nil {
    51 continue
    52 }
    53 h := vmkit.NewTestHost()
    54 snap := []byte(nil)
    55 status := vmkit.Running
    56 n := 0
    57 for status == vmkit.Running && n < 20000 {
    58 m := NewMachine(prog)
    59 if snap != nil {
    60 uassert.NoError(t, m.Restore(snap))
    61 }
    62 _, status = m.Step(h, 3)
    63 snap = m.Snapshot()
    64 n++
    65 }
    66 if h.OutString() != tc.want {
    67 t.Errorf("%s sliced: got %q, want %q", tc.name, h.OutString(), tc.want)
    68 }
    69 }
    70}
    71
    72func TestFuelStopsTheMachine(t *testing.T) {
    73 prog, err := CompileDefault(hello)
    74 uassert.NoError(t, err)
    75 m := NewMachine(prog)
    76 h := vmkit.NewTestHost()
    77
    78 used, status := m.Step(h, 5)
    79 uassert.Equal(t, int64(5), used)
    80 uassert.Equal(t, "running", status.String())
    81 uassert.Equal(t, "", h.OutString()) // not far enough to print anything
    82}
    83
    84// TestScanIsChargedPerCell pins the thing that would otherwise be a way to
    85// buy unbounded work for one unit: a scan walks one cell per unit of fuel,
    86// and stopping mid-scan resumes the same walk.
    87func TestScanIsChargedPerCell(t *testing.T) {
    88 // 20 non-zero cells, then scan left back to the zero at cell 0.
    89 src := ">+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+[<]"
    90 prog, err := CompileDefault(src)
    91 uassert.NoError(t, err)
    92
    93 m := NewMachine(prog)
    94 h := vmkit.NewTestHost()
    95 used, status := m.Step(h, 45)
    96 uassert.Equal(t, int64(45), used)
    97 uassert.Equal(t, "running", status.String())
    98 uassert.True(t, m.Pointer() > 0) // stopped part way down the scan
    99
    100 // Resuming finishes the same walk and lands on the zero cell.
    101 _, status = m.Step(h, vmkit.Unmetered)
    102 uassert.Equal(t, "halted", status.String())
    103 uassert.Equal(t, 0, m.Pointer())
    104}
    105
    106func TestSnapshotRoundTrip(t *testing.T) {
    107 prog, err := CompileDefault(hello)
    108 uassert.NoError(t, err)
    109
    110 a := NewMachine(prog)
    111 h := vmkit.NewTestHost()
    112 a.Step(h, 40)
    113
    114 b := NewMachine(prog)
    115 uassert.NoError(t, b.Restore(a.Snapshot()))
    116 uassert.Equal(t, a.PC(), b.PC())
    117 uassert.Equal(t, a.Pointer(), b.Pointer())
    118 uassert.Equal(t, a.Touched(), b.Touched())
    119 for i := 0; i < a.Touched(); i++ {
    120 uassert.Equal(t, uint64(a.Cell(i)), uint64(b.Cell(i)))
    121 }
    122 uassert.Equal(t, string(a.Snapshot()), string(b.Snapshot()))
    123}
    124
    125// TestSnapshotIsTrimmed is the continuation kill criterion in test form: if a
    126// pause carried the whole 30,000 byte tape, resuming would cost more than
    127// re-running and continuations would be theater.
    128func TestSnapshotIsTrimmed(t *testing.T) {
    129 m, err := Load(hello)
    130 uassert.NoError(t, err)
    131 h := vmkit.NewTestHost()
    132 m.Step(h, vmkit.Unmetered)
    133
    134 uassert.Equal(t, 5, m.Touched()) // hello world uses five cells
    135 snap := m.Snapshot()
    136 // 4 magic + 1 version + 3x8 zig-zag ints + 1 status + 4 empty trap
    137 // + 4 length + 5 tape. The README quotes this number.
    138 uassert.Equal(t, 43, len(snap))
    139 uassert.True(t, len(snap) < TapeSize/100)
    140}
    141
    142func TestRestoreRejectsJunk(t *testing.T) {
    143 prog, err := CompileDefault(hello)
    144 uassert.NoError(t, err)
    145 good := NewMachine(prog)
    146 good.Step(vmkit.NewTestHost(), 20)
    147 snap := good.Snapshot()
    148
    149 cases := []struct {
    150 name string
    151 b []byte
    152 }{
    153 {"empty", []byte{}},
    154 {"truncated", snap[:len(snap)-3]},
    155 {"bad magic", append([]byte{0, 0, 0, 0}, snap[4:]...)},
    156 }
    157 for _, tc := range cases {
    158 m := NewMachine(prog)
    159 if err := m.Restore(tc.b); err == nil {
    160 t.Errorf("Restore(%s) should have failed", tc.name)
    161 }
    162 }
    163
    164 // A snapshot with a wrong version byte is refused rather than decoded
    165 // into a plausible-looking wrong state.
    166 bad := make([]byte, len(snap))
    167 copy(bad, snap)
    168 bad[4] = 99
    169 m := NewMachine(prog)
    170 uassert.ErrorIs(t, m.Restore(bad), vmkit.ErrBadSnapshot)
    171}
    172
    173func TestRestoreRejectsAnOutOfRangePC(t *testing.T) {
    174 small, err := CompileDefault("+")
    175 uassert.NoError(t, err)
    176 big, err := CompileDefault(hello)
    177 uassert.NoError(t, err)
    178
    179 m := NewMachine(big)
    180 m.Step(vmkit.NewTestHost(), 30)
    181 snap := m.Snapshot()
    182
    183 // The same snapshot against a two-op program points past the end.
    184 other := NewMachine(small)
    185 uassert.ErrorIs(t, other.Restore(snap), vmkit.ErrBadSnapshot)
    186}
    187
    188func TestHaltedMachineStaysHalted(t *testing.T) {
    189 m, err := Load("+++.")
    190 uassert.NoError(t, err)
    191 h := vmkit.NewTestHost()
    192 m.Step(h, vmkit.Unmetered)
    193 uassert.Equal(t, "halted", m.Status().String())
    194
    195 used, status := m.Step(h, vmkit.Unmetered)
    196 uassert.Equal(t, int64(0), used)
    197 uassert.Equal(t, "halted", status.String())
    198 uassert.Equal(t, "\x03", h.OutString()) // still only one write
    199}
    200
    201func TestLoadRejectsBadSource(t *testing.T) {
    202 _, err := Load("[[")
    203 uassert.Error(t, err)
    204 status, err := Run("]", vmkit.NewTestHost())
    205 uassert.Error(t, err)
    206 uassert.Equal(t, "trapped", status.String())
    207}
    208
    209// TestInstanceIntegration wires the machine through vmkit's realm-facing
    210// plumbing, which is the shape the demo realm uses.
    211func TestInstanceIntegration(t *testing.T) {
    212 prog, err := CompileDefault(hello)
    213 uassert.NoError(t, err)
    214
    215 inst := vmkit.NewInstance("001", address("g1x"), VMName, []byte(hello), vmkit.Unmetered)
    216 h := vmkit.NewTestHost()
    217 for i := 0; i < 200 && inst.Status == vmkit.Running; i++ {
    218 uassert.NoError(t, inst.Run(NewMachine(prog), h, 8))
    219 }
    220 uassert.Equal(t, "halted", inst.Status.String())
    221 uassert.Equal(t, "Hello World", h.OutString())
    222 uassert.True(t, inst.Slices > 1)
    223 uassert.True(t, inst.FuelUsed > 0)
    224}
    225
    226func TestInstanceHonoursItsBudget(t *testing.T) {
    227 prog, err := CompileDefault(hello)
    228 uassert.NoError(t, err)
    229
    230 inst := vmkit.NewInstance("002", address("g1x"), VMName, []byte(hello), 10)
    231 h := vmkit.NewTestHost()
    232 uassert.NoError(t, inst.Run(NewMachine(prog), h, vmkit.Unmetered))
    233 uassert.Equal(t, "out of fuel", inst.Status.String())
    234 uassert.Equal(t, int64(10), inst.FuelUsed)
    235 uassert.ErrorIs(t, inst.Run(NewMachine(prog), h, vmkit.Unmetered), vmkit.ErrBudgetExhausted)
    236}
    237