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/g1qp5pt8cdq2f6kfdamn3yuxwg6quqnfpyewzz39/timelock_guardian

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
timelock_guardian
Namespace
g1qp5pt8cdq2f6kfdamn3yuxwg6quqnfpyewzz39
Files
3 (gnomod.toml)
Exported functions
15
Module
gno.land/r/g1qp5pt8cdq2f6kfdamn3yuxwg6quqnfpyewzz39/timelock_guardian
gno
0.9

Files (3)

  • gnomod.tomltoml
  • timelock_guardian.gnogno
  • timelock_guardian_test.gnogno
timelock_guardian_test.gnogno
1package timelock_guardian23import (4	"chain"5	"strings"6	"testing"78	"gno.land/p/nt/testutils/v0"9	"gno.land/p/nt/uassert/v0"10)1112var (13	owner    = testutils.TestAddress("owner")14	guardian = testutils.TestAddress("guardian")15	attacker = testutils.TestAddress("attacker")16	newOwner = testutils.TestAddress("newowner")17)1819// resetState resets all package-level state between tests.20func resetState() {21	targets = make(map[string]*TargetConfig)22	targetNames = []string{}23	ownerTargets = make(map[address]int)24	actions = make(map[string]*Action)25	actionIDs = []string{}26	pending = make(map[string][]string)27	pendingTargets = []string{}28	ptIndex = make(map[string]int)29	nextID = 130}3132// heights advancing time: SkipHeights moves the clock 5s per height.33func skipSeconds(sec int64) {34	testing.SkipHeights((sec + 4) / 5)35}3637func registerUpgrades(cur realm) string {38	testing.SetRealm(testing.NewUserRealm(owner))39	RegisterTarget(cross(cur), "upgrades", MinDelayFloor, guardian)40	return "upgrades"41}4243// ---------- RegisterTarget ----------4445func TestRegisterTarget_Basic(cur realm, t *testing.T) {46	resetState()47	testing.SetRealm(testing.NewUserRealm(owner))4849	RegisterTarget(cross(cur), "upgrades", 120, guardian)5051	tc := targets["upgrades"]52	uassert.Equal(t, string(owner), string(tc.Owner))53	uassert.Equal(t, string(guardian), string(tc.Guardian))54	uassert.Equal(t, int64(120), tc.MinDelay)55}5657func TestRegisterTarget_NoGuardianAllowed(cur realm, t *testing.T) {58	resetState()59	testing.SetRealm(testing.NewUserRealm(owner))6061	RegisterTarget(cross(cur), "plain", MinDelayFloor, "")62	uassert.Equal(t, "", string(targets["plain"].Guardian))63}6465func TestRegisterTarget_DuplicateRejected(cur realm, t *testing.T) {66	resetState()67	testing.SetRealm(testing.NewUserRealm(owner))68	registerUpgrades(cur)6970	uassert.AbortsWithMessage(t, cur,71		"target already registered: upgrades",72		func() { RegisterTarget(cross(cur), "upgrades", MinDelayFloor, "") },73	)74}7576func TestRegisterTarget_InvalidNameRejected(cur realm, t *testing.T) {77	resetState()78	testing.SetRealm(testing.NewUserRealm(owner))7980	for _, bad := range []string{"", "Upgrades", "has space", strings.Repeat("a", MaxTargetNameLen+1)} {81		uassert.AbortsContains(t, cur,82			"target name must be",83			func() { RegisterTarget(cross(cur), bad, MinDelayFloor, "") },84		)85	}86}8788func TestRegisterTarget_DelayBoundsEnforced(cur realm, t *testing.T) {89	resetState()90	testing.SetRealm(testing.NewUserRealm(owner))9192	uassert.AbortsContains(t, cur,93		"minimum delay must be at least",94		func() { RegisterTarget(cross(cur), "too_fast", MinDelayFloor-1, "") },95	)96	uassert.AbortsContains(t, cur,97		"minimum delay exceeds the maximum",98		func() { RegisterTarget(cross(cur), "too_slow", MaxDelay+1, "") },99	)100}101102func TestRegisterTarget_InvalidGuardianRejected(cur realm, t *testing.T) {103	resetState()104	testing.SetRealm(testing.NewUserRealm(owner))105106	uassert.AbortsWithMessage(t, cur,107		"invalid guardian address: junk",108		func() { RegisterTarget(cross(cur), "upgrades", MinDelayFloor, address("junk")) },109	)110}111112// ---------- SetGuardian / two-step TransferTargetOwnership ----------113114func TestSetGuardian_OwnerOnly(cur realm, t *testing.T) {115	resetState()116	testing.SetRealm(testing.NewUserRealm(owner))117	registerUpgrades(cur)118119	testing.SetRealm(testing.NewUserRealm(attacker))120	uassert.AbortsWithMessage(t, cur,121		"only the target owner can set the guardian",122		func() { SetGuardian(cross(cur), "upgrades", attacker) },123	)124125	testing.SetRealm(testing.NewUserRealm(owner))126	SetGuardian(cross(cur), "upgrades", "")127	uassert.Equal(t, "", string(targets["upgrades"].Guardian))128}129130func TestTransferTargetOwnership_TwoStep(cur realm, t *testing.T) {131	resetState()132	testing.SetRealm(testing.NewUserRealm(owner))133	registerUpgrades(cur)134135	testing.SetRealm(testing.NewUserRealm(attacker))136	uassert.AbortsWithMessage(t, cur,137		"only the target owner can transfer ownership",138		func() { TransferTargetOwnership(cross(cur), "upgrades", attacker) },139	)140141	testing.SetRealm(testing.NewUserRealm(owner))142	uassert.AbortsWithMessage(t, cur,143		"invalid new owner address: junk",144		func() { TransferTargetOwnership(cross(cur), "upgrades", address("junk")) },145	)146147	uassert.AbortsWithMessage(t, cur,148		"new owner is already the owner",149		func() { TransferTargetOwnership(cross(cur), "upgrades", owner) },150	)151152	// the offer alone changes nothing153	TransferTargetOwnership(cross(cur), "upgrades", newOwner)154	uassert.Equal(t, string(owner), string(targets["upgrades"].Owner))155	uassert.Equal(t, string(newOwner), string(targets["upgrades"].PendingOwner))156	uassert.Equal(t, 1, ownerTargets[owner])157	uassert.Equal(t, 0, ownerTargets[newOwner])158159	// only the nominee can accept160	testing.SetRealm(testing.NewUserRealm(attacker))161	uassert.AbortsWithMessage(t, cur,162		"caller is not the pending owner",163		func() { AcceptTargetOwnership(cross(cur), "upgrades") },164	)165166	testing.SetRealm(testing.NewUserRealm(newOwner))167	AcceptTargetOwnership(cross(cur), "upgrades")168	uassert.Equal(t, string(newOwner), string(targets["upgrades"].Owner))169	uassert.Equal(t, "", string(targets["upgrades"].PendingOwner))170	uassert.Equal(t, 0, ownerTargets[owner])171	uassert.Equal(t, 1, ownerTargets[newOwner])172}173174func TestTransferTargetOwnership_ClearOffer(cur realm, t *testing.T) {175	resetState()176	testing.SetRealm(testing.NewUserRealm(owner))177	registerUpgrades(cur)178179	TransferTargetOwnership(cross(cur), "upgrades", newOwner)180	TransferTargetOwnership(cross(cur), "upgrades", "") // clear181182	testing.SetRealm(testing.NewUserRealm(newOwner))183	uassert.AbortsWithMessage(t, cur,184		"caller is not the pending owner",185		func() { AcceptTargetOwnership(cross(cur), "upgrades") },186	)187}188189func TestTransferTargetOwnership_QuotaCheckedAtAccept(cur realm, t *testing.T) {190	resetState()191	testing.SetRealm(testing.NewUserRealm(newOwner))192	for i := 0; i < MaxTargetsPerOwner; i++ {193		RegisterTarget(cross(cur), "t_"+strings.Repeat("x", i+1), MinDelayFloor, "")194	}195196	testing.SetRealm(testing.NewUserRealm(owner))197	registerUpgrades(cur)198	TransferTargetOwnership(cross(cur), "upgrades", newOwner) // offer succeeds199200	// ...but accepting past the quota is refused, and ownership is unchanged201	testing.SetRealm(testing.NewUserRealm(newOwner))202	uassert.AbortsWithMessage(t, cur,203		"accepting would exceed the per-owner target limit",204		func() { AcceptTargetOwnership(cross(cur), "upgrades") },205	)206	uassert.Equal(t, string(owner), string(targets["upgrades"].Owner))207}208209func TestUnsolicitedOfferConsumesNothing(cur realm, t *testing.T) {210	resetState()211	victim := testutils.TestAddress("victim")212213	// fix Y5 regression: an attacker offering targets to a victim must214	// not consume the victim's quota or change any of their state215	testing.SetRealm(testing.NewUserRealm(attacker))216	for i := 0; i < MaxTargetsPerOwner; i++ {217		name := "junk_" + strings.Repeat("x", i+1)218		RegisterTarget(cross(cur), name, MinDelayFloor, "")219		TransferTargetOwnership(cross(cur), name, victim)220	}221	uassert.Equal(t, 0, ownerTargets[victim])222223	// the victim can still register a full quota of their own targets224	testing.SetRealm(testing.NewUserRealm(victim))225	for i := 0; i < MaxTargetsPerOwner; i++ {226		RegisterTarget(cross(cur), "mine_"+strings.Repeat("y", i+1), MinDelayFloor, "")227	}228}229230// ---------- Schedule ----------231232func TestSchedule_OwnerOnly(cur realm, t *testing.T) {233	resetState()234	testing.SetRealm(testing.NewUserRealm(owner))235	registerUpgrades(cur)236237	// an attacker cannot schedule an action against someone else's238	// target — the core binding the audit found missing239	testing.SetRealm(testing.NewUserRealm(attacker))240	uassert.AbortsWithMessage(t, cur,241		"only the target owner can schedule actions for upgrades",242		func() { Schedule(cross(cur), "upgrades", "malicious upgrade", MinDelayFloor) },243	)244}245246func TestSchedule_UnregisteredTargetRejected(cur realm, t *testing.T) {247	resetState()248	testing.SetRealm(testing.NewUserRealm(owner))249250	uassert.AbortsWithMessage(t, cur,251		"target not found: ghost",252		func() { Schedule(cross(cur), "ghost", "data", MinDelayFloor) },253	)254}255256func TestSchedule_MinDelayEnforced(cur realm, t *testing.T) {257	resetState()258	testing.SetRealm(testing.NewUserRealm(owner))259	RegisterTarget(cross(cur), "upgrades", 3600, "")260261	// a delay below the target's registered minimum is rejected — no262	// more 1-second "timelocks"263	uassert.AbortsWithMessage(t, cur,264		"delay below the target's minimum of 3600 seconds",265		func() { Schedule(cross(cur), "upgrades", "data", 60) },266	)267}268269func TestSchedule_MaxDelayEnforced(cur realm, t *testing.T) {270	resetState()271	testing.SetRealm(testing.NewUserRealm(owner))272	registerUpgrades(cur)273274	// overflow regression: a delay past MaxDelay must abort, never wrap275	// ExecuteAfter into the past276	uassert.AbortsContains(t, cur,277		"delay exceeds the maximum",278		func() { Schedule(cross(cur), "upgrades", "data", MaxDelay+1) },279	)280}281282func TestSchedule_DataValidation(cur realm, t *testing.T) {283	resetState()284	testing.SetRealm(testing.NewUserRealm(owner))285	registerUpgrades(cur)286287	uassert.AbortsWithMessage(t, cur,288		"data must not be empty",289		func() { Schedule(cross(cur), "upgrades", "", MinDelayFloor) },290	)291	uassert.AbortsContains(t, cur,292		"data exceeds",293		func() { Schedule(cross(cur), "upgrades", strings.Repeat("x", MaxDataLen+1), MinDelayFloor) },294	)295}296297func TestSchedule_PendingCap(cur realm, t *testing.T) {298	resetState()299	testing.SetRealm(testing.NewUserRealm(owner))300	registerUpgrades(cur)301302	for i := 0; i < MaxPendingPerTarget; i++ {303		Schedule(cross(cur), "upgrades", "op", MinDelayFloor)304	}305	uassert.AbortsWithMessage(t, cur,306		"too many pending actions for target upgrades",307		func() { Schedule(cross(cur), "upgrades", "op", MinDelayFloor) },308	)309}310311func TestSchedule_SetsWindows(cur realm, t *testing.T) {312	resetState()313	testing.SetRealm(testing.NewUserRealm(owner))314	registerUpgrades(cur)315316	id := Schedule(cross(cur), "upgrades", "rotate keys", 120)317	a := actions[id]318	uassert.Equal(t, int64(120), int64(a.ExecuteAfter.Sub(a.ScheduledAt).Seconds()))319	uassert.Equal(t, GracePeriod, int64(a.ExpiresAt.Sub(a.ExecuteAfter).Seconds()))320}321322// ---------- Execute ----------323324func TestExecute_TooEarlyBlocked(cur realm, t *testing.T) {325	resetState()326	testing.SetRealm(testing.NewUserRealm(owner))327	registerUpgrades(cur)328	id := Schedule(cross(cur), "upgrades", "op", MinDelayFloor)329330	uassert.AbortsContains(t, cur, "too early", func() { Execute(cross(cur), id) })331	uassert.False(t, IsReady(id), "must not be ready before the delay")332}333334func TestExecute_ReadyAfterDelay_AnyoneCanExecute(cur realm, t *testing.T) {335	resetState()336	testing.SetRealm(testing.NewUserRealm(owner))337	registerUpgrades(cur)338	id := Schedule(cross(cur), "upgrades", "op", MinDelayFloor)339340	skipSeconds(MinDelayFloor)341	uassert.True(t, IsReady(id), "must be ready after the delay")342343	// executor identity is deliberately unrestricted344	testing.SetRealm(testing.NewUserRealm(attacker))345	uassert.Equal(t, "executed: "+id, Execute(cross(cur), id))346	uassert.True(t, IsExecuted(id), "must record execution")347}348349func TestExecute_TwiceBlocked(cur realm, t *testing.T) {350	resetState()351	testing.SetRealm(testing.NewUserRealm(owner))352	registerUpgrades(cur)353	id := Schedule(cross(cur), "upgrades", "op", MinDelayFloor)354	skipSeconds(MinDelayFloor)355	Execute(cross(cur), id)356357	uassert.AbortsWithMessage(t, cur, "action already executed", func() { Execute(cross(cur), id) })358}359360func TestExecute_ExpiredBlocked(cur realm, t *testing.T) {361	resetState()362	testing.SetRealm(testing.NewUserRealm(owner))363	registerUpgrades(cur)364	id := Schedule(cross(cur), "upgrades", "op", MinDelayFloor)365366	// travel past the grace window: stale actions cannot be sprung later367	skipSeconds(MinDelayFloor + GracePeriod + 10)368	uassert.False(t, IsReady(id), "expired action must not be ready")369	uassert.AbortsContains(t, cur, "action expired", func() { Execute(cross(cur), id) })370	uassert.Equal(t, "none", GetPending())371}372373// ---------- Cancel / Veto ----------374375func TestCancel_CurrentOwnerOnly(cur realm, t *testing.T) {376	resetState()377	testing.SetRealm(testing.NewUserRealm(owner))378	registerUpgrades(cur)379	id := Schedule(cross(cur), "upgrades", "op", MinDelayFloor)380381	testing.SetRealm(testing.NewUserRealm(attacker))382	uassert.AbortsWithMessage(t, cur,383		"only the target owner can cancel",384		func() { Cancel(cross(cur), id) },385	)386387	testing.SetRealm(testing.NewUserRealm(owner))388	uassert.Equal(t, "cancelled: "+id, Cancel(cross(cur), id))389	_, present := actions[id]390	uassert.False(t, present, "cancelled action must be reaped from state")391392	// re-audit P3: after an ownership transfer the SCHEDULING creator393	// loses cancel rights; only the current owner holds them394	id2 := Schedule(cross(cur), "upgrades", "op2", MinDelayFloor)395	TransferTargetOwnership(cross(cur), "upgrades", newOwner)396	testing.SetRealm(testing.NewUserRealm(newOwner))397	AcceptTargetOwnership(cross(cur), "upgrades")398	testing.SetRealm(testing.NewUserRealm(owner))399	uassert.AbortsWithMessage(t, cur,400		"only the target owner can cancel",401		func() { Cancel(cross(cur), id2) },402	)403	testing.SetRealm(testing.NewUserRealm(newOwner))404	uassert.Equal(t, "cancelled: "+id2, Cancel(cross(cur), id2))405}406407func TestCancel_ExecutedBlocked(cur realm, t *testing.T) {408	resetState()409	testing.SetRealm(testing.NewUserRealm(owner))410	registerUpgrades(cur)411	id := Schedule(cross(cur), "upgrades", "op", MinDelayFloor)412	skipSeconds(MinDelayFloor)413	Execute(cross(cur), id)414415	uassert.AbortsWithMessage(t, cur,416		"cannot cancel an already-executed action",417		func() { Cancel(cross(cur), id) },418	)419}420421func TestVeto_GuardianOnly(cur realm, t *testing.T) {422	resetState()423	testing.SetRealm(testing.NewUserRealm(owner))424	registerUpgrades(cur)425	id := Schedule(cross(cur), "upgrades", "op", MinDelayFloor)426427	testing.SetRealm(testing.NewUserRealm(attacker))428	uassert.AbortsWithMessage(t, cur,429		"only the target guardian can veto",430		func() { Veto(cross(cur), id) },431	)432433	testing.SetRealm(testing.NewUserRealm(guardian))434	uassert.Equal(t, "vetoed: "+id, Veto(cross(cur), id))435	_, present := actions[id]436	uassert.False(t, present, "vetoed action must be reaped from state")437438	// a vetoed action can never execute439	skipSeconds(MinDelayFloor)440	uassert.AbortsWithMessage(t, cur, "action not found: "+id, func() { Execute(cross(cur), id) })441}442443func TestVeto_NoGuardianTargetBlocked(cur realm, t *testing.T) {444	resetState()445	testing.SetRealm(testing.NewUserRealm(owner))446	RegisterTarget(cross(cur), "plain", MinDelayFloor, "")447	id := Schedule(cross(cur), "plain", "op", MinDelayFloor)448449	testing.SetRealm(testing.NewUserRealm(guardian))450	uassert.AbortsWithMessage(t, cur,451		"target has no guardian: plain",452		func() { Veto(cross(cur), id) },453	)454}455456// ---------- Expire (fix Y2) ----------457458func TestExpire_PermissionlessRecovery(cur realm, t *testing.T) {459	resetState()460	testing.SetRealm(testing.NewUserRealm(owner))461	registerUpgrades(cur)462463	// fill the target's quota, then let everything expire464	var ids []string465	for i := 0; i < MaxPendingPerTarget; i++ {466		ids = append(ids, Schedule(cross(cur), "upgrades", "op", MinDelayFloor))467	}468	skipSeconds(MinDelayFloor + GracePeriod + 10)469470	// fix Y2 regression: ANYONE — not just a lucky sweep window — can471	// reap a provably expired action and free the slot it wedges472	testing.SetRealm(testing.NewUserRealm(attacker))473	uassert.Equal(t, "expired: "+ids[0], Expire(cross(cur), ids[0]))474	_, present := actions[ids[0]]475	uassert.False(t, present, "expired action must be reaped from state")476477	// reap the rest as the owner; quota and SetGuardian both recover478	testing.SetRealm(testing.NewUserRealm(owner))479	for _, id := range ids[1:] {480		Expire(cross(cur), id)481	}482	uassert.Equal(t, 0, pendingCount("upgrades"))483	SetGuardian(cross(cur), "upgrades", "") // no longer blocked484	Schedule(cross(cur), "upgrades", "fresh", MinDelayFloor)485}486487func TestExpire_RefusesLiveAndExecuted(cur realm, t *testing.T) {488	resetState()489	testing.SetRealm(testing.NewUserRealm(owner))490	registerUpgrades(cur)491	live := Schedule(cross(cur), "upgrades", "live", MinDelayFloor)492	done := Schedule(cross(cur), "upgrades", "done", MinDelayFloor)493	skipSeconds(MinDelayFloor)494	Execute(cross(cur), done)495496	uassert.AbortsWithMessage(t, cur, "action is not expired",497		func() { Expire(cross(cur), live) })498	uassert.AbortsWithMessage(t, cur, "action already executed",499		func() { Expire(cross(cur), done) })500	uassert.AbortsWithMessage(t, cur, "action not found: ghost",501		func() { Expire(cross(cur), "ghost") })502}503504// ---------- stray sends (fix Y6) ----------505506func TestStraySendRejectedEverywhere(cur realm, t *testing.T) {507	resetState()508	testing.SetRealm(testing.NewUserRealm(owner))509	registerUpgrades(cur)510	id := Schedule(cross(cur), "upgrades", "op", MinDelayFloor)511512	// fix Y6 regression: this realm holds no banker, so an attached513	// send would strand on the realm address forever — every crossing514	// function must abort it (the abort reverts the transfer)515	msg := "this realm does not accept coins"516	testing.SetOriginSend(chain.Coins{{Denom: "ugnot", Amount: 5}})517	uassert.AbortsWithMessage(t, cur, msg, func() { RegisterTarget(cross(cur), "paid", MinDelayFloor, "") })518	uassert.AbortsWithMessage(t, cur, msg, func() { Schedule(cross(cur), "upgrades", "op2", MinDelayFloor) })519	uassert.AbortsWithMessage(t, cur, msg, func() { Cancel(cross(cur), id) })520	uassert.AbortsWithMessage(t, cur, msg, func() { SetGuardian(cross(cur), "upgrades", "") })521	uassert.AbortsWithMessage(t, cur, msg, func() { TransferTargetOwnership(cross(cur), "upgrades", newOwner) })522	uassert.AbortsWithMessage(t, cur, msg, func() { AcceptTargetOwnership(cross(cur), "upgrades") })523	uassert.AbortsWithMessage(t, cur, msg, func() { Veto(cross(cur), id) })524	uassert.AbortsWithMessage(t, cur, msg, func() { Expire(cross(cur), id) })525	// SkipHeights resets the test context (wiping the send envelope),526	// so re-arm it before probing the ready-action Execute path527	skipSeconds(MinDelayFloor)528	testing.SetRealm(testing.NewUserRealm(owner))529	testing.SetOriginSend(chain.Coins{{Denom: "ugnot", Amount: 5}})530	uassert.AbortsWithMessage(t, cur, msg, func() { Execute(cross(cur), id) })531	testing.SetOriginSend(nil)532533	// without coins the same call succeeds534	uassert.Equal(t, "executed: "+id, Execute(cross(cur), id))535}536537// ---------- queries + render ----------538539func TestGetPending_ExcludesFinished(cur realm, t *testing.T) {540	resetState()541	testing.SetRealm(testing.NewUserRealm(owner))542	registerUpgrades(cur)543	id1 := Schedule(cross(cur), "upgrades", "op1", MinDelayFloor)544	id2 := Schedule(cross(cur), "upgrades", "op2", MinDelayFloor)545	id3 := Schedule(cross(cur), "upgrades", "op3", MinDelayFloor)546547	Cancel(cross(cur), id2)548	skipSeconds(MinDelayFloor)549	Execute(cross(cur), id1)550551	uassert.Equal(t, id3, GetPending())552}553554func TestGetPending_GroupedByTarget(cur realm, t *testing.T) {555	resetState()556	testing.SetRealm(testing.NewUserRealm(owner))557	RegisterTarget(cross(cur), "alpha", MinDelayFloor, "")558	RegisterTarget(cross(cur), "beta", MinDelayFloor, "")559560	// interleave scheduling across targets; output groups by target in561	// registration order (fix Y4 bookkeeping), insertion-ordered within562	a1 := Schedule(cross(cur), "alpha", "a1", MinDelayFloor)563	b1 := Schedule(cross(cur), "beta", "b1", MinDelayFloor)564	a2 := Schedule(cross(cur), "alpha", "a2", MinDelayFloor)565566	uassert.Equal(t, a1+", "+a2+", "+b1, GetPending())567	uassert.Equal(t, 2, pendingCount("alpha"))568	uassert.Equal(t, 1, pendingCount("beta"))569570	Cancel(cross(cur), a1)571	uassert.Equal(t, a2+", "+b1, GetPending())572	uassert.Equal(t, 1, pendingCount("alpha"))573}574575func TestGetTarget_Summary(cur realm, t *testing.T) {576	resetState()577	testing.SetRealm(testing.NewUserRealm(owner))578	registerUpgrades(cur)579580	out := GetTarget("upgrades")581	uassert.True(t, strings.Contains(out, string(owner)), "must show owner")582	uassert.True(t, strings.Contains(out, string(guardian)), "must show guardian")583	uassert.True(t, strings.Contains(out, "Min delay: 60s"), "must show min delay")584585	TransferTargetOwnership(cross(cur), "upgrades", newOwner)586	uassert.True(t, strings.Contains(GetTarget("upgrades"), "Pending owner: "+string(newOwner)),587		"must show a pending ownership offer")588}589590func TestRender_SanitizesInjection(cur realm, t *testing.T) {591	resetState()592	testing.SetRealm(testing.NewUserRealm(owner))593	registerUpgrades(cur)594	Schedule(cross(cur), "upgrades", "evil` | injected\nrow", MinDelayFloor)595596	out := Render("")597	uassert.False(t, strings.Contains(out, "evil`"), "backticks must be sanitized")598	uassert.False(t, strings.Contains(out, "injected\nrow"), "newlines must be sanitized")599}600601func TestRender_SanitizesHTMLBrackets(cur realm, t *testing.T) {602	resetState()603	testing.SetRealm(testing.NewUserRealm(owner))604	registerUpgrades(cur)605	// fix Y3 regression: raw HTML must never reach the page606	Schedule(cross(cur), "upgrades", "<script>alert(1)</script>", MinDelayFloor)607608	out := Render("")609	uassert.False(t, strings.Contains(out, "<script"), "script tags must be sanitized in Render")610	uassert.False(t, strings.Contains(out, "</script"), "closing tags must be sanitized in Render")611	one := GetAction(GetPending())612	uassert.False(t, strings.Contains(one, "<script"), "script tags must be sanitized in GetAction")613}614615func TestRender_EmptyState(cur realm, t *testing.T) {616	resetState()617	uassert.Equal(t, "# Timelock Guardian\n\nNo actions scheduled.\n", Render(""))618}619620func TestRender_Sections(cur realm, t *testing.T) {621	resetState()622	testing.SetRealm(testing.NewUserRealm(owner))623	registerUpgrades(cur)624	id1 := Schedule(cross(cur), "upgrades", "op1", MinDelayFloor)625	id2 := Schedule(cross(cur), "upgrades", "op2", MinDelayFloor)626	Schedule(cross(cur), "upgrades", "op3", MinDelayFloor)627	skipSeconds(MinDelayFloor)628	Execute(cross(cur), id1)629	Cancel(cross(cur), id2)630631	out := Render("")632	uassert.True(t, strings.Contains(out, "## Executed (1)"), "executed section")633	uassert.True(t, strings.Contains(out, "## Pending (1)"), "pending section")634	uassert.False(t, strings.Contains(out, "Cancelled"), "cancelled actions are reaped, not rendered")635}636637// ---------- re-audit regressions (2026-09-02) ----------638639func TestScheduleCancelCycling_CannotBrickTheRealm(cur realm, t *testing.T) {640	resetState()641	testing.SetRealm(testing.NewUserRealm(owner))642	registerUpgrades(cur)643644	// re-audit P1: the old lifetime cap could be consumed forever by645	// schedule+cancel cycling; the cap now bounds LIVE actions and646	// cancelled records are reaped, so heavy cycling leaves no residue647	for i := 0; i < 3*MaxPendingPerTarget; i++ {648		id := Schedule(cross(cur), "upgrades", "op", MinDelayFloor)649		Cancel(cross(cur), id)650	}651	uassert.Equal(t, 0, len(actions), "cycling must leave no state residue")652	uassert.Equal(t, 0, pendingCount("upgrades"), "no live actions after cycling")653	Schedule(cross(cur), "upgrades", "op", MinDelayFloor) // must not abort654}655656func TestSetGuardian_BlockedWhilePending(cur realm, t *testing.T) {657	resetState()658	testing.SetRealm(testing.NewUserRealm(owner))659	registerUpgrades(cur)660	id := Schedule(cross(cur), "upgrades", "rug", MinDelayFloor)661662	// re-audit P2: the owner must not be able to strip the guardian663	// during the delay window the guardian exists to police664	uassert.AbortsWithMessage(t, cur,665		"cannot change the guardian while actions are pending",666		func() { SetGuardian(cross(cur), "upgrades", "") },667	)668669	// once nothing is pending, the owner may change the guardian670	Cancel(cross(cur), id)671	SetGuardian(cross(cur), "upgrades", "")672	uassert.Equal(t, "", string(targets["upgrades"].Guardian))673}674675func TestVetoAndCancel_RefuseExpired(cur realm, t *testing.T) {676	resetState()677	testing.SetRealm(testing.NewUserRealm(owner))678	registerUpgrades(cur)679	id := Schedule(cross(cur), "upgrades", "op", MinDelayFloor)680	skipSeconds(MinDelayFloor + GracePeriod + 10)681682	// re-audit P3: terminal-state writes on expired actions rewrote683	// history; both must refuse and point at the Expire valve684	uassert.AbortsWithMessage(t, cur, "action expired: nothing to cancel (use Expire)",685		func() { Cancel(cross(cur), id) })686	testing.SetRealm(testing.NewUserRealm(guardian))687	uassert.AbortsWithMessage(t, cur, "action expired: nothing to veto (use Expire)",688		func() { Veto(cross(cur), id) })689}690691func TestExpiredActions_ReapedOnSchedule(cur realm, t *testing.T) {692	resetState()693	testing.SetRealm(testing.NewUserRealm(owner))694	registerUpgrades(cur)695	Schedule(cross(cur), "upgrades", "op", MinDelayFloor)696	skipSeconds(MinDelayFloor + GracePeriod + 10)697698	// the next Schedule sweeps expired actions out of state699	Schedule(cross(cur), "upgrades", "op2", MinDelayFloor)700	uassert.Equal(t, 1, len(actions), "expired action must be reaped by the sweep")701}702703func TestRender_LinkInjectionSanitized(cur realm, t *testing.T) {704	resetState()705	testing.SetRealm(testing.NewUserRealm(owner))706	registerUpgrades(cur)707	Schedule(cross(cur), "upgrades", "[approve](https://evil.example)", MinDelayFloor)708709	out := Render("")710	uassert.False(t, strings.Contains(out, "[approve]"), "link syntax must be sanitized")711}712713func TestPerOwnerTargetCap(cur realm, t *testing.T) {714	resetState()715	testing.SetRealm(testing.NewUserRealm(owner))716	for i := 0; i < MaxTargetsPerOwner; i++ {717		RegisterTarget(cross(cur), "t_"+strings.Repeat("x", i+1), MinDelayFloor, "")718	}719	uassert.AbortsWithMessage(t, cur,720		"per-owner target limit reached",721		func() { RegisterTarget(cross(cur), "one_more", MinDelayFloor, "") },722	)723}724725// ---------- round-3 audit regressions (2026-09-02) ----------726727func TestSybilsCannotExhaustSharedCapacity(cur realm, t *testing.T) {728	resetState()729730	// round-3 P1: two attackers filling their OWN per-owner quotas must731	// never block a third owner's Schedule — there is no shared cap left732	// to exhaust733	sybils := []address{testutils.TestAddress("sybil_a"), testutils.TestAddress("sybil_b")}734	for _, syb := range sybils {735		testing.SetRealm(testing.NewUserRealm(syb))736		for i := 0; i < MaxTargetsPerOwner; i++ {737			name := "t_" + string(syb[len(syb)-4:]) + "_" + strings.Repeat("x", i+1)738			RegisterTarget(cross(cur), name, MinDelayFloor, "")739			for j := 0; j < MaxPendingPerTarget; j++ {740				Schedule(cross(cur), name, "spam", MaxDelay) // 10y delay: sweep reclaims nothing741			}742		}743	}744745	// a legitimate owner is entirely unaffected746	testing.SetRealm(testing.NewUserRealm(owner))747	RegisterTarget(cross(cur), "legit", MinDelayFloor, "")748	Schedule(cross(cur), "legit", "real work", MinDelayFloor) // must not abort749}750751func TestVictimRecoversBehindSybilWall(cur realm, t *testing.T) {752	resetState()753754	// fix Y2/Y4 regression — the exact starvation case the old global755	// budget-windowed sweep could not recover from: a wall of long-delay756	// sybil actions in front, a victim whose actions expired behind it.757	// Per-target sweeps and permissionless Expire make recovery local.758	syb := testutils.TestAddress("wall")759	testing.SetRealm(testing.NewUserRealm(syb))760	for i := 0; i < 5; i++ {761		name := "wall_" + strings.Repeat("w", i+1)762		RegisterTarget(cross(cur), name, MinDelayFloor, "")763		for j := 0; j < MaxPendingPerTarget; j++ {764			Schedule(cross(cur), name, "wall", MaxDelay) // 100 live 10y entries765		}766	}767768	victim := testutils.TestAddress("victim2")769	testing.SetRealm(testing.NewUserRealm(victim))770	RegisterTarget(cross(cur), "vt", MinDelayFloor, guardian)771	var ids []string772	for j := 0; j < MaxPendingPerTarget; j++ {773		ids = append(ids, Schedule(cross(cur), "vt", "op", MinDelayFloor))774	}775	skipSeconds(MinDelayFloor + GracePeriod + 10) // all 20 expire776777	// the victim's own next Schedule sweeps THEIR target despite the wall778	Schedule(cross(cur), "vt", "recovered", MinDelayFloor)779	uassert.Equal(t, 1, pendingCount("vt"), "expired actions swept despite the sybil wall")780781	// and Expire frees a wedged slot directly, from any key782	id2 := Schedule(cross(cur), "vt", "will expire", MinDelayFloor)783	testing.SetRealm(testing.NewUserRealm(attacker))784	skipSeconds(MinDelayFloor + GracePeriod + 10)785	Expire(cross(cur), id2)786	_, present := actions[id2]787	uassert.False(t, present, "Expire must reap regardless of global queue position")788}789790func TestPendingCounterConsistency(cur realm, t *testing.T) {791	resetState()792	testing.SetRealm(testing.NewUserRealm(owner))793	registerUpgrades(cur)794795	id1 := Schedule(cross(cur), "upgrades", "a", MinDelayFloor)796	id2 := Schedule(cross(cur), "upgrades", "b", MinDelayFloor)797	Schedule(cross(cur), "upgrades", "c", MinDelayFloor)798	uassert.Equal(t, 3, pendingCount("upgrades"))799800	Cancel(cross(cur), id1)801	uassert.Equal(t, 2, pendingCount("upgrades"))802	skipSeconds(MinDelayFloor)803	Execute(cross(cur), id2)804	uassert.Equal(t, 1, pendingCount("upgrades"))805806	// expiry: the count drops when the sweep reaps807	skipSeconds(GracePeriod + 10)808	Schedule(cross(cur), "upgrades", "d", MinDelayFloor) // triggers sweep of expired "c"809	uassert.Equal(t, 1, pendingCount("upgrades"))810}811812func TestSanitize_EmphasisMarkers(cur realm, t *testing.T) {813	resetState()814	testing.SetRealm(testing.NewUserRealm(owner))815	registerUpgrades(cur)816	Schedule(cross(cur), "upgrades", "**ready** _now_", MinDelayFloor)817818	out := Render("")819	uassert.False(t, strings.Contains(out, "**ready** _now_"),820		"emphasis markers in Data must be sanitized")821}822823// ---------- render-index bounds (fix Y4) ----------824825func TestRenderIndexSelfTrims(cur realm, t *testing.T) {826	resetState()827	testing.SetRealm(testing.NewUserRealm(owner))828	RegisterTarget(cross(cur), "churn", MinDelayFloor, "")829830	// execute many actions so actionIDs would grow unboundedly without831	// the trim; the index must stay within RenderIndexCap and old832	// executed records must stay queryable via the map reads833	var first string834	for i := 0; i < RenderIndexCap+30; i++ {835		id := Schedule(cross(cur), "churn", "op", MinDelayFloor)836		if i == 0 {837			first = id838		}839		skipSeconds(MinDelayFloor)840		Execute(cross(cur), id)841	}842	uassert.True(t, len(actionIDs) <= RenderIndexCap, "render index must self-trim")843	uassert.True(t, IsExecuted(first), "trimmed records stay queryable forever")844	uassert.True(t, strings.Contains(GetAction(first), "Status: executed"),845		"GetAction must still serve trimmed records")846}847848// ---------- round-2 audit regressions ----------849850func TestSetGuardian_SweepsExpiredFirst(cur realm, t *testing.T) {851	resetState()852	testing.SetRealm(testing.NewUserRealm(owner))853	registerUpgrades(cur)854	Schedule(cross(cur), "upgrades", "op", MinDelayFloor)855	skipSeconds(MinDelayFloor + GracePeriod + 10)856857	// round-2 hardening: expired-but-unswept actions protect nothing858	// and must not block a guardian rotation859	SetGuardian(cross(cur), "upgrades", "")860	uassert.Equal(t, "", string(targets["upgrades"].Guardian))861	uassert.Equal(t, 0, pendingCount("upgrades"), "the gate sweep must reap expired actions")862}863864func TestRenderShowsPendingDespiteChurn(cur realm, t *testing.T) {865	resetState()866	testing.SetRealm(testing.NewUserRealm(owner))867	RegisterTarget(cross(cur), "vis", MinDelayFloor, "")868	watched := Schedule(cross(cur), "vis", "watched rug", 2*(MinDelayFloor+5*(RenderIndexCap+30)))869870	// round-2 fix Y-2: flood the render index with executed churn; the871	// live pending action must remain visible for its whole window872	RegisterTarget(cross(cur), "churn2", MinDelayFloor, "")873	for i := 0; i < RenderIndexCap+30; i++ {874		id := Schedule(cross(cur), "churn2", "noise", MinDelayFloor)875		skipSeconds(MinDelayFloor)876		Execute(cross(cur), id)877	}878879	out := Render("")880	uassert.True(t, strings.Contains(out, watched), "a live pending action must survive render-index churn")881	uassert.True(t, strings.Contains(out, "## Pending (1)"), "pending section from live lists")882883	// and state stays consistent for an action trimmed out of the884	// render index: Cancel still works (absent-id removeID is a no-op)885	uassert.Equal(t, "cancelled: "+watched, Cancel(cross(cur), watched))886	uassert.Equal(t, 0, pendingCount("vis"))887}888889func TestPendingTargetsBookkeeping(cur realm, t *testing.T) {890	resetState()891	testing.SetRealm(testing.NewUserRealm(owner))892	RegisterTarget(cross(cur), "one", MinDelayFloor, "")893	RegisterTarget(cross(cur), "two", MinDelayFloor, "")894895	// round-2 fix Y-1: only targets with live pendings are tracked896	uassert.Equal(t, 0, len(pendingTargets))897	a1 := Schedule(cross(cur), "one", "a", MinDelayFloor)898	Schedule(cross(cur), "two", "b", MinDelayFloor)899	uassert.Equal(t, 2, len(pendingTargets))900901	Cancel(cross(cur), a1)902	uassert.Equal(t, 1, len(pendingTargets), "emptied target leaves the with-pendings list")903	uassert.Equal(t, 1, len(ptIndex))904905	// registration alone never inflates the list906	RegisterTarget(cross(cur), "three", MinDelayFloor, "")907	uassert.Equal(t, 1, len(pendingTargets))908}909

Functions

  • AcceptTargetOwnership(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}, targetName string)

  • Cancel(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}, actionID string) string

  • Execute(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}, actionID string) string

  • Expire(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}, actionID string) string

  • GetAction(actionID string) string

  • GetPending() string

  • GetTarget(targetName string) string

  • IsExecuted(actionID string) bool

  • IsReady(actionID string) bool

  • RegisterTarget(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}, name string, minDelay int64, guardian string)

  • Render(path string) string

  • Schedule(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}, targetName string, data string, delay int64) string

  • SetGuardian(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}, targetName string, guardian string)

  • TransferTargetOwnership(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}, targetName string, newOwner string)

  • Veto(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}, actionID 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.