1// Package counter implements "Counter Club": a single shared integer counter2// with a rolling history of the last 20 mutations. Anyone may Inc, Dec, or3// Reset the value; every change records the caller, the delta applied, the4// resulting value, and the block height it happened at.5package counter67import (8 "chain"9 "chain/runtime"10 "chain/runtime/unsafe"11 "strconv"12 "strings"13)1415// maxHistory is the number of recent changes kept in the log.16const maxHistory = 201718// change is a single recorded mutation of the counter.19type change struct {20 caller address // who triggered the change21 delta int // how much the value moved (+1, -1, or reset amount)22 value int // the resulting counter value after the change23 height int64 // block height at which it occurred24}2526// value is the current shared counter.27var value int2829// total counts every mutation ever applied (not capped, unlike history).30var total int3132// history holds the last maxHistory changes, oldest first.33var history []change3435// 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}5455// Inc adds one to the shared counter and logs the change.56func Inc(cur realm) int {57 value++58 record(1, value)59 return value60}6162// Dec subtracts one from the shared counter and logs the change.63func Dec(cur realm) int {64 value--65 record(-1, value)66 return value67}6869// Reset sets the shared counter back to zero and logs the change. The recorded70// delta is the amount required to bring the previous value to zero.71func Reset(cur realm) int {72 delta := -value73 value = 074 record(delta, value)75 return value76}7778// Value returns the current counter value (read-only helper).79func Value() int {80 return value81}8283// Total returns the total number of mutations ever applied.84func Total() int {85 return total86}8788// Render produces a Markdown view: the big current value, the total number of89// changes, and a table of the most recent changes (newest first).90func Render(path string) string {91 var b strings.Builder9293 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")9899 // Big current value.100 b.WriteString("## Current value\n\n")101 b.WriteString("# ")102 b.WriteString(strconv.Itoa(value))103 b.WriteString("\n\n")104105 b.WriteString("**Total changes:** ")106 b.WriteString(strconv.Itoa(total))107 b.WriteString("\n\n")108109 // 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 }115116 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 }133134 return b.String()135}136137// 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}144Dec(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}) int
Inc(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}) int
Render(path string) string
Reset(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}) int
Total() int
Value() int
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.