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

notes.gno

4.49 Kb · 150 lines
  1package memba_notes_v1
  2
  3import (
  4	"chain"
  5	"chain/banker"
  6	"chain/runtime"
  7)
  8
  9// CreateNote is the only payable entrypoint; encrypted creation is atomic.
 10func CreateNote(cur realm, id [16]byte, mode uint8, title, body, access, commitment []byte, maxFee int64, opID [16]byte) {
 11	who := enter(cur, true)
 12	defer leave()
 13	if !cur.Previous().IsUserCall() {
 14		panic("notes: create directly from your account")
 15	}
 16	if paused {
 17		panic("notes: creation paused")
 18	}
 19	if id == ([16]byte{}) {
 20		panic("notes: empty note id")
 21	}
 22	if _, ok := notes.Get(idText(id)); ok {
 23		panic("notes: note id used")
 24	}
 25	if mode > ModePublicOpen || public(mode) && (len(access) != 0 || len(commitment) != 0) {
 26		panic("notes: unsupported creation mode")
 27	}
 28	if public(mode) {
 29		validatePublic(title, body)
 30	}
 31	operation(nil, opID)
 32	assertCreatePayment(cur, maxFee)
 33	if sequence == ^uint64(0) {
 34		panic("notes: sequence exhausted")
 35	}
 36	sequence++
 37	n := &note{ID: id, Owner: who, OwnerGeneration: 1, Mode: mode, TitleRevision: 1, BodyRevision: 1, Title: copied(title), Body: copied(body), BodyBytes: len(body), CreatedHeight: runtime.ChainHeight(), Sequence: sequence, Listed: public(mode)}
 38	if encrypted(mode) {
 39		initializeEncrypted(n, access, commitment)
 40	}
 41	bump(n, who, opID, "create")
 42	notes.Set(idText(id), n)
 43	index(n)
 44	if createFee > 0 {
 45		banker.NewBanker(banker.BankerTypeRealmSend, cur).SendCoins(cur.Address(), treasury, chain.Coins{chain.NewCoin("ugnot", createFee)})
 46	}
 47}
 48
 49// fieldMask: 1 title, 2 body, 3 both. An unchanged field must be omitted (empty
 50// blob). The separate field revision advances only when that field changes.
 51func Commit(cur realm, id [16]byte, baseRevision uint64, expectedEpoch uint32, fieldMask uint8, title, body []byte, opID [16]byte) {
 52	who := enter(cur, false)
 53	defer leave()
 54	mutateCommit(cur, who, id, baseRevision, expectedEpoch, fieldMask, title, body, opID)
 55}
 56func mutateCommit(cur realm, who address, id [16]byte, baseRevision uint64, expectedEpoch uint32, fieldMask uint8, title, body []byte, opID [16]byte) {
 57	n := live(id)
 58	requireContentWrite(cur, n, who)
 59	expected(n, baseRevision)
 60	if n.Epoch != expectedEpoch {
 61		panic("notes: stale epoch")
 62	}
 63	privateWritable(n)
 64	if fieldMask < 1 || fieldMask > 3 || (fieldMask&1 == 0 && len(title) != 0) || (fieldMask&2 == 0 && len(body) != 0) {
 65		panic("notes: bad field mask")
 66	}
 67	if fieldMask&1 != 0 {
 68		if public(n.Mode) {
 69			validateTitle(title)
 70		} else {
 71			validateCipher(title, n.Epoch, 1, n.TitleRevision+1, MaxCipherTitleBytes)
 72		}
 73		if n.TitleRevision == ^uint64(0) {
 74			panic("notes: title revision exhausted")
 75		}
 76	}
 77	if fieldMask&2 != 0 {
 78		if public(n.Mode) {
 79			validatePublic(n.Title, body)
 80		} else {
 81			validateCipher(body, n.Epoch, 2, n.BodyRevision+1, MaxCipherBodyBytes)
 82		}
 83		if n.BodyRevision == ^uint64(0) {
 84			panic("notes: body revision exhausted")
 85		}
 86	}
 87	operation(n, opID)
 88	if fieldMask&1 != 0 {
 89		n.Title = copied(title)
 90		n.TitleRevision++
 91	}
 92	if fieldMask&2 != 0 {
 93		n.Body = copied(body)
 94		n.BodyBytes = len(body)
 95		n.BodyRevision++
 96	}
 97	bump(n, who, opID, "commit")
 98}
 99func Rename(cur realm, id [16]byte, baseRevision uint64, expectedEpoch uint32, title []byte, opID [16]byte) {
100	Commit(cur, id, baseRevision, expectedEpoch, 1, title, nil, opID)
101}
102
103// Delete retains the ID and last operation receipt forever. Large collections
104// are purged by bounded follow-up calls, never by an unbounded delete loop.
105func Delete(cur realm, id [16]byte, baseRevision uint64, opID [16]byte) {
106	who := enter(cur, false)
107	defer leave()
108	mutateDelete(cur, who, id, baseRevision, opID)
109}
110func mutateDelete(cur realm, who address, id [16]byte, baseRevision uint64, opID [16]byte) {
111	n := live(id)
112	owner(n, who)
113	expected(n, baseRevision)
114	operation(n, opID)
115	unindex(n)
116	resetPublicWrites(n)
117	n.Deleted = true
118	n.Listed = false
119	n.Title = nil
120	n.Body = nil
121	n.BodyBytes = 0
122	n.Commitment = nil
123	n.PendingOwner = ""
124	n.Writers = nil
125	n.Readers = nil
126	n.Policies = [3]string{}
127	n.GovWriters = false
128	bump(n, who, opID, "delete")
129}
130func SetCommentMode(cur realm, id [16]byte, baseRevision uint64, open bool, opID [16]byte) {
131	who := enter(cur, false)
132	defer leave()
133	mutateSetCommentMode(cur, who, id, baseRevision, open, opID)
134}
135func mutateSetCommentMode(cur realm, who address, id [16]byte, baseRevision uint64, open bool, opID [16]byte) {
136	n := live(id)
137	owner(n, who)
138	expected(n, baseRevision)
139	if !public(n.Mode) {
140		panic("notes: public note required")
141	}
142	operation(n, opID)
143	if open {
144		n.Mode = ModePublicOpen
145	} else {
146		resetPublicWrites(n)
147		n.Mode = ModePublic
148	}
149	bump(n, who, opID, "comments-mode")
150}