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.

root.gno

2.44 Kb · 81 lines
 1// untrusted-render: live is the only stored string Render echoes, and SetLive
 2// validates it with assertPkgPath before storing it.
 3//
 4// Package root is the data realm of the "state realm + swappable logic" upgrade
 5// pattern (pattern C of the exploration; see ../../README.md).
 6//
 7// root holds the state and nothing else worth changing. It grants write access
 8// to exactly one logic realm at a time, identified by package path off the
 9// crossing frame rather than passed in as an argument, so a logic realm cannot
10// claim to be a path it does not occupy. Upgrading is a single SetLive call:
11// no migration, no downtime, and the data never moves.
12package root
13
14import (
15	"strings"
16	"gno.land/p/nt/ownable/v0"
17	"gno.land/p/nt/ufmt/v0"
18)
19
20const owner address = "g1manfred47kzduec920z88wfr64ylksmdcedlf5" // @moul
21
22var (
23	Ownable = ownable.NewWithAddress(owner)
24
25	counter int
26	live    = "gno.land/r/moul/x/upgrade/store/logic/v0"
27)
28
29// Inc adds n to the stored counter. Only the live logic realm may call it.
30func Inc(cur realm, n int) int {
31	assertCallerIsLive(cur)
32	counter += n
33	return counter
34}
35
36// Get is open to everyone: the data is public, only writes are gated.
37func Get() int {
38	return counter
39}
40
41// Live is the package path currently allowed to write.
42func Live() string {
43	return live
44}
45
46// SetLive hands write access to another logic realm. This is the upgrade.
47func SetLive(cur realm, pkgPath string) {
48	Ownable.AssertOwnedBy(cur.Previous().Address())
49	assertPkgPath(pkgPath)
50	live = pkgPath
51}
52
53func assertCallerIsLive(cur realm) {
54	caller := cur.Previous().PkgPath()
55	if caller != live {
56		panic("unauthorized: " + caller + " is not the live logic realm (" + live + ")")
57	}
58}
59
60func Render(_ string) string {
61	return ufmt.Sprintf("store/root/v0: %d (live logic: %s)\n", counter, live)
62}
63
64// assertPkgPath rejects anything that is not a gno.land realm path.
65//
66// It exists for Render, not for correctness of the upgrade: the stored path is
67// echoed into markdown, so validating it at write time is what lets Render
68// print it raw. ui.Inline would escape the dots in "gno.land" and turn the one
69// string a reader needs to copy into "gno\.land".
70func assertPkgPath(p string) {
71	if !strings.HasPrefix(p, "gno.land/r/") {
72		panic("not a realm path: " + p)
73	}
74	for _, c := range p {
75		ok := c == '/' || c == '.' || c == '_' || c == '-' ||
76			(c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')
77		if !ok {
78			panic("illegal character in realm path")
79		}
80	}
81}