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/p/moul/x/games/clock/v0

Package
Open in gnoweb ↗

Overview

Kind
Pure package
Name
v0
Namespace
moul / x / games / clock
Files
4 (README)(gnomod.toml)
Exported functions
n/a — not supported for pure packages by the node (vm/qfuncs)
Module
gno.land/p/moul/x/games/clock/v0
gno
0.9

Files (4)

  • README.mdmarkdown
  • gnomod.tomltoml
  • clock.gnogno
  • clock_test.gnogno
clock_test.gnogno
1package clock23import (4	"testing"56	"gno.land/p/nt/uassert/v0"7)89func mustNew(t *testing.T, now, window, floor, life int64) *Clock {10	t.Helper()11	c, err := New(now, window, floor, life)12	uassert.NoError(t, err)13	return c14}1516func TestNewValidation(t *testing.T) {17	cases := []struct {18		name                     string19		now, window, floor, life int6420		want                     error21	}{22		{"zero window", 0, 0, 0, 0, ErrBadWindow},23		{"negative window", 0, -1, 0, 0, ErrBadWindow},24		{"negative floor", 0, 100, -1, 0, ErrBadFloor},25		{"floor above window", 0, 100, 101, 0, ErrBadFloor},26		{"negative life", 0, 100, 10, -1, ErrBadLife},27		{"life shorter than window", 0, 100, 10, 99, ErrBadLife},28		{"window overflows", maxInt64 - 5, 100, 0, 0, ErrOverflow},29		{"life overflows", maxInt64 - 500, 100, 0, 1000, ErrOverflow},30		{"unbounded is legal", 0, 100, 10, 0, nil},31		{"life equal to window is legal", 0, 100, 10, 100, nil},32		{"floor equal to window is legal", 0, 100, 100, 0, nil},33	}34	for _, tc := range cases {35		_, err := New(tc.now, tc.window, tc.floor, tc.life)36		if tc.want == nil {37			uassert.NoError(t, err, tc.name)38			continue39		}40		uassert.ErrorIs(t, err, tc.want, tc.name)41	}42}4344func TestOpensDueAtWindow(t *testing.T) {45	c := mustNew(t, 1000, 100, 10, 500)46	uassert.Equal(t, int64(1000), c.Start())47	uassert.Equal(t, int64(1100), c.Deadline())48	uassert.Equal(t, int64(1500), c.HardEnd())49	uassert.Equal(t, int64(100), c.Remaining(1000))50	uassert.Equal(t, int64(0), c.Elapsed(1000))51	uassert.False(t, c.Expired(1099))52	uassert.True(t, c.Expired(1100), "the deadline itself is expired")53	uassert.False(t, c.Final())54}5556func TestUnboundedHasNoHardEnd(t *testing.T) {57	c := mustNew(t, 0, 100, 0, 0)58	uassert.Equal(t, int64(0), c.HardEnd())59	uassert.False(t, c.Final(), "an unbounded clock is never final")60	c.Bump(90)61	c.Bump(180)62	uassert.Equal(t, int64(280), c.Deadline(), "nothing caps it")63}6465// TestBumpNeverMovesBackwards is the invariant a caller supplying its own grant66// gets wrong first: a late, small grant must not shorten the clock.67func TestBumpNeverMovesBackwards(t *testing.T) {68	c := mustNew(t, 0, 1000, 0, 0)69	uassert.Equal(t, int64(1000), c.Deadline())7071	uassert.Equal(t, int64(1000), c.BumpBy(10, 5), "now+5 is before the deadline")72	uassert.Equal(t, int64(1000), c.BumpBy(900, 0), "a zero grant leaves it alone")73	uassert.Equal(t, int64(1100), c.BumpBy(900, 200), "a grant past the deadline moves it")74}7576// TestFloorSurvivesATinyGrant is the anti-snipe: whatever the policy grants, a77// bump leaves at least the floor, so the last stretch stays reachable.78func TestFloorSurvivesATinyGrant(t *testing.T) {79	c := mustNew(t, 0, 1000, 50, 0)80	c.BumpBy(990, 1)81	uassert.Equal(t, int64(1040), c.Deadline(), "1 was raised to the floor of 50")82	uassert.Equal(t, int64(50), c.Remaining(990))8384	c2 := mustNew(t, 0, 1000, 50, 0)85	c2.BumpBy(990, 0)86	uassert.Equal(t, int64(50), c2.Remaining(990), "even a zero grant leaves the floor")87}8889// TestHardEndCapsEveryBump is the terminator: without it a contested clock is90// extended forever and the game has no end.91func TestHardEndCapsEveryBump(t *testing.T) {92	c := mustNew(t, 0, 100, 10, 250)93	uassert.Equal(t, int64(250), c.HardEnd())9495	c.BumpBy(90, 100)96	uassert.Equal(t, int64(190), c.Deadline())97	c.BumpBy(180, 100)98	uassert.Equal(t, int64(250), c.Deadline(), "capped at the hard end, not 280")99	uassert.True(t, c.Final())100101	c.BumpBy(240, 1000000)102	uassert.Equal(t, int64(250), c.Deadline(), "the cap holds against any grant")103	uassert.Equal(t, int64(10), c.Remaining(240), "and it beats the floor")104}105106// TestExpiredClockNeverRestarts stops a late action from reopening a settled107// game, which is the difference between a closed pot and a stolen one.108func TestExpiredClockNeverRestarts(t *testing.T) {109	c := mustNew(t, 0, 100, 10, 0)110	uassert.True(t, c.Expired(100))111	uassert.Equal(t, int64(100), c.BumpBy(100, 500), "exactly at the deadline")112	uassert.Equal(t, int64(100), c.Bump(5000), "long after")113	uassert.Equal(t, int64(0), c.Remaining(100))114115	settled := mustNew(t, 0, 100, 10, 1000)116	uassert.True(t, settled.Expired(100))117	got, err := settled.BumpShare(200, 50)118	uassert.NoError(t, err)119	uassert.Equal(t, int64(100), got, "not even a large share reopens it")120}121122func TestBumpShareValidation(t *testing.T) {123	c := mustNew(t, 0, 100, 0, 500)124	_, err := c.BumpShare(10, -1)125	uassert.ErrorIs(t, err, ErrBadShare)126	_, err = c.BumpShare(10, 101)127	uassert.ErrorIs(t, err, ErrBadShare)128	uassert.Equal(t, int64(100), c.Deadline(), "a rejected share changes nothing")129130	unbounded := mustNew(t, 0, 100, 0, 0)131	_, err = unbounded.BumpShare(10, 50)132	uassert.ErrorIs(t, err, ErrUnbounded, "no hard end, nothing to take a share of")133}134135// TestBumpShareDecays is why the share grant exists: each action closes a136// fraction of the gap to the hard end, so the grants shrink as the game runs137// and the pressure to act one more time is relieved instead of compounding.138func TestBumpShareDecays(t *testing.T) {139	c := mustNew(t, 0, 100, 1, 1000)140	first, err := c.BumpShare(10, 50)141	uassert.NoError(t, err)142	uassert.Equal(t, int64(505), first, "half the 990 left to the hard end")143144	second, err := c.BumpShare(500, 50)145	uassert.NoError(t, err)146	uassert.Equal(t, int64(750), second, "half of the 500 now left, a smaller grant")147148	third, err := c.BumpShare(700, 50)149	uassert.NoError(t, err)150	uassert.Equal(t, int64(850), third, "smaller again")151	uassert.True(t, third < c.HardEnd(), "it approaches the hard end without reaching it")152}153154// TestBumpShareRoundingStillGrants is the multiply-first lesson: a share of a155// gap smaller than the divisor must not truncate to a zero grant.156func TestBumpShareRoundingStillGrants(t *testing.T) {157	// 52 due, 50 left to the hard end: a tenth of that is 5, and dividing158	// before multiplying would truncate it to a grant of zero.159	c := mustNew(t, 0, 52, 0, 100)160	got, err := c.BumpShare(50, 10)161	uassert.NoError(t, err)162	uassert.Equal(t, int64(55), got, "a tenth of the 50 left is 5, not 0")163}164165func TestBumpShareRespectsFloorAndCap(t *testing.T) {166	c := mustNew(t, 0, 100, 20, 150)167	got, err := c.BumpShare(95, 10) // a tenth of the 55 left is 5, floored to 20168	uassert.NoError(t, err)169	uassert.Equal(t, int64(115), got)170171	got, err = c.BumpShare(110, 100) // would be 150 exactly, and never past it172	uassert.NoError(t, err)173	uassert.Equal(t, int64(150), got)174	uassert.True(t, c.Final())175}176177// TestHugeGrantDoesNotWrap keeps a bump total at the extremes: a wrapped178// deadline would land in the past and settle the game instantly.179func TestHugeGrantDoesNotWrap(t *testing.T) {180	c := mustNew(t, 0, 100, 0, 0)181	uassert.Equal(t, maxInt64, c.BumpBy(50, maxInt64), "clamped, not wrapped")182	uassert.True(t, c.Deadline() > 0)183184	big := mustNew(t, maxInt64/2, 1000, 0, maxInt64/4)185	got, err := big.BumpShare(maxInt64/2+1, 100)186	uassert.NoError(t, err)187	uassert.True(t, got > maxInt64/2, "a huge remaining share does not wrap")188}189190func TestElapsedAndRemainingAreNeverNegative(t *testing.T) {191	c := mustNew(t, 100, 100, 0, 0)192	uassert.Equal(t, int64(0), c.Elapsed(50), "before the start")193	uassert.Equal(t, int64(100), c.Remaining(100))194	uassert.Equal(t, int64(0), c.Remaining(9999), "long past the deadline")195	uassert.Equal(t, int64(9899), c.Elapsed(9999))196}197

Functions

not supported for pure packages by the node (vm/qfuncs)

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