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

blog package

Overview

Package blog is moul's personal blog on gno.land: one realm, one author, posts that live in chain storage rather than in the code.

The shape

A post is markdown plus four fields (slug, title, date, tags). Writing one is a single Set transaction, so publishing never redeploys the realm and fixing a typo costs one small call instead of a new package path.

The reader-facing paths are deliberately short, because they get pasted into other people's chats:

Example
1gno.land/r/moul/blog             the index, newest first
2gno.land/r/moul/blog:<slug>      one post
3gno.land/r/moul/blog:t/<tag>     every post carrying a tag

Ordering without sort

gno has no sort.Slice, and avl.Tree iterates by key. So posts live in two trees: `posts` keyed by slug, for the O(log n) lookup a permalink needs, and `order` keyed by "<date>/<slug>", walked in reverse for newest-first. The date is YYYY-MM-DD precisely so that lexical order is chronological order, which is what makes the second tree free.

Versioning

gnomod.toml declares private = true, which lets the creator re-add the package at this exact path. That redeploy re-runs init() and WIPES every post here, so the markdown kept off chain is the source of truth and tools/gnoblog pushes it back. Trading that risk for a stable URL is the whole design: a /v1 would break every link already shared, a redeploy does not, and Manifest() makes restoring the content one diff.

Functions

Append

func Append(cur realm, slug, body string)

Append adds to the end of a post's body. It exists for a body too large to fit in one transaction: Set the first chunk, Append the rest. An ordinary edit uses Set, which is idempotent and therefore safe to retry.

Params

Command

# WARNING: This command is running in an INSECURE mode.
# It is strongly recommended to use a hardware device for signing
# and avoid trusting any computer connected to the internet,
# as your private keys could be exposed.

gnokey maketx call -pkgpath "gno.land/r/moul/blog" -func "Append" -args $'' -args $'' -gas-fee 1000000ugnot -gas-wanted 1_000_000_000 -send "" -chainid "gnoland-1" -remote "https://rpc.gno.land" ADDRESSgnokey query -remote "https://rpc.gno.land" auth/accounts/ADDRESS
gnokey maketx call -pkgpath "gno.land/r/moul/blog" -func "Append" -args $'' -args $'' -gas-fee 1000000ugnot -gas-wanted 1_000_000_000 -send "" -broadcast=false ADDRESS > call.tx
gnokey sign -tx-path call.tx -chainid "gnoland-1" -account-number ACCOUNTNUMBER -account-sequence SEQUENCENUMBER ADDRESS
gnokey broadcast -remote "https://rpc.gno.land" call.tx
  

Count

func Count() int

Count returns the number of published posts.

Command

gnokey query vm/qeval -remote "https://rpc.gno.land" -data "gno.land/r/moul/blog.Count()"

Result

Delete

func Delete(cur realm, slug string)

Delete removes a post and its index entry.

Param

Command

# WARNING: This command is running in an INSECURE mode.
# It is strongly recommended to use a hardware device for signing
# and avoid trusting any computer connected to the internet,
# as your private keys could be exposed.

gnokey maketx call -pkgpath "gno.land/r/moul/blog" -func "Delete" -args $'' -gas-fee 1000000ugnot -gas-wanted 1_000_000_000 -send "" -chainid "gnoland-1" -remote "https://rpc.gno.land" ADDRESSgnokey query -remote "https://rpc.gno.land" auth/accounts/ADDRESS
gnokey maketx call -pkgpath "gno.land/r/moul/blog" -func "Delete" -args $'' -gas-fee 1000000ugnot -gas-wanted 1_000_000_000 -send "" -broadcast=false ADDRESS > call.tx
gnokey sign -tx-path call.tx -chainid "gnoland-1" -account-number ACCOUNTNUMBER -account-sequence SEQUENCENUMBER ADDRESS
gnokey broadcast -remote "https://rpc.gno.land" call.tx
  

Get

func Get(slug string) string

