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

state.gno

3.29 Kb · 129 lines
  1package memba_notes_v1
  2
  3import (
  4	"chain"
  5	"chain/runtime"
  6	"encoding/hex"
  7	"strconv"
  8	"strings"
  9	"unicode"
 10	"unicode/utf8"
 11)
 12
 13func enter(cur realm, payable bool) address {
 14	if !cur.IsCurrent() {
 15		panic("notes: stale realm")
 16	}
 17	if busy {
 18		panic("notes: reentry")
 19	}
 20	if !payable {
 21		assertNoCoins()
 22	}
 23	busy = true
 24	return cur.Previous().Address()
 25}
 26func leave()                    { busy = false }
 27func idText(id [16]byte) string { return hex.EncodeToString(id[:]) }
 28func readID(s string) [16]byte {
 29	if len(s) != 32 {
 30		panic("notes: bad note id")
 31	}
 32	b, err := hex.DecodeString(s)
 33	if err != nil || hex.EncodeToString(b) != s {
 34		panic("notes: bad note id")
 35	}
 36	var id [16]byte
 37	copy(id[:], b)
 38	return id
 39}
 40func find(id [16]byte) *note {
 41	v, ok := notes.Get(idText(id))
 42	if !ok {
 43		panic("notes: note not found")
 44	}
 45	return v.(*note)
 46}
 47func live(id [16]byte) *note {
 48	n := find(id)
 49	if n.Deleted {
 50		panic("notes: note deleted")
 51	}
 52	return n
 53}
 54func expected(n *note, rev uint64) {
 55	if rev != n.Revision {
 56		panic("notes: stale revision")
 57	}
 58	if rev == ^uint64(0) {
 59		panic("notes: revision exhausted")
 60	}
 61}
 62func owner(n *note, who address) {
 63	if n.Owner != who {
 64		panic("notes: owner required")
 65	}
 66}
 67func operation(n *note, op [16]byte) {
 68	if op == ([16]byte{}) {
 69		panic("notes: empty operation id")
 70	}
 71	if n != nil && n.Last.Operation == op {
 72		panic("notes: operation id reused")
 73	}
 74}
 75func bump(n *note, who address, op [16]byte, action string) {
 76	bumpHistory(n, who, op, action, "")
 77}
 78func bumpHistory(n *note, who address, op [16]byte, action, historyExtra string) {
 79	operation(n, op)
 80	n.Revision++
 81	n.Last = receipt{op, who, runtime.ChainHeight()}
 82	n.LastExecutor = ""
 83	historyNote(n, who, op, action, historyExtra)
 84	chain.Emit("NoteChanged", "id", idText(n.ID), "action", action, "revision", strconv.FormatUint(n.Revision, 10), "actor", string(who), "op_id", idText(op))
 85}
 86func copied(b []byte) []byte { return append([]byte(nil), b...) }
 87func public(mode uint8) bool { return mode == ModePublic || mode == ModePublicOpen }
 88func indexKey(n *note) string {
 89	s := strconv.FormatUint(n.Sequence, 10)
 90	return strings.Repeat("0", 20-len(s)) + s + ":" + idText(n.ID)
 91}
 92func index(n *note) {
 93	for _, a := range append(copiedAddresses(n.Writers), n.Readers...) {
 94		sharedIndex.Set(string(a)+":"+indexKey(n), idText(n.ID))
 95	}
 96	ownerIndex.Set(string(n.Owner)+":"+indexKey(n), idText(n.ID))
 97	if public(n.Mode) && n.Listed && !n.ModeratorHidden {
 98		publicIndex.Set(indexKey(n), idText(n.ID))
 99	}
100}
101func unindex(n *note) {
102	for _, a := range append(copiedAddresses(n.Writers), n.Readers...) {
103		sharedIndex.Remove(string(a) + ":" + indexKey(n))
104	}
105	ownerIndex.Remove(string(n.Owner) + ":" + indexKey(n))
106	publicIndex.Remove(indexKey(n))
107}
108func validateTitle(title []byte) {
109	if len(title) == 0 || len(title) > MaxTitleBytes || !utf8.Valid(title) || utf8.RuneCount(title) > 80 {
110		panic("notes: invalid title")
111	}
112	s := string(title)
113	if strings.TrimSpace(s) != s {
114		panic("notes: invalid title")
115	}
116	for _, r := range s {
117		if r == '/' || unicode.IsControl(r) || unicode.Is(unicode.Cf, r) {
118			panic("notes: invalid title")
119		}
120	}
121}
122func validatePublic(title, body []byte) {
123	validateTitle(title)
124	if len(body) > MaxBodyBytes || !utf8.Valid(body) {
125		panic("notes: invalid body")
126	}
127}
128
129func copiedAddresses(a []address) []address { return append([]address(nil), a...) }