Search Apps Documentation Source Content File Folder Download Copy Actions Download 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...) }