Get returns a post's raw markdown body, or "" when there is no such post.

Param

Command

gnokey query vm/qeval -remote "https://rpc.gno.land" -data "gno.land/r/moul/blog.Get()"

Result

Manifest

func Manifest() string

Manifest returns one tab-separated line per post, plus one for the intro:

Example
1<slug>\t<rev>\t<date>\t<len of body>\t<sha256 of the canonical record>

It is the diff surface tools/gnoblog reads with a single vm/qeval: the hash covers the title, date, tags and body together, so one read says exactly which local file needs a transaction without downloading a single body.

The intro is reported under the key "!intro" with an empty date. '!' is not a legal slug character, so that row can never be confused with a post.

Command

gnokey query vm/qeval -remote "https://rpc.gno.land" -data "gno.land/r/moul/blog.Manifest()"

Result

Render

func Render(path string) string

Render serves three views:

Example
1""         the index, newest first
2"<slug>"   one post
3"t/<tag>"  every post carrying a tag

Param

Command

gnokey query vm/qeval -remote "https://rpc.gno.land" -data "gno.land/r/moul/blog.Render()"

Result

Revision

func Revision() int

Revision returns the total number of writes this realm has accepted. It changes on every mutation, so a client can cheaply tell "nothing moved".

Command

gnokey query vm/qeval -remote "https://rpc.gno.land" -data "gno.land/r/moul/blog.Revision()"

Result

Set

func Set(cur realm, slug, title, date, tags, body string)

Set creates or replaces the post at slug. This is the ordinary publish: one post, one transaction, idempotent.

Changing the date moves the post in the index, so the old order entry is removed before the new one is written.

Params

Command

# WARNING: This command is running in an INSECURE mode.
# It is strongly recommended to use a hardware device for signing
# and avoid trusting any computer connected to the internet,
# as your private keys could be exposed.

gnokey maketx call -pkgpath "gno.land/r/moul/blog" -func "Set" -args $'' -args $'' -args $'' -args $'' -args $'' -gas-fee 1000000ugnot -gas-wanted 1_000_000_000 -send "" -chainid "gnoland-1" -remote "https://rpc.gno.land" ADDRESSgnokey query -remote "https://rpc.gno.land" auth/accounts/ADDRESS
gnokey maketx call -pkgpath "gno.land/r/moul/blog" -func "Set" -args $'' -args $'' -args $'' -args $'' -args $'' -gas-fee 1000000ugnot -gas-wanted 1_000_000_000 -send "" -broadcast=false ADDRESS > call.tx
gnokey sign -tx-path call.tx -chainid "gnoland-1" -account-number ACCOUNTNUMBER -account-sequence SEQUENCENUMBER ADDRESS
gnokey broadcast -remote "https://rpc.gno.land" call.tx
  

SetIntro

func SetIntro(cur realm, body string)

SetIntro replaces the markdown shown above the index. Passing "" restores the built-in header.

Param

Command

# WARNING: This command is running in an INSECURE mode.
# It is strongly recommended to use a hardware device for signing
# and avoid trusting any computer connected to the internet,
# as your private keys could be exposed.

gnokey maketx call -pkgpath "gno.land/r/moul/blog" -func "SetIntro" -args $'' -gas-fee 1000000ugnot -gas-wanted 1_000_000_000 -send "" -chainid "gnoland-1" -remote "https://rpc.gno.land" ADDRESSgnokey query -remote "https://rpc.gno.land" auth/accounts/ADDRESS
gnokey maketx call -pkgpath "gno.land/r/moul/blog" -func "SetIntro" -args $'' -gas-fee 1000000ugnot -gas-wanted 1_000_000_000 -send "" -broadcast=false ADDRESS > call.tx
gnokey sign -tx-path call.tx -chainid "gnoland-1" -account-number ACCOUNTNUMBER -account-sequence SEQUENCENUMBER ADDRESS
gnokey broadcast -remote "https://rpc.gno.land" call.tx