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.

read.gno

3.93 Kb · 146 lines
  1package nsvote
  2
  3import (
  4	"strings"
  5
  6	"gno.land/p/nt/ufmt/v0"
  7	"gno.land/r/nym-mnsrehearsal001/nsdata/v2"
  8)
  9
 10// Everything a caller needs about one request, on one line. Fields are
 11// separated by "|" rather than "," because a reason may well contain a
 12// comma; it may not contain "|" or a newline, which Propose enforces.
 13func row(id int64, p *Proposal) string {
 14	kind := p.kind
 15	if kind == "" {
 16		kind = "domain" // anything written before kinds existed
 17	}
 18	return ufmt.Sprintf("%d|%s|%s|%s|%s|%d|%d|%d|%s|%d",
 19		id, kind, p.label, p.proposer.String(), p.reason,
 20		p.created, p.yes, p.no, p.status, p.decided)
 21}
 22
 23// ListProposals pages newest first, which is the order anybody actually
 24// wants to read them in.
 25func ListProposals(after string, limit int) (rows, next string) {
 26	if limit <= 0 || limit > maxPage {
 27		limit = maxPage
 28	}
 29	var keys []string
 30	proposals.Iterate("", "", func(k string, _ any) bool {
 31		keys = append(keys, k)
 32		return false
 33	})
 34
 35	var b strings.Builder
 36	n := 0
 37	last := ""
 38	started := after == ""
 39	// Walk backwards for newest-first; `after` is the last key returned.
 40	for i := len(keys) - 1; i >= 0; i-- {
 41		k := keys[i]
 42		if !started {
 43			if k == after {
 44				started = true
 45			}
 46			continue
 47		}
 48		if n >= limit {
 49			return b.String(), last
 50		}
 51		v := proposals.Get(k)
 52		if v == nil {
 53			continue
 54		}
 55		if b.Len() > 0 {
 56			b.WriteString("\n")
 57		}
 58		p := v.(*Proposal)
 59		b.WriteString(row(parseKey(k), p))
 60		last = k
 61		n++
 62	}
 63	return b.String(), ""
 64}
 65
 66func parseKey(k string) int64 {
 67	var out int64
 68	for i := 0; i < len(k); i++ {
 69		if k[i] < '0' || k[i] > '9' {
 70			return 0
 71		}
 72		out = out*10 + int64(k[i]-'0')
 73	}
 74	return out
 75}
 76
 77func GetProposal(id int64) string {
 78	v := proposals.Get(key(id))
 79	if v == nil {
 80		return ""
 81	}
 82	return row(id, v.(*Proposal))
 83}
 84
 85func CountProposals() int64 { return int64(proposals.Size()) }
 86
 87// HasVoted lets the page grey out a button instead of letting somebody
 88// sign a transaction that is certain to be rejected.
 89func HasVoted(id int64, voter address) string {
 90	v := votes.Get(voteKey(id, voter))
 91	if v == nil {
 92		return ""
 93	}
 94	return v.(string)
 95}
 96
 97// CanTakePart answers the one question the page needs before it offers
 98// any of this: does this address hold a name.
 99func CanTakePart(who address) bool { return nsdata.BalanceOf(who) > 0 }
100
101// Roster is the raw material for the leaderboards: one line per name,
102// owner first, so the caller can aggregate however it likes.
103//
104// It lives here rather than in nslogic because this realm is being
105// deployed anyway and nslogic is not — adding it there would have cost
106// a fresh deployment of the largest realm we have, for a read.
107//
108// Paged, and the page walks every name in it. That is fine at the scale
109// this registry is at and it will not be fine at fifty thousand names;
110// at that point the aggregate belongs somewhere it is kept as it
111// changes rather than recomputed on every read.
112func Roster(after string, limit int) (rows, next string) {
113	if limit <= 0 || limit > maxPage {
114		limit = maxPage
115	}
116	keys, nxt := nsdata.ExportNames("", after, limit)
117
118	var b strings.Builder
119	for _, k := range strings.Split(keys, ",") {
120		if k == "" {
121			continue
122		}
123		at := strings.Index(k, "*")
124		if at < 0 {
125			continue
126		}
127		domainLabel, label := k[:at], k[at+1:]
128		owner, registered, expires, streak, frozen, _ := nsdata.GetNameInfo(label, domainLabel)
129		if b.Len() > 0 {
130			b.WriteString("\n")
131		}
132		b.WriteString(ufmt.Sprintf("%s|%s*%s|%d|%d|%d|%t",
133			owner.String(), label, domainLabel, registered, expires, streak, frozen))
134	}
135	return b.String(), nxt
136}
137
138// Version lets a caller find out what it is talking to BEFORE it sends a
139// transaction that would be rejected for having the wrong number of
140// arguments.
141//
142// v1 has no such function, so a nil answer is itself the answer: an
143// older realm. That is cheaper and more honest than the site assuming
144// the newest shape and failing at signing time, which is exactly what
145// happened when Propose grew a `kind`.
146func Version() string { return "v2" }