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

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

rust_test.gno

3.41 Kb · 99 lines
 1package riscv
 2
 3import (
 4	"testing"
 5
 6	"gno.land/p/nym-moultest123/x/vm/vmkit/v0"
 7	"gno.land/p/nt/uassert/v0"
 8)
 9
10// The demo the design issue actually asked for: Rust code, compiled by rustc,
11// running on gno.land, moving a balance from one account to another.
12//
13// The image is guests.gno's, built from tools/riscv-guests/ledger. It is worth
14// more than the C guest for one reason: it links Rust's real core and
15// compiler_builtins, so this exercises the standard library's own software
16// arithmetic rather than only what the compiler emitted for my source.
17
18func runLedger(t *testing.T, in string) (string, vmkit.Status, *Machine) {
19	t.Helper()
20	m, err := NewMachine(GuestLedger(), entry)
21	uassert.NoError(t, err)
22	if m == nil {
23		return "", vmkit.Trapped, nil
24	}
25	h := vmkit.NewTestHost().WithInput([]byte(in))
26	_, status := m.Step(h, 5000000)
27	return string(h.Out()), status, m
28}
29
30func TestRustLedgerTransfers(t *testing.T) {
31	out, status, _ := runLedger(t,
32		"mint alice 100\nmint bob 50\nsend alice bob 30\n")
33	uassert.Equal(t, "halted", status.String())
34	uassert.Equal(t, "alice 70\nbob 80\n", out)
35}
36
37func TestRustLedgerMintBurnAndBlankLines(t *testing.T) {
38	out, status, _ := runLedger(t, "mint a 5\n\n   \nburn a 2\n")
39	uassert.Equal(t, "halted", status.String())
40	uassert.Equal(t, "a 3\n", out)
41
42	out, status, _ = runLedger(t, "")
43	uassert.Equal(t, "halted", status.String())
44	uassert.Equal(t, "", out)
45}
46
47// A refusal is halted, not trapped, and it names the line. This is the
48// semantic the whole VM is built around: the program said no, the machine did
49// not break, and a chain has to be able to tell a user which one happened.
50func TestRustLedgerRefusalsAreHaltsNotTraps(t *testing.T) {
51	cases := []struct{ in, want string }{
52		{"mint a 1\nsend a b 9\n", "line 2: insufficient balance\n"},
53		{"send nobody b 1\n", "line 1: unknown sender\n"},
54		{"burn ghost 1\n", "line 1: unknown account\n"},
55		{"frobnicate\n", "line 1: unknown command\n"},
56		{"mint a x\n", "line 1: bad amount\n"},
57	}
58	for _, c := range cases {
59		out, status, m := runLedger(t, c.in)
60		uassert.Equal(t, "halted", status.String(), c.in+": "+m.Trap())
61		uassert.Equal(t, c.want, out)
62		uassert.Equal(t, uint64(1), uint64(m.Registers()[10]), "a refusal exits 1")
63	}
64}
65
66// 64-bit arithmetic on a 32-bit machine goes through compiler_builtins, and
67// printing a balance above 2^32 is the path that proves __udivdi3 ran.
68func TestRustLedgerDoes64BitArithmetic(t *testing.T) {
69	// Nine-digit mints, accumulated past what 32 bits holds.
70	in := ""
71	for i := 0; i < 6; i++ {
72		in += "mint whale 999999999\n"
73	}
74	out, status, _ := runLedger(t, in)
75	uassert.Equal(t, "halted", status.String())
76	uassert.Equal(t, "whale 5999999994\n", out)
77}
78
79// Compiled Rust pauses and resumes like anything else, including in the middle
80// of a library routine it never asked to call.
81func TestRustLedgerSurvivesSlicing(t *testing.T) {
82	image := GuestLedger()
83	h := vmkit.NewTestHost().WithInput([]byte("mint alice 100\nsend alice bob 30\n"))
84
85	sliced, err := NewMachine(image, entry)
86	uassert.NoError(t, err)
87	status := vmkit.Running
88	slices := 0
89	for i := 0; i < 4000 && status == vmkit.Running; i++ {
90		var fresh Machine
91		uassert.NoError(t, fresh.Restore(sliced.Snapshot()))
92		_, status = fresh.Step(h, 17)
93		sliced = &fresh
94		slices++
95	}
96	uassert.Equal(t, "halted", status.String())
97	uassert.True(t, slices > 20, "a sliced run must actually have been sliced")
98	uassert.Equal(t, "alice 70\nbob 30\n", string(h.Out()))
99}