Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

example_test.gno

4.61 Kb · 104 lines
  1package reaper
  2
  3import (
  4	"strings"
  5
  6	"gno.land/p/moul/x/storagecost/v0"
  7	"gno.land/p/nt/ufmt/v0"
  8)
  9
 10// Every Example in this file is a *query*, and that is a constraint rather
 11// than a choice: an example function takes no arguments, so it never receives
 12// a `cur realm` and can never call Post, Reap or Compact. What is left is
 13// exactly the surface a reader of the live realm has without a key, so each
 14// one carries the `vm/qeval` line that produces the same answer on chain:
 15//
 16//	gnokey query vm/qeval -remote https://rpc.gno.land \
 17//	  -data 'gno.land/r/moul/x/reaper/v0.<expr>'
 18//
 19// The board is empty by the time these run, because every Test in this
 20// package drains what it posted and examples run after all of them.
 21
 22// ExampleRender pins the page's skeleton: the title, the two sections that are
 23// always present, and the footer crediting the two packages that own the parts
 24// this realm does not.
 25//
 26//	vm/qrender  gno.land/r/moul/x/reaper/v0:
 27//
 28// It deliberately prints only the invariant lines. Everything interesting on
 29// the page is priced from the current block height and the notes outstanding,
 30// and an Example runs after every Test in the package and sees whatever state
 31// they left. The variable half is pinned by TestRenderShowsTheBountyAndTheReapLink
 32// instead, which controls the board first.
 33func ExampleRender() {
 34	for _, line := range strings.Split(Render(""), "\n") {
 35		switch {
 36		case strings.HasPrefix(line, "# "),
 37			strings.HasPrefix(line, "## "),
 38			strings.HasPrefix(line, "A noticeboard"),
 39			strings.HasPrefix(line, "The arithmetic is"):
 40			print(line + "\n")
 41		}
 42	}
 43	// Output:
 44	// # Reaper
 45	// A noticeboard whose garbage is a standing bounty. Posting a note locks a storage deposit. Once the note expires, anyone can delete it and the chain refunds that deposit **to whoever signs the deleting transaction**.
 46	// ## On the table right now
 47	// ## Board
 48	// The arithmetic is [p/moul/x/storagecost](/p/moul/x/storagecost/v0); the storage is [p/moul/ulist](/p/moul/ulist/v1), whose `Compact` reclaims dead nodes without moving a live index. Byte figures on this page are estimates from payload length: no stdlib call exposes a realm's real locked storage.
 49}
 50
 51// ExampleReapable is the poll a reaping bot runs before it spends anything:
 52// three counters, three queries, no key and no gas.
 53//
 54//	vm/qeval  gno.land/r/moul/x/reaper/v0.Live()
 55//	vm/qeval  gno.land/r/moul/x/reaper/v0.Reapable()
 56//	vm/qeval  gno.land/r/moul/x/reaper/v0.Compactable()
 57//
 58// Reapable and Compactable are separate numbers because reaping and
 59// compacting are separate transactions, and compaction returns nothing at all
 60// while a live note still sits below the dead ones. A bot that sees
 61// `reapable 0, compactable 0` should not sign anything, which is the answer
 62// here.
 63func ExampleReapable() {
 64	print(ufmt.Sprintf("live %d, reapable %d, compactable %d\n",
 65		Live(), Reapable(), Compactable()))
 66	// Output:
 67	// live 0, reapable 0, compactable 0
 68}
 69
 70// ExampleBounty is the single query that decides whether reaping is worth
 71// doing, and on an empty board it has to refuse to advertise a profit.
 72//
 73//	vm/qeval  gno.land/r/moul/x/reaper/v0.Bounty().String()
 74//
 75// Fee is what the reaping transaction costs at the floor gas price, and the
 76// chain charges it whether or not anything is freed. BreakEven turns that fee
 77// back into bytes: free fewer than 50 and the reaper is paying to tidy up.
 78// That threshold, not the size of the board, is what makes the mechanism a
 79// market rather than a chore.
 80func ExampleBounty() {
 81	print(Bounty().String() + "\n")
 82	// Output:
 83	// 0 bytes, refunds 0 GNOT against 0.005 GNOT of gas, break-even 50 bytes: not worth it yet
 84}
 85
 86// ExampleBounty_worth is the same query answered by a board worth draining:
 87// ten expired notes of a kilobyte each.
 88//
 89// It recomputes the quote instead of posting, because an example has no
 90// `cur realm` to post with. The arithmetic is the one Bounty applies, so the
 91// numbers are the ones the live query would return with that board on it.
 92//
 93// This is the whole concept in two lines. The poster locked 1.8944 GNOT to
 94// occupy that space; a stranger who never posted anything spends 0.005 GNOT of
 95// gas to delete it and the chain hands them the deposit. Nobody minted a
 96// token, and no pool was funded.
 97func ExampleBounty_worth() {
 98	q := storagecost.EvaluateAtFloor(storagecost.EstimateBytes(10*1024), gasWantedReap)
 99	print(q.String() + "\n")
100	print(ufmt.Sprintf("the reaper is paid %dx what the transaction costs\n", q.Refund/q.Fee))
101	// Output:
102	// 18944 bytes, refunds 1.8944 GNOT against 0.005 GNOT of gas, break-even 50 bytes: worth 1.8894 GNOT
103	// the reaper is paid 378x what the transaction costs
104}