PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

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/timecapsule/v0

Realm
Open in gnoweb ↗

Overview

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

Files (3)

  • README.mdmarkdown
  • gnomod.tomltoml
  • timecapsule.gnogno
timecapsule.gnogno
1// Package timecapsule is a public guestbook where every message is sealed2// until a future block height, then permanently unlocked for anyone to read.3package timecapsule45import (6	"strconv"7	"strings"89	"chain"10	"chain/runtime"1112	"gno.land/p/nt/avl/v0"13	"gno.land/p/nt/markdown/sanitize/v0"14)1516type capsule struct {17	id           int6418	author       address19	message      string20	createdAt    int6421	unlockHeight int6422}2324var (25	capsules avl.Tree // key: zero-padded id -> *capsule26	nextID   int6427)2829const (30	maxDelayBlocks int64 = 1_000_00031	maxMessageLen  int   = 50032)3334// Leave seals a new message that stays hidden until `delayBlocks` blocks35// from now, then becomes publicly readable forever. Returns the capsule id.36func Leave(cur realm, message string, delayBlocks int64) int64 {37	if !cur.Previous().IsUserCall() {38		panic("only direct user calls can leave a capsule")39	}4041	message = strings.TrimSpace(message)42	if message == "" {43		panic("message must not be empty")44	}45	if len(message) > maxMessageLen {46		panic("message too long")47	}48	if delayBlocks <= 0 || delayBlocks > maxDelayBlocks {49		panic("delayBlocks out of range")50	}5152	now := runtime.ChainHeight()53	id := nextID54	nextID++5556	c := &capsule{57		id:           id,58		author:       cur.Previous().Address(),59		message:      message,60		createdAt:    now,61		unlockHeight: now + delayBlocks,62	}63	capsules.Set(idKey(id), c)6465	chain.Emit("CapsuleSealed",66		"id", strconv.FormatInt(id, 10),67		"unlockHeight", strconv.FormatInt(c.unlockHeight, 10),68	)69	return id70}7172func idKey(id int64) string {73	s := strconv.FormatInt(id, 10)74	return strings.Repeat("0", 12-len(s)) + s75}7677func Render(path string) string {78	switch {79	case path == "":80		return renderHome()81	case path == "sealed":82		return renderSealed()83	case strings.HasPrefix(path, "capsule/"):84		return renderCapsule(strings.TrimPrefix(path, "capsule/"))85	default:86		return "> [!WARNING]\n> Path not found\n"87	}88}8990func renderHome() string {91	now := runtime.ChainHeight()9293	revealed := 094	sealed := 095	capsules.Iterate("", "", func(_ string, value any) bool {96		if value.(*capsule).unlockHeight <= now {97			revealed++98		} else {99			sealed++100		}101		return false102	})103104	var out strings.Builder105	out.WriteString("# ⏳ Time Capsule Guestbook\n\n")106	out.WriteString("Leave a message for the future. It stays sealed until its unlock block height, then anyone can read it — call `Leave(message, delayBlocks)`.\n\n")107	out.WriteString(strconv.Itoa(revealed+sealed) + " capsule(s) total · " +108		strconv.Itoa(revealed) + " unlocked · " + strconv.Itoa(sealed) + " still sealed")109	if sealed > 0 {110		out.WriteString(" (see [sealed](sealed))")111	}112	out.WriteString(".\n\n## Unlocked messages\n\n")113114	if revealed == 0 {115		out.WriteString("_None yet. Be the first to leave one that will open later._\n")116		return out.String()117	}118119	capsules.Iterate("", "", func(_ string, value any) bool {120		c := value.(*capsule)121		if c.unlockHeight <= now {122			out.WriteString(renderEntry(c))123		}124		return false125	})126	return out.String()127}128129func renderSealed() string {130	now := runtime.ChainHeight()131132	var out strings.Builder133	out.WriteString("# Sealed Capsules\n\n")134135	found := false136	capsules.Iterate("", "", func(_ string, value any) bool {137		c := value.(*capsule)138		if c.unlockHeight > now {139			found = true140			out.WriteString("- capsule [#" + strconv.FormatInt(c.id, 10) + "](capsule/" +141				strconv.FormatInt(c.id, 10) + ") by `" + c.author.String() +142				"` — unlocks at block " + strconv.FormatInt(c.unlockHeight, 10) +143				" (" + strconv.FormatInt(c.unlockHeight-now, 10) + " blocks left)\n")144		}145		return false146	})147	if !found {148		out.WriteString("_No sealed capsules right now._\n")149	}150	return out.String()151}152153func renderCapsule(idStr string) string {154	id, err := strconv.ParseInt(idStr, 10, 64)155	if err != nil {156		return "> [!WARNING]\n> Invalid capsule id\n"157	}158	v := capsules.Get(idKey(id))159	if v == nil {160		return "> [!WARNING]\n> Capsule not found\n"161	}162	c := v.(*capsule)163	now := runtime.ChainHeight()164165	var out strings.Builder166	out.WriteString("# Capsule #" + strconv.FormatInt(c.id, 10) + "\n\n")167	out.WriteString("Sealed by `" + c.author.String() + "` at block " + strconv.FormatInt(c.createdAt, 10) + ".\n\n")168169	if c.unlockHeight > now {170		out.WriteString("\U0001f512 Still sealed. Unlocks at block " + strconv.FormatInt(c.unlockHeight, 10) +171			" (" + strconv.FormatInt(c.unlockHeight-now, 10) + " blocks left).\n")172		return out.String()173	}174175	out.WriteString("\U0001f513 Unlocked at block " + strconv.FormatInt(c.unlockHeight, 10) + ":\n\n> " +176		sanitize.InlineText(c.message) + "\n")177	return out.String()178}179180func renderEntry(c *capsule) string {181	return "- **#" + strconv.FormatInt(c.id, 10) + "** by `" + c.author.String() +182		"` (sealed at block " + strconv.FormatInt(c.createdAt, 10) +183		", opened at block " + strconv.FormatInt(c.unlockHeight, 10) + "):\n  > " +184		sanitize.InlineText(c.message) + "\n\n"185}186

Functions

  • Leave(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}, message string, delayBlocks int64) int64

  • Render(path string) string

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.