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

notes.gno

4.49 Kb · 150 lines
  1package memba_notes_rc1
  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}