Transaction

1DF83BA0FA43C6…C97331E57C4D

Block 26,102 · index 0 · indexed

Summary

Hash
1DF83BA0FA43C67F84C6BED077EAF22C5C69CC8B383927F51EBCC97331E57C4D
Block
26,102
Size
5279 bytes
Gas used
9,885,763 / 11,862,975
Fee
1000000 ugnot
Memo
gnopublish
Status
success

Messages

Arguments · 9

  1. #1ratelimitdemo
  2. #2README.md
  3. #3# `gno.land/r/moul/x/daily/ratelimitdemo/v0` Live demo of the [`p/moul/x/daily/ratelimit`](https://github.com/moul/gno-contracts/tree/main/p/moul/x/daily/ratelimit/v0) token-bucket rate limiter. Holds one package-level `ratelimit.Limiter` (0.5 tokens/block, capacity 5) and wires it to the chain — the tick is `runtime.ChainHeight()`, each caller is keyed by `unsafe.PreviousRealm().Address()`: - `Allow(cur) bool` — consume one token for the caller. - `SetConfig(cur, rate, burst)` — retune the shared bucket. - `Tokens(addr) int` — read-only balance. - `Render("/")` — config + a table of callers; `Render("/addr/<address>")` focuses one. All refill/consume math lives in the library; this realm is just the wiring and the gnoweb view. Render it at [`/r/moul/x/daily/ratelimitdemo/v0`](https://gno.land/r/moul/x/daily/ratelimitdemo/v0). <!-- BEGIN GNOCONTRACTS FOOTER (generated by `make readmes`; do not edit below) --> --- Part of **[moul/gno-contracts](https://github.com/moul/gno-contracts)** — moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage. **Dependency graph:** ![gno.land/r/moul/x/daily/ratelimitdemo/v0 dependency graph](https://raw.githubusercontent.com/moul/gno-contracts/main/_assets/gno.land/r/moul/x/daily/ratelimitdemo/v0/deps.png) > 🧪 **Highly experimental — potentially vibe-coded.** Not audited; may break, change, or be removed at any time. Do not use with anything of value. Full disclaimer: [DISCLAIMER](https://github.com/moul/gno-contracts/blob/main/DISCLAIMER.md). <!-- END GNOCONTRACTS FOOTER -->
  4. #4gnomod.toml
  5. #5module = "gno.land/r/moul/x/daily/ratelimitdemo/v0" gno = "0.9"
  6. #6ratelimitdemo.gno
  7. #7// Package ratelimitdemo is a small on-chain demo of the token-bucket rate // limiter provided by the [p/moul/x/daily/ratelimit](/p/moul/x/daily/ratelimit/v0) // library. // // It holds a single package-level [ratelimit.Limiter] and wires it to the // chain: the tick is runtime.ChainHeight() and each caller is keyed by its // address (unsafe.PreviousRealm().Address()). It contains no limiter logic of // its own — refill/consume math all lives in the library. package ratelimitdemo import ( "strconv" "chain/runtime" "chain/runtime/unsafe" "gno.land/p/moul/x/daily/ratelimit/v0" ) // limiter starts at 0.5 tokens/block (one every two blocks), capacity 5. var limiter = ratelimit.New(0.5, 5.0) // Allow consumes one token for the calling realm/user at the current block // height and reports whether the request is permitted. Returns false (and // consumes nothing) when the caller's bucket is empty. func Allow(cur realm) bool { addr := unsafe.PreviousRealm().Address() return limiter.Allow(string(addr), runtime.ChainHeight()) } // SetConfig updates the shared rate (tokens per block) and burst (capacity). // rate is clamped to >= 0, burst to >= 1. func SetConfig(cur realm, rate, burst float64) { limiter.SetConfig(rate, burst) } // Tokens reports how many whole tokens `addr` has available at the current // block height, without mutating any state. func Tokens(addr address) int { return limiter.Tokens(string(addr), runtime.ChainHeight()) } // --- rendering -------------------------------------------------------------- func ftoa(f float64) string { return strconv.FormatFloat(f, 'g', -1, 64) } // Render shows the limiter config and a table of known callers with their // current tokens and last-seen height. Path "/addr/<address>" focuses one // caller. func Render(path string) string { now := runtime.ChainHeight() rate, burst := limiter.Config() if len(path) > 6 && path[:6] == "/addr/" { key := path[6:] out := "# Rate Limiter — caller\n\n" out += "Address: `" + key + "`\n\n" out += "- Current tokens: **" + strconv.Itoa(limiter.Tokens(key, now)) + "** / " + ftoa(burst) + "\n" out += "- Now (height): " + strconv.FormatInt(now, 10) + "\n" return out } out := "# Rate Limiter\n\n" out += "Demo of the [`p/moul/x/daily/ratelimit`](/p/moul/x/daily/ratelimit/v0) library — " out += "an on-chain token-bucket limiter (port of `golang.org/x/time/rate`).\n\n" out += "## Config\n\n" out += "| Parameter | Value |\n|---|---|\n" out += "| Rate (tokens/block) | " + ftoa(rate) + " |\n" out += "| Burst (capacity) | " + ftoa(burst) + " |\n" out += "| Clock height | " + strconv.FormatInt(now, 10) + " |\n\n" out += "## Callers\n\n" if limiter.Len() == 0 { out += "_No caller has hit the limiter yet._\n\n" } else { out += "| Address | Tokens | Last height |\n|---|---|---|\n" limiter.Iterate(now, func(key string, tokens int, last int64) bool { out += "| `" + key + "` | " + strconv.Itoa(tokens) + " | " + strconv.FormatInt(last, 10) + " |\n" return false }) out += "\n" } out += "---\n" out += "Call `Allow(cur)` to consume a token; read `Tokens(addr)` for a caller's balance.\n" return out }
  8. #8/gno.MemPackageType
  9. #9 MPUserProd

Result log

msg:0,success:true,log:,events:[]