PathrockNetwork Gno Explorer
HomeBlocksTransactionsRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/r/moul/x/daily/dice/v0

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
v0
Namespace
moul / x / daily / dice
Files
3 (README)(gnomod.toml)
Exported functions
5
Module
gno.land/r/moul/x/daily/dice/v0
gno
0.9

Files (3)

  • README.mdmarkdown
  • gnomod.tomltoml
  • dice.gnogno
dice.gnogno
1// Package dice implements a provably-fair on-chain dice game for gno.land.2//3// There is no true randomness on-chain: every node must reach the same result4// deterministically. Instead, each roll derives its 1-6 face from public block5// entropy (chain height) mixed with the caller address and the caller's roll6// count. The derivation is fully reproducible from public data, which is what7// "provably fair" means here — anyone can recompute a roll and verify it.8package dice910import (11	"chain"12	"chain/runtime"13	"strconv"14	"strings"1516	"gno.land/p/nt/avl/v0"17)1819// history holds every roll made by a single caller, most recent last.20type history struct {21	rolls []int // each value in [1,6]22}2324var (25	// count[i] is the total number of times face (i+1) has come up globally.26	count [6]int27	// total is the total number of rolls across all callers.28	total int29	// players maps caller address string -> *history (deterministic iteration).30	players = avl.NewTree()31)3233// deriveFace turns public entropy into a face in [1,6]. It is deterministic:34// the same (height, addr, n) always yields the same face, so any observer can35// recompute and verify a roll. Uses a simple FNV-1a-style hash over the mixed36// entropy bytes so different callers at the same height get different faces.37func deriveFace(height int64, addr string, n int) int {38	const (39		offset = uint64(1469598103934665603)40		prime  = uint64(1099511628211)41	)42	h := offset43	mix := func(v uint64) {44		for i := 0; i < 8; i++ {45			h ^= v & 0xff46			h *= prime47			v >>= 848		}49	}50	mix(uint64(height))51	mix(uint64(n))52	for i := 0; i < len(addr); i++ {53		h ^= uint64(addr[i])54		h *= prime55	}56	return int(h%6) + 157}5859// Roll performs one dice roll for the calling account and records it.60//61// It is a crossing function (gno 0.9 interrealm convention: `cur realm` first62// parameter). Callers invoke it as Roll(cross(cur)). The result is derived63// deterministically from the current block height, the caller address, and the64// caller's prior roll count — no stored secret, fully verifiable.65func Roll(cur realm) int {66	if !cur.IsCurrent() {67		panic("dice: spoofed realm value")68	}69	addr := cur.Previous().Address().String()7071	var h *history72	if v := players.Get(addr); v != nil {73		h = v.(*history)74	} else {75		h = &history{}76		players.Set(addr, h)77	}7879	face := deriveFace(runtime.ChainHeight(), addr, len(h.rolls))80	h.rolls = append(h.rolls, face)81	count[face-1]++82	total++8384	chain.Emit("Roll", "player", addr, "face", strconv.Itoa(face))85	return face86}8788// RollsOf returns the recorded roll history for an address (oldest first).89// Read-only helper, safe to call as a query.90func RollsOf(addr string) []int {91	v := players.Get(addr)92	if v == nil {93		return nil94	}95	out := v.(*history).rolls96	cp := make([]int, len(out))97	copy(cp, out)98	return cp99}100101// Total returns the global roll count.102func Total() int { return total }103104// Distribution returns the global per-face counts, faces 1-6.105func Distribution() [6]int { return count }106107// bar renders a proportional ▓/░ bar of fixed width for a face's share.108func bar(n, max, width int) string {109	if max <= 0 {110		return strings.Repeat("░", width)111	}112	filled := n * width / max113	if filled > width {114		filled = width115	}116	return strings.Repeat("▓", filled) + strings.Repeat("░", width-filled)117}118119// Render returns the realm's gnoweb Markdown view.120//121// Render is NOT a crossing function (no `cur realm` param) — it is a read-only122// query surface. It shows the total roll count, a distribution bar chart for123// faces 1-6, and the most recent rolls.124func Render(path string) string {125	var b strings.Builder126	b.WriteString("# 🎲 Provably-Fair Dice\n\n")127	b.WriteString("Every roll is derived deterministically from the block height, ")128	b.WriteString("the caller address, and their roll count — no hidden randomness, ")129	b.WriteString("fully reproducible from public data.\n\n")130131	b.WriteString("**Total rolls:** " + strconv.Itoa(total) + "\n\n")132133	// Distribution bar chart.134	b.WriteString("## Distribution\n\n")135	max := 0136	for _, c := range count {137		if c > max {138			max = c139		}140	}141	for face := 1; face <= 6; face++ {142		c := count[face-1]143		pct := 0144		if total > 0 {145			pct = c * 100 / total146		}147		b.WriteString("`" + strconv.Itoa(face) + "` ")148		b.WriteString(bar(c, max, 20))149		b.WriteString(" " + strconv.Itoa(c))150		b.WriteString(" (" + strconv.Itoa(pct) + "%)\n\n")151	}152153	// Recent rolls: walk players, collect last rolls, show most recent globally.154	b.WriteString("## Recent rolls\n\n")155	if total == 0 {156		b.WriteString("_No rolls yet. Call `Roll` to play._\n")157		return b.String()158	}159	type entry struct {160		addr string161		face int162	}163	recent := []entry{}164	players.Iterate("", "", func(key string, value interface{}) bool {165		h := value.(*history)166		// take up to the last 3 rolls of each player167		start := len(h.rolls) - 3168		if start < 0 {169			start = 0170		}171		for _, f := range h.rolls[start:] {172			recent = append(recent, entry{addr: key, face: f})173		}174		return false175	})176	// show at most the last 10 collected177	start := len(recent) - 10178	if start < 0 {179		start = 0180	}181	for _, e := range recent[start:] {182		short := e.addr183		if len(short) > 12 {184			short = short[:8] + "…" + short[len(short)-4:]185		}186		b.WriteString("- 🎲 **" + strconv.Itoa(e.face) + "** — `" + short + "`\n")187	}188	return b.String()189}190

Functions

  • Distribution() [6]int

  • Render(path string) string

  • Roll(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

  • RollsOf(addr string) []int

  • Total() int

Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.

Rendered

RenderedRawgnoweb ↗

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.