Search Apps Documentation Source Content File Folder Download Copy Actions Download

counter.gno

3.68 Kb · 143 lines
  1// Package counter implements "Counter Club": a single shared integer counter
  2// with a rolling history of the last 20 mutations. Anyone may Inc, Dec, or
  3// Reset the value; every change records the caller, the delta applied, the
  4// resulting value, and the block height it happened at.
  5package counter
  6
  7import (
  8	"chain"
  9	"chain/runtime"
 10	"chain/runtime/unsafe"
 11	"strconv"
 12	"strings"
 13)
 14
 15// maxHistory is the number of recent changes kept in the log.
 16const maxHistory = 20
 17
 18// change is a single recorded mutation of the counter.
 19type change struct {
 20	caller address // who triggered the change
 21	delta  int     // how much the value moved (+1, -1, or reset amount)
 22	value  int     // the resulting counter value after the change
 23	height int64   // block height at which it occurred
 24}
 25
 26// value is the current shared counter.
 27var value int
 28
 29// total counts every mutation ever applied (not capped, unlike history).
 30var total int
 31
 32// history holds the last maxHistory changes, oldest first.
 33var history []change
 34
 35// record appends a change to the history, trimming to the last maxHistory.
 36func record(delta, newValue int) {
 37	c := change{
 38		caller: unsafe.PreviousRealm().Address(),
 39		delta:  delta,
 40		value:  newValue,
 41		height: runtime.ChainHeight(),
 42	}
 43	history = append(history, c)
 44	if len(history) > maxHistory {
 45		history = history[len(history)-maxHistory:]
 46	}
 47	total++
 48	chain.Emit(
 49		"CounterChange",
 50		"delta", strconv.Itoa(delta),
 51		"value", strconv.Itoa(newValue),
 52	)
 53}
 54
 55// Inc adds one to the shared counter and logs the change.
 56func Inc(cur realm) int {
 57	value++
 58	record(1, value)
 59	return value
 60}
 61
 62// Dec subtracts one from the shared counter and logs the change.
 63func Dec(cur realm) int {
 64	value--
 65	record(-1, value)
 66	return value
 67}
 68
 69// Reset sets the shared counter back to zero and logs the change. The recorded
 70// delta is the amount required to bring the previous value to zero.
 71func Reset(cur realm) int {
 72	delta := -value
 73	value = 0
 74	record(delta, value)
 75	return value
 76}
 77
 78// Value returns the current counter value (read-only helper).
 79func Value() int {
 80	return value
 81}
 82
 83// Total returns the total number of mutations ever applied.
 84func Total() int {
 85	return total
 86}
 87
 88// Render produces a Markdown view: the big current value, the total number of
 89// changes, and a table of the most recent changes (newest first).
 90func Render(path string) string {
 91	var b strings.Builder
 92
 93	b.WriteString("# Counter Club\n\n")
 94	b.WriteString("A shared counter anyone can Inc, Dec, or Reset. ")
 95	b.WriteString("The last ")
 96	b.WriteString(strconv.Itoa(maxHistory))
 97	b.WriteString(" changes are logged below.\n\n")
 98
 99	// Big current value.
100	b.WriteString("## Current value\n\n")
101	b.WriteString("# ")
102	b.WriteString(strconv.Itoa(value))
103	b.WriteString("\n\n")
104
105	b.WriteString("**Total changes:** ")
106	b.WriteString(strconv.Itoa(total))
107	b.WriteString("\n\n")
108
109	// Recent history, newest first.
110	b.WriteString("## Recent history\n\n")
111	if len(history) == 0 {
112		b.WriteString("_No changes yet — be the first to count!_\n")
113		return b.String()
114	}
115
116	b.WriteString("| # | Caller | Delta | New value | Height |\n")
117	b.WriteString("|---|--------|-------|-----------|--------|\n")
118	n := len(history)
119	for i := n - 1; i >= 0; i-- {
120		c := history[i]
121		b.WriteString("| ")
122		b.WriteString(strconv.Itoa(n - i))
123		b.WriteString(" | ")
124		b.WriteString(c.caller.String())
125		b.WriteString(" | ")
126		b.WriteString(signed(c.delta))
127		b.WriteString(" | ")
128		b.WriteString(strconv.Itoa(c.value))
129		b.WriteString(" | ")
130		b.WriteString(strconv.FormatInt(c.height, 10))
131		b.WriteString(" |\n")
132	}
133
134	return b.String()
135}
136
137// signed formats an int with an explicit leading sign for non-negative values.
138func signed(n int) string {
139	if n >= 0 {
140		return "+" + strconv.Itoa(n)
141	}
142	return strconv.Itoa(n)
143}