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

governor.gno

96.80 Kb · 2331 lines
   1// Package governor is a proposal engine: it decides what a body of holders has
   2// agreed to, and it decides nothing about what agreement means.
   3//
   4// THE SPLIT IS THE POINT. A Governor holds proposals, epochs, quorum floors, the
   5// roll of eligible voters and the tally; it does not hold a treasury, a token, or
   6// any idea of what "adopt this" should DO. Adoption produces a KIND and a
   7// PAYLOAD, both strings, and the realm that installed the governor is what turns
   8// those into an effect. r/govern is the worked consumer, and r/offerer is the
   9// fixture proving a SECOND realm can extend the same engine from a different
  10// package without being trusted by it.
  11//
  12// Voting power is read from a snapshot, never from a live balance. The electorate
  13// is asked what an address COULD vote at the block a proposal opened, which is
  14// what stops a vote being bought after the question is known -- see
  15// p/kourt/grc20votes, which remembers exactly that, and p/kourt/checkpoint under
  16// it. A bar is frozen for the life of a proposal for the same reason: a live
  17// numerator against a moving denominator produced turnout above 100% of its own
  18// bar and a permissionless verdict flip. VOTELOCK.md is the argument.
  19//
  20// Strings rather than structs throughout the proposal surface, and that is forced
  21// rather than chosen: MsgCall.Args is []string, so a struct payload cannot cross
  22// the transaction boundary at all. The comment on the payload type below records
  23// what that costs and why nothing better is available.
  24package governor
  25
  26import (
  27	"chain"
  28	"crypto/sha256"
  29	"strconv"
  30	"strings"
  31
  32	bptree "gno.land/p/nt/bptree/v0"
  33	ufmt "gno.land/p/nt/ufmt/v0"
  34)
  35
  36// A proposal is a KIND and a PAYLOAD, both strings.
  37//
  38// Forced, and better than the alternative. MsgCall.Args is []string
  39// (gno.land/pkg/sdk/vm/msgs.go) and convertArgToGno switches on
  40// gno.BaseOf(argT), so scalars and named scalars like `address` convert; a
  41// struct, interface, pointer or func panics with "unexpected type in contract
  42// arg". An entrypoint taking one is uncallable by transaction.
  43//
  44// A []byte converts too, base64-decoded, so the string is a choice: a payload
  45// arrives as text a voter can read, where bytes would arrive as base64.
  46//
  47// A proposer cannot supply a closure either. A realm can persist one, but
  48// MsgRun forces the ephemeral package private and the save walk refuses it
  49// (realm.go, "cannot persist function or method from the private realm").
  50//
  51// The property that falls out is what OpenZeppelin cannot offer: Describe and
  52// Do consume the identical string, so what voters read IS what runs.
  53type Kind interface {
  54	// Name is the registry key.
  55	Name() string
  56
  57	// Describe renders a payload for the people voting on it.
  58	//
  59	// It must be a total function of the payload ALONE. Read live state here
  60	// and two voters at different heights are deciding different questions
  61	// while looking at the same page.
  62	Describe(payload string) string
  63
  64	// Check validates a payload against the world as it is now. Called when
  65	// the proposal opens AND again immediately before Do.
  66	//
  67	// The second call is the point. A proposal that was sound a week ago need
  68	// not be sound now, and the alternative is discovering that inside Do,
  69	// half-applied.
  70	Check(payload string) error
  71
  72	// Do performs it. Non-crossing, taking the realm as data, so a /p/ package
  73	// could implement this unchanged — crossing functions are illegal outside
  74	// a realm.
  75	//
  76	// Returning an error and panicking are different decisions. An error
  77	// FINISHES the proposal: recorded failed, slot returned, no retry. Say so
  78	// when the answer will not change.
  79	//
  80	// A panic ABORTS the transaction, writing nothing — including the failure
  81	// — so the proposal stays Succeeded and anybody may try again. Say so when
  82	// a retry could work, or when half-finishing is worse than not starting:
  83	// an abort is the only rollback gno offers. govern:batch depends on it.
  84	Do(_ int, rlm realm, payload string) error
  85}
  86
  87// Rules are per kind, never global. Renaming a parameter and spending the
  88// reserve should not need the same turnout, which is why one global quorum is
  89// always wrong for something.
  90//
  91// Basis points as int64, never float64: gno's own govdao compares against a
  92// float 66.66, and a threshold decided by binary floating point is a rounding
  93// argument waiting to happen. yes*bps >= (yes+no)*ThresholdBps is exact.
  94//
  95// bps is named once because it is load-bearing in three places at once: the
  96// tally, the rendered percentages and the supply ceiling. A scale written out
  97// separately in each is a number that can come to disagree with itself.
  98const bps = int64(10000)
  99
 100// maxWeighable is the largest snapshot supply a tally can weigh without yes*bps
 101// overflowing int64 (and going negative, which reads a won vote as lost). The
 102// Electorate contract requires PastTotal to stay within it; grc20votes caps its
 103// own supply here exactly, so for that token this ceiling is never approached. It
 104// is checked at the Propose door for a swapped-in electorate that does not.
 105const maxWeighable = int64(9223372036854775807) / bps
 106
 107type Rules struct {
 108	QuorumBps int64 // of the snapshot supply, counting abstain as turnout
 109
 110	// ThresholdBps is the share of yes+no (abstain excluded) that yes must reach.
 111	// The comparison is INCLUSIVE — yes*bps >= (yes+no)*ThresholdBps — so at 5000
 112	// a 50-50 tie PASSES. A realm wanting a strict majority sets 5001 or more; the
 113	// bootstrap and gno's govdao use a 6600 supermajority.
 114	ThresholdBps int64
 115
 116	// ProposeBps is what a proposer must hold, as a fraction of the snapshot
 117	// supply, to open a question at all.
 118	//
 119	// Attention control, not spam control: opening a proposal already costs a
 120	// new key's worth of deposit. The list is what holders read, and a list
 121	// nobody reads is a governor nobody governs. Zero means anyone may
 122	// propose — right for a small realm, wrong for a public token.
 123	ProposeBps   int64
 124	VotingBlocks int64
 125	DelayBlocks  int64 // succeeded -> executable; the timelock
 126	GraceBlocks  int64 // executable -> expired
 127}
 128
 129const (
 130	stateActive int8 = iota
 131	stateDefeated
 132	stateSucceeded
 133	stateExecuted
 134	stateFailed
 135	stateCanceled
 136	stateExpired
 137)
 138
 139// proposal is one question, frozen.
 140type proposal struct {
 141	id       int64
 142	kind     string
 143	payload  string
 144	title    string
 145	proposer address
 146
 147	// Both copied when the proposal opens: the rules, so a later change cannot
 148	// move the bar earlier voters faced; the snapshot epoch, so the electorate
 149	// is the one that existed when the question was asked.
 150	rules Rules
 151	epoch uint32
 152	total int64 // supply at that epoch, so quorum has a fixed denominator
 153
 154	// engaged is the quorum's DENOMINATOR; total is everything in issue. Equal
 155	// for this realm's token and not necessarily for another: an electorate may
 156	// drop idle weight out of the bar while that weight can still vote. So
 157	// quorum divides by engaged, and "what could still be cast" divides by
 158	// total.
 159	engaged int64
 160
 161	// quorumFloor, when positive, is an ABSOLUTE turnout the proposal needs
 162	// instead of the rules' QuorumBps fraction of engaged — a figure the consumer
 163	// computed itself (a court's max(5% supply, min(1×X̄, ⅓ votable))) and passed
 164	// through ProposeWithQuorum. Snapshotted here like every other bar, so it
 165	// cannot move under an open vote. Zero means the bps formula applies, which is
 166	// every ordinary caller.
 167	quorumFloor int64
 168
 169	opened int64
 170	closes int64
 171	// The same two moments in unix seconds, written beside the heights and never
 172	// derived afterwards. A VOTING WINDOW IS A PROMISE TO A VOTER, and a height
 173	// only means a date if the chain's pace never changes; a proposal opened
 174	// before these existed carries 0 and keeps the height it was opened under.
 175	openedTime int64
 176	closesTime int64
 177	ready      int64 // set when it succeeds
 178	readyTime  int64 // its wall-clock twin, written at the same moment
 179	state  int8
 180	reason string
 181
 182	yes, no, abstain int64
 183	// voted exists only to refuse a second vote from the same address. Nothing
 184	// renders it and nothing else reads it.
 185	//
 186	// A tree per proposal rather than one shared tree keyed by (id, voter),
 187	// for cleanup rather than cost: this buys a whole node on the first vote
 188	// (~4,500 bytes) where a shared tree would cost one entry, but dropping it
 189	// is one assignment and the deposit goes back to whoever settles. Clearing
 190	// a range out of a shared tree is a removal per voter, unbounded, and
 191	// bptree forbids removing during iteration.
 192	//
 193	// Dropped the moment the proposal closes: Vote refuses a closed proposal
 194	// before it looks here, so the tree would be rent on something nobody can
 195	// consult. The roll survives in the Voted events.
 196	voted *bptree.BPTree
 197}
 198
 199// entry is a kind and whether it may actually be proposed. Separate, because
 200// publishing code is something a realm does and letting that code hold this
 201// governor's authority is something the holders do. One registration call fuses
 202// them, and then whoever may register can grant themselves any power with no
 203// vote.
 204type entry struct {
 205	kind  Kind
 206	rules Rules
 207	live  bool
 208}
 209
 210// maxLive bounds how many questions can be open at once. A security parameter,
 211// not a storage one: it is the only thing between a determined proposer and a
 212// list nobody can read.
 213//
 214// Cancel frees a slot outright. Time only makes one RECLAIMABLE — a read can
 215// work out that a proposal is over but cannot write it down — so the slot
 216// comes back when somebody calls Settle, or when sweep finds it on the next
 217// Propose. Reading this as "time frees a slot" is how the reclaim came to be
 218// something a proposer could hold shut; see the cursor sweep keeps.
 219//
 220// The open section of the front page has no length cap of its own, so its
 221// worst case is this many rows at maxTitle and maxKindName each: 14,220 bytes,
 222// which is a page. Ten thousand slots would be 2.2MB, which is not. A test
 223// holds the product against a ceiling, so raising either number fails it.
 224const maxLive = 64
 225
 226// govLanes is how many of those slots only the governor's own kinds may take.
 227//
 228// Without it the sixty-four are a commons and any one kind may hold all of
 229// them. Sixty-four proposals of some cheap kind with a long voting window, and
 230// nothing else can be asked until that window runs out — including the
 231// govern:rules vote that would shorten the window. The realm stays up and stops
 232// being governable, which is the one failure it must not have, because every
 233// other kind of congestion is something the holders can vote their way out of.
 234//
 235// Priced rather than assumed: the bootstrap terms put ProposeBps at zero, so
 236// any holder may propose, and sixty-four proposals is about 56 GNOT of deposit
 237// — refundable, and held for one bootstrap voting window of a week.
 238//
 239// Eight rather than one. The governor has five kinds of its own and they are
 240// not alternatives: retuning a kind, adopting another, and retiring a third can
 241// all be live questions at once, and a lane of one would mean the first of them
 242// blocks the rest. Eight leaves room for a second round of each.
 243//
 244// This does NOT stop the governor's own kinds crowding each other out, and it
 245// is not meant to. A realm whose holders have filled the governance lane with
 246// governance is congested by its own doing and can wait; a realm shut out of
 247// governance by a kind it adopted for something else cannot.
 248const govLanes = 8
 249
 250// maxOpen is what any other kind may fill, which is the number a proposer
 251// actually meets. maxLive stays the bound on the front page, since the lane is
 252// a reallocation of the sixty-four and not an addition to them.
 253const maxOpen = maxLive - govLanes
 254
 255var (
 256	errNoSuchKind          = govErr("no kind by that name has been offered")
 257	errAlreadyLive         = govErr("that kind is already adopted")
 258	errNotLive             = govErr("that kind is not adopted")
 259	errCannotRetireBuiltin = govErr("the governor's own kinds cannot be retired")
 260)
 261
 262// Governor is one governing body: which powers it has adopted, every question
 263// it has been asked, and where its slot reclaim had got to.
 264//
 265// Allocated by the consuming realm, which is what makes this a library rather
 266// than a realm. A /p/ package's own state is frozen after init, so nothing
 267// durable could live at package level; the trees below carry the consumer's
 268// storage stamp, and every method here borrows the consumer's authority back
 269// for the write.
 270//
 271// Every field is unexported and no method hands one out. /p/-declared types can
 272// be named by other /p/ packages, so an exported *proposal or a method
 273// returning one would let a stranger declare a mutator over it — and the
 274// storage-realm borrow would run that mutator under the CONSUMING realm's
 275// authority. See gno-security-guide.md §3(B) and §4.
 276type Governor struct {
 277	voters Electorate
 278	token  Token
 279
 280	kinds     *bptree.BPTree // name -> *entry
 281	proposals *bptree.BPTree // enc(id) -> *proposal
 282	openIdx   *bptree.BPTree // digest -> enc(id), the live ones
 283
 284	propSeq int64
 285
 286	// executing is the re-entrancy latch, and it is held for the WHOLE of every
 287	// state-changing call — propose, castVote and Execute — not only Execute.
 288	//
 289	// It started as an Execute-only flag, against a kind calling back in while
 290	// its own Do runs and seeing a proposal mid-execution. The other two read it
 291	// and never wrote it, which made those reads decorative: propose and castVote
 292	// both call into the consumer-supplied Electorate (PastVotes, PastTotal,
 293	// EngagedTotal, and Height/Now by way of settle) and both mutate afterwards,
 294	// so a hostile or merely re-entrant electorate could nest a second call
 295	// inside the first. castVote was the sharp one — its already-voted guard
 296	// reads state that the same function does not write until after the external
 297	// call, so a nested frame passed both checks and the tally took the weight
 298	// twice.
 299	//
 300	// The name is kept because every panic and every test says it; what changed
 301	// is the span, from one call to three.
 302	//
 303	// THE THREE PANICS GAINED A CLAUSE RATHER THAN NEW WORDING. Each said "from
 304	// inside an execution", which stopped being the only cause the moment vote
 305	// and propose began holding the latch too. Rewriting them outright broke
 306	// TestExecutionCannotReEnterTheGovernor, which pins each message by
 307	// substring — correctly, because a panic string is API for anyone matching on
 308	// it. Appending "or a vote" makes them true without moving what was pinned.
 309	executing bool
 310
 311	// sweepFrom is where the next slot reclaim starts scanning, and it rotates.
 312	// The index is keyed by digest(kind, payload) and a proposer chooses their
 313	// payload, so they choose their key: park a few long-running proposals on
 314	// the lowest keys and a FIXED window never sees past them, freeing nothing
 315	// while the rest of the list is finished business. Beating the lowest of
 316	// fifty-six random keys is a few hundred hashes offline.
 317	sweepFrom string
 318}
 319
 320// reserved names the governor's own kinds. Offer refuses this prefix, so no
 321// realm can publish something that renders as a built-in.
 322const reserved = "govern:"
 323
 324// isReserved reports whether a name belongs to the governor itself.
 325//
 326// One predicate, two callers: Offer refusing to publish under the prefix, and
 327// govern:retire refusing to withdraw something carrying it. It was written
 328// twice, and a weakened retire copy would let the holders withdraw
 329// govern:adopt — after which no kind could ever be adopted again and no
 330// proposal could restore it.
 331func isReserved(name string) bool {
 332	return len(name) >= len(reserved) && name[:len(reserved)] == reserved
 333}
 334
 335// NewRules builds the terms a kind would pass on. A realm cannot allocate
 336// another realm's struct — govern.Rules{...} written elsewhere is refused with
 337// "cannot allocate ... in realm" — so the value comes into existence here and
 338// the caller passes numbers. Without it, Offer was uncallable from outside this
 339// package.
 340func NewRules(quorumBps, thresholdBps, votingBlocks, delayBlocks, graceBlocks, proposeBps int64) Rules {
 341	return Rules{
 342		QuorumBps: quorumBps, ThresholdBps: thresholdBps,
 343		VotingBlocks: votingBlocks, DelayBlocks: delayBlocks,
 344		GraceBlocks: graceBlocks, ProposeBps: proposeBps,
 345	}
 346}
 347
 348// Offer shelves a kind. It takes effect on nothing.
 349//
 350// Ungated, because an offered kind can do nothing. What it buys is a name
 351// pointing at published, immutable code the holders are later asked to approve.
 352//
 353// The two-step exists because MsgCall.Args is []string: an account cannot hand
 354// over a Kind, only a realm can construct one. If adopting required passing
 355// the value, only realms could grow the governor — and that decision has to
 356// belong to the holders. Offer is the realm's half; the vote is theirs.
 357func (g *Governor) Offer(who address, k Kind, r Rules) {
 358	name := k.Name()
 359	mustBeUsableName(name)
 360	if isReserved(name) {
 361		panic("govern: that prefix belongs to the governor")
 362	}
 363	g.mustBeSaneRules(r)
 364
 365	// A name, once offered, is bound to that code forever.
 366	//
 367	// The alternative — allowing a re-offer while the kind is not yet adopted —
 368	// is a live attack, not an untidiness. Offer harmless code, wait for an
 369	// adoption proposal to open on it, then re-offer under the same name while
 370	// the vote runs. The holders read the first Describe, approve it, and Do
 371	// dispatches to the second. gno's own daokit has this shape and records it
 372	// as a TODO; here the vote would be a signature on a blank cheque.
 373	//
 374	// Pinning the value into the proposal would also close it, at the cost of
 375	// a Kind stored per proposal and a rule about which copy wins. Refusing
 376	// the rewrite is smaller and matches how the chain already behaves: a
 377	// realm cannot be redeployed at its path either. A realm with new code
 378	// publishes a new name — treasury/spend/v2 — which the holders then have
 379	// to adopt knowingly, which is the entire point.
 380	if g.entryOf(name) != nil {
 381		panic("govern: that name is taken; publish a new one rather than " +
 382			"rewriting what may already be under a vote")
 383	}
 384	g.kinds.Set(name, &entry{kind: k, rules: r})
 385
 386	// The terms go out with it. A holder deciding whether to adopt this is
 387	// deciding on the code AND on the bar it would pass at, and the two are
 388	// bound together from here — Offer refuses to rewrite either.
 389	chain.Emit(kindOfferedEvent,
 390		"name", name,
 391		"offerer", who.String(),
 392		"quorumBps", strconv.FormatInt(r.QuorumBps, 10),
 393		"thresholdBps", strconv.FormatInt(r.ThresholdBps, 10),
 394		"votingBlocks", strconv.FormatInt(r.VotingBlocks, 10),
 395		"delayBlocks", strconv.FormatInt(r.DelayBlocks, 10),
 396		"graceBlocks", strconv.FormatInt(r.GraceBlocks, 10),
 397		"proposeBps", strconv.FormatInt(r.ProposeBps, 10),
 398	)
 399}
 400
 401// maxTitle bounds the headline, which goes on the shared page. Every open
 402// proposal's title is concatenated into Render(""), and the only cap there is
 403// on the decided tail — so the page every holder reads is as long as the open
 404// titles put together. Anything needing more room is what the payload is for.
 405const maxTitle = 120
 406
 407// maxPayload bounds the argument. Looser than the title on purpose: this is
 408// what the proposal actually says, a batch carries up to maxBatch members in
 409// one, and the cost falls on the proposer — Render lists titles, so nobody
 410// loads a payload without asking for that proposal by number.
 411const maxPayload = 4096
 412
 413// maxKindName bounds a name. Offer is ungated, so it is chosen by whoever
 414// turns up, and everything that renders a proposal renders it.
 415const maxKindName = 64
 416
 417// mustBeUsableName refuses a name that cannot be used everywhere a name is
 418// used.
 419//
 420// A kind's name is not only a registry key. It is the first field of a batch
 421// member line, and parseBatch ends that field at the first SPACE; it goes into
 422// the digest that decides whether two proposals are the same question; and it
 423// is rendered on a page somebody has to read before voting. A name that works
 424// in one of those and not the others is a kind that is quietly unusable.
 425//
 426// A space is the one that looks harmless and is not. "my kind" offers and
 427// proposes perfectly well, and then a batch reads everything after the space
 428// as the payload — so the member resolves to a kind called "my", the batch is
 429// refused with "no kind called my", and nothing points at the name.
 430//
 431// Printable ASCII, no space. That is what every kind here already uses — fee,
 432// treasury/spend, govern:adopt — and it is the largest set that works in all
 433// three places at once.
 434func mustBeUsableName(name string) {
 435	if name == "" {
 436		panic("govern: a kind needs a name")
 437	}
 438	if len(name) > maxKindName {
 439		panic("govern: that name is too long")
 440	}
 441	for i := 0; i < len(name); i++ {
 442		if c := name[i]; c <= ' ' || c > '~' {
 443			panic("govern: a kind name must be printable ASCII with no spaces")
 444		}
 445	}
 446}
 447
 448// mustBeUsableTitle bounds the one piece of free prose an ungated caller puts
 449// on a page everybody reads.
 450//
 451// A title goes onto the front page inside a markdown list item, so a newline
 452// ends that item and starts a row of the proposer's own — a forged proposal
 453// with a state and a link they choose:
 454//
 455//   - [#1](:1) **x
 456//   - [#999](:999) **Ratified by the foundation** — `govern:minter` · succeeded
 457//
 458// The bootstrap kinds ask for no stake, so that cost nothing but a transaction.
 459//
 460// Control characters, not printable-ASCII: a title is prose and keeps spaces
 461// and any language. Markdown within a line is left alone — it cannot leave the
 462// row it belongs to, and structure is the part a reader cannot check.
 463func mustBeUsableTitle(title string) {
 464	if len(title) > maxTitle {
 465		panic("govern: that title is too long")
 466	}
 467	if err := TextOnly(title); err != nil {
 468		panic("govern: a title " + err.Error())
 469	}
 470}
 471
 472// TextOnly reports whether a string is text rather than page structure.
 473//
 474// Exported because it is a kind author's problem. A payload comes from whoever
 475// proposes — any address at all when ProposeBps is zero — and Describe renders
 476// it onto a page others vote from, so a raw payload hands page structure to a
 477// stranger. The built-ins are safe by accident: their payloads are kind names
 478// and addresses, which cannot hold a newline. It bites the first kind that
 479// takes free text.
 480//
 481//	func (k mykind) Check(payload string) error {
 482//		if len(payload) > 280 {
 483//			return errTooLong
 484//		}
 485//		return govern.TextOnly(payload)
 486//	}
 487//
 488// Control characters, not printable-ASCII, so prose in any language survives —
 489// every byte of a multi-byte character is >= 0x80. Markdown within a line is
 490// allowed: it cannot leave the row it belongs to.
 491//
 492// The governor cannot apply this to payloads itself; govern:batch is defined
 493// in terms of newlines. Only a kind knows its own grammar.
 494func TextOnly(s string) error {
 495	for i := 0; i < len(s); i++ {
 496		if c := s[i]; c < 0x20 || c == 0x7f {
 497			return errNotTextOnly
 498		}
 499	}
 500	return nil
 501}
 502
 503var errNotTextOnly = govErr("cannot contain control characters")
 504
 505// saneRules is the one definition of terms this realm will accept — one
 506// function, two callers, after two copies drifted apart.
 507//
 508// Both copies missed ProposeBps. Above a hundred percent it asks a proposer to
 509// hold more than everything, so nobody can open a question under that kind:
 510// adopted and unusable. And govern:rules accepted only five of the six terms,
 511// so the one field where a bad value bricks a kind was the one nobody could
 512// retune. It takes all six now.
 513func saneRules(r Rules) error {
 514	if r.QuorumBps < 0 || r.QuorumBps > bps || r.ThresholdBps < 0 || r.ThresholdBps > bps {
 515		return govErr("basis points out of range")
 516	}
 517	if r.ProposeBps < 0 || r.ProposeBps > bps {
 518		// Exactly bps is allowed: "only somebody holding the entire supply may
 519		// propose this" is a coherent, if severe, thing to want.
 520		return govErr("a proposer cannot be asked to hold more than the whole supply")
 521	}
 522	if r.VotingBlocks <= 0 {
 523		return govErr("a vote needs a period")
 524	}
 525	if r.GraceBlocks <= 0 {
 526		// A decision has to be able to expire, because never expiring leaks a
 527		// slot.
 528		//
 529		// A Succeeded proposal keeps its place in the open index until it is
 530		// executed, because until then a duplicate would be a second live copy
 531		// of the same question. With no grace period there is nothing that ever
 532		// ends it: Cancel refuses a decided proposal, Settle and sweep find
 533		// nothing to change, and the slot is held for the life of the realm.
 534		// Sixty-four like that and nobody can open a proposal again.
 535		//
 536		// Refusing zero is what makes "every proposal eventually gives its slot
 537		// back" true by construction, and it agrees with what this realm
 538		// already says about grace: a decision nobody executed is a decision
 539		// about a world that has moved.
 540		return govErr("a decision has to expire; a grace period of zero holds " +
 541			"its slot for the life of the realm")
 542	}
 543	if r.DelayBlocks < 0 {
 544		// GraceBlocks < 0 needs no test here: the GraceBlocks <= 0 return above
 545		// already refuses it. Negative behaves as zero everywhere it is used, so
 546		// this refuses a value that means nothing rather than one that does harm —
 547		// and stops it being stored and rendered as a term somebody agreed to.
 548		return govErr("a period cannot be negative")
 549	}
 550	return nil
 551}
 552
 553func (g *Governor) mustBeSaneRules(r Rules) {
 554	if err := saneRules(r); err != nil {
 555		panic("govern: " + err.Error())
 556	}
 557}
 558
 559// init makes the governor able to govern itself, and nothing else. These are
 560// live from the first block because adopting a kind is itself a kind, so there
 561// is nothing to bootstrap them with. Everything beyond must be offered and
 562// adopted, so not even the deployer can add a power without a vote.
 563
 564// BootstrapRules are the terms the governor governs ITSELF on.
 565//
 566// Exported because a consuming realm registering a power of its own —
 567// the mint, most of all — should govern it on the same terms rather than
 568// inventing a second set that can drift from these.
 569func BootstrapRules() Rules {
 570	return Rules{
 571		// A fifth of the supply has to turn out. Low enough to reach with
 572		// dispersed holders, high enough that a handful cannot decide alone
 573		// while everybody else is asleep.
 574		QuorumBps: 2000,
 575
 576		// Two thirds of what was cast, not half. A simple majority is the
 577		// wrong bar for changing the rules of the game — these kinds decide
 578		// who may mint and what powers exist — and 6600 is exact where gno's
 579		// own govdao carries 66.66 as a float64 and compares with >=.
 580		ThresholdBps: 6600,
 581
 582		// A week to vote, so holders in any timezone get a turn. It is a
 583		// DEADLINE and not a duration: a vote nothing further could change
 584		// closes on the arithmetic, so an agreed decision does not wait it out.
 585		VotingBlocks: 7 * 24 * 60 * 60 / 5,
 586
 587		// Two days between deciding and doing, which is what a timelock is
 588		// for: time for somebody who dislikes the outcome to sell, leave, or
 589		// argue before it takes effect.
 590		DelayBlocks: 2 * 24 * 60 * 60 / 5,
 591
 592		// A fortnight to execute, and then the decision expires. A proposal
 593		// nobody executed for two weeks is a decision about a world that has
 594		// moved, and gno's own govdao had to bolt on a reject path precisely
 595		// because proposals could otherwise sit forever.
 596		GraceBlocks: 14 * 24 * 60 * 60 / 5,
 597	}
 598}
 599
 600// installBuiltins registers the kinds the governor governs itself with.
 601func (g *Governor) installBuiltins() {
 602	// The terms the governor governs ITSELF on. See BootstrapRules.
 603	bootstrap := BootstrapRules()
 604	g.kinds.Set(adoptKind{}.Name(), &entry{kind: adoptKind{}, rules: bootstrap, live: true})
 605	g.kinds.Set(retireKind{}.Name(), &entry{kind: retireKind{}, rules: bootstrap, live: true})
 606	g.kinds.Set(rulesKind{}.Name(), &entry{kind: rulesKind{}, rules: bootstrap, live: true})
 607	g.kinds.Set(batchKind{}.Name(), &entry{kind: batchKind{}, rules: bootstrap, live: true})
 608}
 609
 610// adoptKind turns an offered kind live. Its payload is only a name, so what
 611// the holders read is exactly what they are approving.
 612type adoptKind struct{}
 613
 614func (k adoptKind) Name() string { return reserved + "adopt" }
 615
 616func (k adoptKind) describe(g *Governor, payload string) string {
 617	out := "adopt the kind `" + payload + "`, letting it be proposed and executed"
 618	e := g.entryOf(payload)
 619	if e == nil {
 620		return out + "\n\n_Nothing has been offered under that name._"
 621	}
 622	// The terms, not just the name: a holder approving a power needs to see how
 623	// easily it can be used. A hostile realm offers a spending kind with a
 624	// hundredth of a percent quorum and a one-block vote, and the adoption
 625	// reads exactly like an honest one.
 626	//
 627	// Still a total function of the payload — an offered name is bound to its
 628	// code permanently, and govern:rules refuses to retune an unadopted kind,
 629	// so none of this can move between proposing and executing.
 630	out += ufmt.Sprintf("\n\nIt would pass on:"+
 631		"\n- quorum: %s of the supply"+
 632		"\n- threshold: %s of votes cast"+
 633		"\n- time to vote: %s"+
 634		"\n- delay before it can run: %s"+
 635		"\n- expires after: %s",
 636		pct(e.rules.QuorumBps), pct(e.rules.ThresholdBps),
 637		span(e.rules.VotingBlocks), span(e.rules.DelayBlocks), span(e.rules.GraceBlocks))
 638	// Always rendered, including when it is zero — which is when it matters
 639	// most. Zero means Propose skips the stake check, so any address may open
 640	// a proposal holding nothing, and omitting the line read as "not
 641	// applicable" rather than "anybody". A permissive default is the term a
 642	// page most needs to say out loud.
 643	out += "\n- who may propose: " + proposerBar(e.rules.ProposeBps)
 644	return out
 645}
 646
 647func (k adoptKind) check(g *Governor, payload string) error {
 648	e := g.entryOf(payload)
 649	if e == nil {
 650		return errNoSuchKind
 651	}
 652	if e.live {
 653		return errAlreadyLive
 654	}
 655	return nil
 656}
 657
 658func (k adoptKind) run(g *Governor, dispatch Dispatch, payload string) error {
 659	e := g.entryOf(payload)
 660	if e == nil {
 661		return errNoSuchKind
 662	}
 663	e.live = true
 664	return nil
 665}
 666
 667// retireKind withdraws one. Offered-but-not-live is the resting state, so a
 668// retired kind can be adopted again without the realm re-offering it.
 669type retireKind struct{}
 670
 671func (k retireKind) Name() string { return reserved + "retire" }
 672
 673func (k retireKind) describe(g *Governor, payload string) string {
 674	return "retire the kind `" + payload + "`, so it can no longer be proposed" +
 675		"\n\nThis also kills any proposal of that kind that has already been " +
 676		"decided and not yet run: Execute refuses a kind that is no longer " +
 677		"adopted, and records the proposal as failed. Retiring is not only " +
 678		"about the future."
 679}
 680
 681func (k retireKind) check(g *Governor, payload string) error {
 682	e := g.entryOf(payload)
 683	if e == nil {
 684		return errNoSuchKind
 685	}
 686	if !e.live {
 687		return errNotLive
 688	}
 689	if isReserved(payload) {
 690		return errCannotRetireBuiltin
 691	}
 692	return nil
 693}
 694
 695func (k retireKind) run(g *Governor, dispatch Dispatch, payload string) error {
 696	e := g.entryOf(payload)
 697	if e == nil {
 698		return errNoSuchKind
 699	}
 700	e.live = false
 701	return nil
 702}
 703
 704// Propose opens a question. One maketx call, two strings — which is the whole
 705// design and the reason the payload is not a struct.
 706//
 707// The quorum is the rules' QuorumBps fraction of the engaged weight. A consumer
 708// that computes its own absolute bar — a court sizing quorum to a claim's open
 709// interest — uses ProposeWithQuorum instead.
 710func (g *Governor) Propose(who address, kind, payload, title string) int64 {
 711	return g.propose(who, kind, payload, title, 0)
 712}
 713
 714// ProposeWithQuorum is Propose with an ABSOLUTE turnout the question needs,
 715// replacing the rules' QuorumBps fraction for this one proposal. The figure is
 716// the consumer's to compute (a court's max(5% supply, min(1×X̄, ⅓ votable))) and
 717// is snapshotted here, so the bar cannot move under an open vote. A non-positive
 718// floor is refused — a caller wanting the bps formula calls Propose.
 719//
 720// Additive: Propose is unchanged and passes zero, which every existing user does.
 721func (g *Governor) ProposeWithQuorum(who address, kind, payload, title string, quorumFloor int64) int64 {
 722	if quorumFloor <= 0 {
 723		panic("govern: a quorum floor has to be positive; use Propose for the bps bar")
 724	}
 725	return g.propose(who, kind, payload, title, quorumFloor)
 726}
 727
 728func (g *Governor) propose(who address, kind, payload, title string, quorumFloor int64) int64 {
 729	if g.executing {
 730		panic("govern: cannot propose from inside an execution or a vote")
 731	}
 732	// Held for the call, for the reason castVote's own note gives at length: this
 733	// function reads the consumer-supplied Electorate four times (Epoch,
 734	// PastTotal, EngagedTotal, PastVotes) and writes a proposal afterwards, so
 735	// the read-only check above was excluding nothing on its own.
 736	//
 737	// Its exposure is milder than castVote's — there is no
 738	// check-then-write-the-thing-you-checked pair here, so a nested frame would
 739	// mint a second proposal rather than double-count a tally — but two
 740	// proposals from one call is still a write the caller did not ask for, and
 741	// the latch is the same two lines.
 742	g.executing = true
 743	defer func() { g.executing = false }()
 744	// Checked before anything else is done with them: these are the two
 745	// strings an ungated caller supplies, and they are persisted for the life
 746	// of the realm.
 747	mustBeUsableTitle(title)
 748	if len(payload) > maxPayload {
 749		panic("govern: that payload is too long")
 750	}
 751	k := g.kindOf(kind)
 752	if err := g.checkKind(k, payload); err != nil {
 753		panic("govern: " + err.Error())
 754	}
 755
 756	// The electorate is the checkpointed supply at the last sealed epoch. Not a
 757	// hand-kept roll: the token already remembers who held what, and asking it is
 758	// what makes the weight historical.
 759	//
 760	// THIS ALONE DOES NOT MAKE WEIGHT UNRENTABLE, and an earlier version of this
 761	// comment claimed it did. The anchor is derived HERE, at propose time, by
 762	// whoever proposes — so a renter buys float, waits ONE epoch for the
 763	// checkpoint to seal, proposes (pinning the anchor to a window in which they
 764	// hold), sells, and votes with weight they no longer own. Measured end to end:
 765	// 300 B of pinned weight cast at 600x a quorum floor with a live balance of
 766	// zero and one epoch of capital at risk. What this line buys on its own is
 767	// only that weight cannot be acquired AFTER the question exists.
 768	//
 769	// CLOSED, and not here — the other half is supplied by the CONSUMER, through
 770	// VoteWithCap, as a ceiling of the voter's live balance. The engine still
 771	// derives this snapshot and takes the lesser, so a consumer can only lower.
 772	// See VOTEFLOOR.md; kourtv2 caps all three of its lanes and r/govern does not,
 773	// which is why the exposure is described here rather than fixed here.
 774	at := g.voters.Epoch() - 1
 775	if at == 0 {
 776		panic("govern: no sealed epoch yet — the chain is too young to vote")
 777	}
 778	total := g.voters.PastTotal(at)
 779	if total <= 0 {
 780		panic("govern: nothing was in issue at that epoch")
 781	}
 782	if total > maxWeighable {
 783		// The ceiling the tally silently assumed. grc20votes caps here so it never
 784		// trips; a swapped-in electorate that does not would overflow yes*bps into
 785		// a negative tally — a won vote reported as lost. Refused at the door,
 786		// where it reads as a misconfigured electorate rather than the governor
 787		// miscounting.
 788		panic("govern: the snapshot supply exceeds what a tally can weigh")
 789	}
 790	// Snapshotted with the rest, so a bar cannot move under an open vote.
 791	engaged := g.voters.EngagedTotal(at)
 792	if engaged <= 0 {
 793		// An electorate that engages nobody makes every quorum TRIVIAL, which is
 794		// the opposite of what this comment said for a long time and the reason
 795		// the guard is load-bearing rather than tidy. The bar is
 796		// `cast*bps >= engaged*QuorumBps`; at engaged == 0 the right-hand side is
 797		// zero and the comparison holds for any turnout, including none — so
 798		// quorum stops existing, and at the deadline one yes vote carries the
 799		// question however few showed up.
 800		//
 801		// Reachable with an honest electorate rather than a broken one:
 802		// EngagedTotal is there so a realm can drop idle weight out of the
 803		// denominator, and one where all weight is idle returns zero truthfully.
 804		panic("govern: the engaged weight has to be positive")
 805	}
 806	if engaged > total {
 807		// Clamp rather than refuse. A court deliberately hosts claims too big for
 808		// its electorate to decide, and an EngagedTotal above the snapshot supply
 809		// should make the bar unreachable-but-valid, not abort the proposal.
 810		// Clamping to total keeps rest = total - cast non-negative in the tally.
 811		// The token this ships with returns engaged == total, so this never fires
 812		// for it — it is here for a replacement electorate.
 813		engaged = total
 814	}
 815
 816	rules := g.rulesOf(kind)
 817	if rules.ProposeBps > 0 {
 818		// The numbers, not just the verdict. The realm knows the bar and what
 819		// the caller held; withholding both leaves somebody to work out from
 820		// the terms page what they are short of, and the epoch matters most of
 821		// all — a holder refused here may well hold plenty NOW and nothing at
 822		// the sealed epoch this is weighed at, which reads as a bug rather than
 823		// as the anti-flash-loan rule doing its job.
 824		if held := g.voters.PastVotes(who, at); held*bps < total*rules.ProposeBps {
 825			panic(ufmt.Sprintf("govern: not enough voting power to open this: "+
 826				"%s of the supply is required, and you held %d of %d at epoch %d",
 827				pct(rules.ProposeBps), held, total, at))
 828		}
 829	}
 830	// Everything may fill the board except the last few slots, which the
 831	// governor's own kinds keep — see govLanes.
 832	limit := maxLive
 833	if !isReserved(kind) {
 834		limit = maxOpen
 835	}
 836	if g.openIdx.Size() >= limit {
 837		// Try to reclaim before refusing: a full list is usually full of
 838		// finished business nobody has written down.
 839		g.sweep()
 840	}
 841	if g.openIdx.Size() >= limit {
 842		if limit < maxLive {
 843			panic("govern: too many proposals are already open; the last " +
 844				"few slots are kept for the governor's own kinds")
 845		}
 846		panic("govern: too many proposals are already open")
 847	}
 848	d := g.digest(kind, payload)
 849	if v := g.openIdx.Get(d); v != nil {
 850		// Settle the one already standing here before refusing on its account.
 851		//
 852		// The index holds finished proposals too — a read can work out that a
 853		// proposal lost but cannot write it down, and the sweep above only
 854		// runs when the list is FULL. So without this, a question defeated on
 855		// its deadline and left unrecorded blocks the same question from being
 856		// asked again, and the refusal says "already open" about something
 857		// that closed.
 858		//
 859		// Targeted rather than a scan: the one proposal actually in the way,
 860		// on the rare path where a digest collides at all.
 861		if pv := g.proposals.Get(v.(string)); pv != nil {
 862			g.settle(pv.(*proposal))
 863		}
 864	}
 865	if g.openIdx.Has(d) {
 866		panic("govern: an identical proposal is already open")
 867	}
 868	now := g.voters.Height()
 869	g.propSeq++
 870	p := &proposal{
 871		id: g.propSeq, kind: kind, payload: payload, title: title, proposer: who,
 872		rules: rules, epoch: at, total: total, engaged: engaged,
 873		quorumFloor: quorumFloor,
 874		opened:      now, closes: now + rules.VotingBlocks,
 875		openedTime:  g.voters.Now(),
 876		closesTime:  g.voters.Now() + rules.VotingBlocks*secsPerBlock,
 877		// The voter roll is bought here, by the proposer, including its first
 878		// node — see rollSentinel just below the Set. Whoever asks, pays.
 879		//
 880		// The alternative is to let the first voter buy it, on the argument
 881		// that a proposal nobody answers should cost nothing to leave
 882		// unanswered. That saving only ever accrues to a proposal that failed,
 883		// and it charges the first voter eleven times what the second pays.
 884		// Being early is the wrong thing to tax.
 885		//
 886		// Fanout 32 on purpose. A narrower tree makes that first node cheaper
 887		// (2,699 bytes at fanout 8 against 4,955) until the ninth voter, where
 888		// the tree splits and that vote costs 5,476 — thirteen times what the
 889		// eighth paid, for arriving in the wrong order. See
 890		// docs/DESIGN.md.
 891		state: stateActive, voted: bptree.NewBPTree32(),
 892	}
 893	p.voted.Set(rollSentinel, ballot(0))
 894	g.proposals.Set(enc(uint64(g.propSeq)), p)
 895	g.openIdx.Set(d, enc(uint64(g.propSeq)))
 896
 897	chain.Emit(proposalOpenedEvent,
 898		"id", strconv.FormatInt(g.propSeq, 10),
 899		"kind", kind,
 900		"proposer", who.String(),
 901		"epoch", strconv.FormatUint(uint64(at), 10),
 902	)
 903	return g.propSeq
 904}
 905
 906// Vote records a choice, weighed at the proposal's snapshot.
 907func (g *Governor) Vote(who address, id int64, choice string) {
 908	g.castVote(who, id, choice, "", 0)
 909}
 910
 911// VoteWithCap is Vote where the consumer supplies a CEILING on the weight, and
 912// the engine still derives the weight itself and takes the lesser.
 913//
 914// A CEILING, NEVER A WEIGHT, and the distinction is the whole reason this method
 915// is shaped like this. An earlier attempt added VoteWithWeight, which took the
 916// figure to tally. That was a permissionless verdict flip.
 917//
 918// A supplied weight is not drawn from p.total, so `cast` could exceed it and
 919// `rest := p.total - cast` went NEGATIVE. Written out, the two early arms are
 920//
 921//	early-succeed  yes*bps                    >= (total - abstain)*T
 922//	early-defeat   (total - no - abstain)*bps  < (total - abstain)*T
 923//
 924// because turnout is yes+no+abstain, so yes+no+rest is identically total-abstain.
 925// The damage was therefore an inflated NUMERATOR against a snapshotted denominator:
 926// `yes` could exceed anything the electorate held while (total - abstain) stayed
 927// put, passing on support that did not exist. And a negative rest shrinks
 928// (yes+rest), so the defeat arm could fire on a question still open.
 929//
 930// AN EARLIER VERSION OF THIS COMMENT SAID the arm "reduced to yes*bps >= (total -
 931// abstain)*T, dropping `no` out of the test entirely". The identity above shows
 932// that reduction is not a symptom of anything: it holds always, and `no` is not in
 933// the early-succeed comparison and never was. The description was repeated in four
 934// files before the algebra was checked, which is what
 935// TestTheEarlyArmsIgnoreNoAndACapOnlyDelays now pins. Here the consumer can only
 936// LOWER what this package read for itself, so
 937//
 938//	Σ w  ≤  Σ PastVotes(·, p.epoch)  ≤  PastTotal(p.epoch)  =  p.total
 939//
 940// holds as an inequality rather than as a promise a caller has to keep. A hostile
 941// consumer cannot raise `cast`, and the contract electorate.gno says this engine
 942// "cannot check and cannot recover from" stays enforced where it lives.
 943//
 944// NO SENTINEL. `cap <= 0` is refused, and Vote is the uncapped path. Treating zero
 945// as "uncapped" was tried in the plan for this change and reopened the exploit
 946// verbatim: a renter who has sold everything HAS a floor of zero, so zero is not an
 947// edge case, it is the attack's terminal state.
 948//
 949// Why a consumer would want this: kourtv2 caps at the voter's live balance, so
 950// weight that has been sold back cannot vote. See VOTEFLOOR.md.
 951func (g *Governor) VoteWithCap(who address, id int64, choice string, cap int64) {
 952	if cap <= 0 {
 953		panic("govern: a vote cap must be positive; use Vote for no cap")
 954	}
 955	g.castVote(who, id, choice, "", cap)
 956}
 957
 958// VoteWithReason is Vote with a note the voter wants on the record — the same
 959// pair OpenZeppelin has. Two entrypoints rather than one optional argument
 960// because MsgCall carries a fixed list of strings and gno has no optional
 961// parameters.
 962//
 963// The reason is emitted and never stored: it rides the Voted event, so the
 964// voter pays gas for the bytes and the ledger carries none of them. Storing it
 965// would be a new key per vote, on the path this design keeps cheapest.
 966//
 967// Bounded by maxReason. Not filtered through TextOnly, unlike a title: the
 968// realm never renders this on a page, so a consumer that displays it is
 969// responsible for its own escaping, as with any event field.
 970func (g *Governor) VoteWithReason(who address, id int64, choice, reason string) {
 971	if len(reason) > maxReason {
 972		panic("govern: that reason is too long")
 973	}
 974	g.castVote(who, id, choice, reason, 0)
 975}
 976
 977func (g *Governor) castVote(who address, id int64, choice, reason string, cap int64) {
 978	if g.executing {
 979		panic("govern: cannot vote from inside an execution or another vote")
 980	}
 981	// AND THE LATCH IS HELD FOR THIS CALL, not merely read at the top of it.
 982	//
 983	// It was read here and written only in Execute, which means it guarded
 984	// nothing on this path: a check with no corresponding write cannot exclude
 985	// anything. The hazard is specific and it is this function's own ordering —
 986	// the double-vote guard below reads p.voted, and p.voted is not written until
 987	// after g.voters.PastVotes has been called. Between those two lines sits a
 988	// call into an interface the CONSUMER supplies.
 989	//
 990	// So an Electorate whose PastVotes re-enters Vote for the same voter and
 991	// proposal gets a nested frame that passes the executing check (false) and
 992	// passes the already-voted check (not yet written), recurses, and adds its
 993	// weight again on every unwind. mustProposal hands back a pointer, so every
 994	// frame is adding to the same tally.
 995	//
 996	// Holding the latch for the whole call closes it at the door rather than by
 997	// reordering the body, which also covers g.settle's own reads of
 998	// g.voters.Height/Now above and below — the same class of call, made twice
 999	// more on this path.
1000	//
1001	// A consumer whose electorate is its own ledger — which is the only shape in
1002	// this repo, kourtv2 passes its grc20votes ledger as both electorate and
1003	// token — cannot reach this. The guard is for the ones that are not.
1004	g.executing = true
1005	defer func() { g.executing = false }()
1006	p := g.mustProposal(id)
1007	g.settle(p)
1008	if p.state != stateActive {
1009		panic("govern: that proposal is closed")
1010	}
1011	if p.voted.Has(string(who)) {
1012		panic("govern: already voted")
1013	}
1014	// Weighed as of the snapshot, so buying in after the question was asked buys
1015	// nothing, and selling out afterwards costs nothing.
1016	//
1017	// THE SECOND HALF IS A KNOWN, MEASURED EXPOSURE and it is still not closed
1018	// HERE — it is closed by the caller, if the caller chooses to. VoteWithCap
1019	// takes a ceiling and the clamp below applies it, so a consumer that passes
1020	// the voter's live balance gets min(snapshot, held) and the rental dies;
1021	// plain Vote leaves the exposure exactly as propose() describes it. kourtv2
1022	// caps all three of its lanes; r/govern does not. VOTEFLOOR.md has the
1023	// derivation and why both halves are needed.
1024	//
1025	// A 29-line block describing a LIVE-BALANCE CAP stood here and was wrong twice
1026	// over: the cap was implemented, reverted in the same commit, and the prose
1027	// outlived it — in a commit whose subject was "correct a false safety claim".
1028	// It also argued against a design this file then shipped. Recorded because the
1029	// lesson is the expensive one: a comment describing a reverted mechanism is a
1030	// false safety claim with a plausible pedigree.
1031	w := g.voters.PastVotes(who, p.epoch)
1032	if w <= 0 {
1033		panic("govern: no voting power at that epoch")
1034	}
1035	// The consumer's ceiling, and it may only LOWER. Written as an explicit clamp
1036	// rather than a min() helper so that the one property this block exists for —
1037	// w is never raised — is a single readable line that a guard can pin.
1038	if cap > 0 && cap < w {
1039		w = cap
1040	}
1041	switch choice {
1042	case "yes":
1043		p.yes += w
1044	case "no":
1045		p.no += w
1046	case "abstain":
1047		// Turnout, not indifference. Showing up to decline is a different
1048		// statement from silence, and it counts towards quorum while staying
1049		// out of the threshold.
1050		p.abstain += w
1051	default:
1052		panic("govern: choice must be yes, no or abstain")
1053	}
1054	// For a long time nothing read this — only Has() was ever asked of the
1055	// tree — and it was kept anyway, on the measurement that swapping the whole
1056	// value for a bool saves ONE byte per vote, because what a vote costs is
1057	// the address key and the tree's own entry overhead rather than the value
1058	// hanging off it. VoteOf reads it now, which is what the byte was for.
1059	p.voted.Set(string(who), packBallot(choice, w))
1060	g.settle(p)
1061
1062	// The reason rides along only when there is one. An empty attribute on
1063	// every vote would cost every voter gas to say nothing, and would leave an
1064	// indexer unable to tell a voter who declined to explain from one whose
1065	// client cannot ask.
1066	if reason == "" {
1067		chain.Emit(votedEvent,
1068			"id", strconv.FormatInt(id, 10),
1069			"voter", who.String(),
1070			"choice", choice,
1071			"weight", strconv.FormatInt(w, 10),
1072		)
1073		return
1074	}
1075	chain.Emit(votedEvent,
1076		"id", strconv.FormatInt(id, 10),
1077		"voter", who.String(),
1078		"choice", choice,
1079		"weight", strconv.FormatInt(w, 10),
1080		"reason", reason,
1081	)
1082}
1083
1084// ballot is one vote as cast. The weight is what the tally used; the choice is
1085// here so a kind can pay the side that voted with it, which is the whole reason
1086// VoteOf exists — a scheme that pays only the winners gives a juror expecting to
1087// lose no reason to turn up, which suppresses the honest side during exactly
1088// the manipulation a vote is meant to stop.
1089// A ballot is one int64, not a struct.
1090//
1091// The tree hands out each value as its own object for lazy loading, and a
1092// struct there is a SECOND object per vote — measured at 846 bytes a vote
1093// against 454 for a scalar. A vote is the one thing in this realm that happens
1094// thousands of times, so 405 bytes of object header is the wrong place to spend
1095// on tidiness.
1096//
1097// weight*4 + the choice. Two bits for three choices, and the weight is bounded
1098// by maxSupply, which is MaxInt64/10000 — so the shift cannot overflow with
1099// four orders of magnitude to spare.
1100type ballot int64
1101
1102const (
1103	ballotYes int64 = iota
1104	ballotNo
1105	ballotAbstain
1106)
1107
1108func packBallot(choice string, weight int64) ballot {
1109	switch choice {
1110	case "yes":
1111		return ballot(weight<<2 | ballotYes)
1112	case "no":
1113		return ballot(weight<<2 | ballotNo)
1114	case "abstain":
1115		return ballot(weight<<2 | ballotAbstain)
1116	}
1117	// Unreachable: castVote refuses anything else before it gets here. Panics
1118	// rather than defaulting, because a silent default would file a vote under
1119	// a choice nobody made.
1120	panic("govern: not a choice: " + choice)
1121}
1122
1123func (b ballot) unpack() (choice string, weight int64) {
1124	switch int64(b) & 3 {
1125	case ballotYes:
1126		choice = "yes"
1127	case ballotNo:
1128		choice = "no"
1129	default:
1130		choice = "abstain"
1131	}
1132	return choice, int64(b) >> 2
1133}
1134
1135// rollSentinel is the key Propose writes into a new voter roll, so that the
1136// roll's first node is bought by the person asking the question rather than by
1137// whoever happens to answer it first.
1138//
1139// A bptree allocates nothing until its first key, and its leaf carries
1140// fanout-sized backing arrays, so that first key costs about eleven times an
1141// ordinary insert. Left to the first voter, that is a tax on being early —
1142// which is the worst moment to put one, since a proposal with no votes yet is
1143// the one that needs the first.
1144//
1145// The empty string, because it is the one key no address can be: an address is
1146// bech32 and bech32 is never empty. Readers taking an address from outside are
1147// still told to refuse it, since "" arrives as a valid Go string from anybody
1148// who wants to ask.
1149const rollSentinel = ""
1150
1151// VoteOf is how an address voted, for a kind that has to pay them.
1152//
1153// One address at a time, on purpose. A list of every voter is an unbounded
1154// return, and handing back the tree itself would be a live mutator holding this
1155// realm's authority — so payouts are pull-based: each claimant asks about
1156// themselves.
1157//
1158// Answers only while the roll survives. It is dropped by ReleaseRoll, so a kind
1159// that pays out should either do it inside Do, where the roll is certainly
1160// intact, or tell its claimants that the window closes when somebody reclaims
1161// the deposit.
1162func (g *Governor) VoteOf(id int64, who address) (choice string, weight int64, ok bool) {
1163	p := g.mustProposal(id)
1164	if p.voted == nil || who == rollSentinel {
1165		return "", 0, false
1166	}
1167	v := p.voted.Get(string(who))
1168	if v == nil {
1169		return "", 0, false
1170	}
1171	choice, weight = v.(ballot).unpack()
1172	return choice, weight, true
1173}
1174
1175// wouldBe is what the rules and the clock say a proposal's state is, without
1176// writing anything down.
1177//
1178// Split out from settle because reads must not mutate. Render walks every
1179// proposal, and a settle-on-read there is an unbounded write hiding inside a
1180// function that looks like a query — discarded harmlessly when it IS a query,
1181// and a surprise when some realm calls Render inside a transaction.
1182//
1183// Every multiplication here is safe because the supply is capped at maxSupply.
1184// yes, no and abstain are each bounded by the snapshot total, and total*bps
1185// fits in int64 by construction.
1186func (g *Governor) wouldBe(p *proposal, now int64) (int8, string) {
1187	switch p.state {
1188	case stateActive:
1189		cast := turnout(p)
1190		// The bar: an absolute floor the consumer set for this proposal, or the
1191		// rules' QuorumBps fraction of the engaged weight when it did not.
1192		var quorum bool
1193		if p.quorumFloor > 0 {
1194			quorum = cast >= p.quorumFloor
1195		} else {
1196			quorum = cast*bps >= p.engaged*p.rules.QuorumBps
1197		}
1198		// Every vote not yet cast, all of which could still say no. Negative if
1199		// an electorate's parts exceed its whole, which this token cannot do
1200		// and a replacement might; a clamp here changed no outcome, because a
1201		// broken roll settles on the first vote either way. The contract is on
1202		// the electorate instead, where somebody swapping one will read it.
1203		rest := p.total - cast
1204		// p.yes > 0 is not redundant, and leaving it out was a real hole.
1205		//
1206		// The threshold compares yes against yes+no. When everybody ABSTAINS
1207		// both are zero, the comparison is 0 >= 0, and the proposal passed —
1208		// immediately, with nobody in favour, on the strength of an empty
1209		// denominator. Abstain is documented as turnout without support and it
1210		// was carrying proposals.
1211		//
1212		// Nothing passes without somebody voting for it, whatever the
1213		// threshold is set to.
1214		if quorum && p.yes > 0 && p.yes*bps >= (p.yes+p.no+rest)*p.rules.ThresholdBps {
1215			// Decided even if every remaining vote goes against. Waiting out
1216			// the clock on a settled question is latency, not deliberation —
1217			// and it is only computable because the denominator was
1218			// snapshotted, which is a third reason to snapshot.
1219			return stateSucceeded, ""
1220		}
1221		// And the same argument the other way, which was missing.
1222		//
1223		// If the threshold cannot be reached even with every remaining vote in
1224		// favour, the question is as settled as one that has already won — and
1225		// this side is the more common one, because a proposal that is going
1226		// to lose usually loses by everybody ignoring it.
1227		//
1228		// It was asymmetric for no reason anybody could have defended: a
1229		// decided YES closed at once while a decided NO sat out its deadline,
1230		// holding a slot in a list bounded at maxLive, asking a question that
1231		// had already been answered.
1232		if p.yes+rest == 0 {
1233			// Nobody in favour and nobody left who could be. Settled, whatever
1234			// the clock says — this is the all-abstained case, which now loses
1235			// at once instead of sitting out its deadline having already
1236			// failed.
1237			return stateDefeated, "nobody voted in favour"
1238		}
1239		if (p.yes+rest)*bps < (p.yes+rest+p.no)*p.rules.ThresholdBps {
1240			return stateDefeated, "threshold can no longer be reached"
1241		}
1242		if g.votingClosed(p, now) {
1243			if quorum && p.yes > 0 && p.yes*bps >= forAndAgainst(p)*p.rules.ThresholdBps {
1244				return stateSucceeded, ""
1245			}
1246			if !quorum {
1247				return stateDefeated, "quorum not reached"
1248			}
1249			return stateDefeated, "threshold not reached"
1250		}
1251		return stateActive, p.reason
1252
1253	case stateSucceeded:
1254		if g.expired(p) {
1255			// A proposal nobody executed for a long time is a decision about a
1256			// world that has moved. gno's own govdao has no deadline at all
1257			// and had to bolt on a reject path because proposals could sit
1258			// forever.
1259			return stateExpired, "not executed within the grace period"
1260		}
1261	}
1262	return p.state, p.reason
1263}
1264
1265// settle writes down what wouldBe worked out. Only ever called from a
1266// transaction, because only a transaction can record anything.
1267func (g *Governor) settle(p *proposal) {
1268	now := g.voters.Height()
1269	next, reason := g.wouldBe(p, now)
1270	if next == p.state {
1271		return
1272	}
1273	g.setState(p, next, reason)
1274	if next == stateSucceeded {
1275		// The delay runs from when the outcome is WRITTEN DOWN, not from when
1276		// the votes stopped mattering. Those differ for a proposal that wins on
1277		// its deadline: nobody has to be present when a deadline passes, so the
1278		// outcome is only recorded by the next transaction.
1279		//
1280		// Right way round — a timelock exists so people can react, and there is
1281		// nothing to react to until the decision is announced. Settle is
1282		// permissionless so announcing is never a privileged position.
1283		p.ready = now + p.rules.DelayBlocks
1284		p.readyTime = g.voters.Now() + p.rules.DelayBlocks*secsPerBlock
1285		return
1286	}
1287}
1288
1289// Execute runs a passed proposal. Permissionless on purpose: after the vote
1290// and the delay there is nothing left to decide, so there is nobody left to
1291// trust with the decision.
1292// Dispatch runs an adopted kind. The consuming realm supplies it, because it is
1293// the only thing that can: minting the sub-realm token a kind is handed needs a
1294// live `cur`, and a /p/ package has none.
1295//
1296// It receives the kind, the sub-path to mint under, and the payload — and
1297// NOTHING ELSE. No pointer into governor or ledger state passes through here,
1298// which is what makes dispatching third-party code safe: gno-security-guide.md
1299// §3(C) is about a victim invoking a caller-supplied value while holding its
1300// own authority, and the damage in that class is done through a pointer
1301// parameter. There is none to give.
1302//
1303// The realm's implementation is one line:
1304//
1305//	func(k governor.Kind, sub, payload string) error {
1306//		return k.Do(0, cur.Sub(sub), payload)
1307//	}
1308type Dispatch func(k Kind, subpath, payload string) error
1309
1310func (g *Governor) Execute(who address, id int64, run Dispatch) {
1311	if run == nil {
1312		// The engine holds no capability of its own, so without a dispatcher
1313		// there is nothing that could run a kind. Refused before anything is
1314		// written, so a caller who forgot one can supply it and retry.
1315		panic("govern: a dispatcher is required to run a kind")
1316	}
1317	if g.executing {
1318		panic("govern: re-entrant execution or vote")
1319	}
1320	p := g.mustProposal(id)
1321	g.settle(p)
1322	if p.state != stateSucceeded {
1323		panic("govern: that proposal is not waiting to be executed")
1324	}
1325	if g.inDelay(p) {
1326		// Says when, because "not yet" without a when is an invitation to poll.
1327		// The proposal page has carried this figure all along; the refusal a
1328		// caller actually receives did not.
1329		//
1330		// In the unit that GOVERNS: a caller told "1,000 blocks away" has to know
1331		// the chain's pace to turn that into "come back tomorrow", and the pace
1332		// is what this conversion exists to stop assuming. A proposal settled
1333		// before the stamps keeps the block form, which is all it ever had.
1334		if p.readyTime != 0 {
1335			panic(ufmt.Sprintf("govern: still in the delay window: executable at "+
1336				"%d (block %d), %d seconds away",
1337				p.readyTime, p.ready, p.readyTime-g.voters.Now()))
1338		}
1339		now := g.voters.Height()
1340		panic(ufmt.Sprintf("govern: still in the delay window: executable at "+
1341			"height %d, %d blocks away", p.ready, p.ready-now))
1342	}
1343	e := g.entryOf(p.kind)
1344	if e == nil || !e.live {
1345		// The holders withdrew this power while the proposal was waiting.
1346		// Recorded as a failure rather than a panic: the proposal is finished
1347		// either way, and a panic would leave it Succeeded forever, retried by
1348		// anyone, failing identically each time.
1349		g.setState(p, stateFailed, "the kind was retired before this could run")
1350		return
1351	}
1352	k := e.kind
1353
1354	// Checked again, against the world as it is now rather than as it was when
1355	// the question was asked.
1356	if err := g.checkKind(k, p.payload); err != nil {
1357		g.setState(p, stateFailed, "no longer valid: "+err.Error())
1358		return
1359	}
1360
1361	// Deferred, not cleared on the next line. If Do panics the transaction
1362	// aborts and the flag rolls back with everything else — but a recover
1363	// anywhere between here and there would leave the latch set and the
1364	// governor permanently unable to run anything again.
1365	g.executing = true
1366	defer func() { g.executing = false }()
1367	// The kind gets a SUB-REALM, never the realm's own capability — which is
1368	// why the sub-path is computed here and handed out, rather than left to
1369	// whoever writes the Dispatch.
1370	//
1371	// A live cur inside a foreign kind's Do has IsCurrent() true and the
1372	// consuming realm's PkgPath, so it is not "the realm as data", it is that
1373	// realm's authority, handed to code the holders adopted for one purpose.
1374	// With it a kind can cross() into any realm that trusts the consumer and be
1375	// seen as it, issue its tokens, and drain its banker. Adopting a treasury
1376	// kind would grant reach over every realm that names this one.
1377	//
1378	// cur.Sub gives a distinct pkgpath and a distinct address, and the VM
1379	// refuses RealmIssue for a sub-realm outright. A governed realm therefore
1380	// gates on the sub-path of the power it granted, which is also more useful
1381	// than gating on the governor as a whole.
1382	var err error
1383	if b, ok := asBuiltin(k); ok {
1384		// The governor's own kinds act on the governor. They are handed it
1385		// directly and never a sub-realm: there is no outside world for them
1386		// to reach, so there is nothing to grant.
1387		err = b.run(g, run, p.payload)
1388	} else {
1389		err = run(k, subPathOf(p.kind), p.payload)
1390	}
1391
1392	if err != nil {
1393		g.setState(p, stateFailed, err.Error())
1394		return
1395	}
1396	g.setState(p, stateExecuted, "")
1397}
1398
1399// ReleaseRoll drops a finished proposal's voter roll and refunds its deposit to
1400// whoever calls.
1401//
1402// The roll does not go when a proposal settles, because a kind that pays out to
1403// the people who voted has to ask after the fact, and pull-based claiming means
1404// the last claim can be a long way after execution. So it is reclaimed on
1405// request instead: nobody is obliged to, and whoever does is paid for it — the
1406// same bargain Settle makes for the slot.
1407//
1408// Refused twice over. While a proposal is open, because Vote reads the roll to
1409// refuse a second vote and dropping it early would let everybody vote twice.
1410// And while it has SUCCEEDED but not yet run, because that is exactly the
1411// window in which the kind has not read it yet — Execute is where a kind that
1412// pays its voters looks, so a stranger could otherwise empty the roll in the
1413// block before execution and leave the kind with nobody to pay. Waiting for the
1414// execution to land costs the reclaimer nothing; there is no deadline on this.
1415func (g *Governor) ReleaseRoll(who address, id int64) {
1416	p := g.mustProposal(id)
1417	g.settle(p)
1418	switch p.state {
1419	case stateActive:
1420		panic("govern: that proposal is still open; its roll is what refuses a second vote")
1421	case stateSucceeded:
1422		panic("govern: that proposal has not run yet; the roll is what it runs against")
1423	}
1424	p.voted = nil
1425}
1426
1427// Settle advances a proposal's state and frees its slot if it is finished.
1428//
1429// Needed because a read cannot persist: State and Render will tell you a
1430// proposal is defeated and tell you again tomorrow, since the transition they
1431// computed died with the query. Without a way to record it, the open list is a
1432// resource anybody can exhaust — fill every slot with proposals that will lose
1433// and nothing ever reclaims them.
1434//
1435// Permissionless, because it decides nothing: it writes down a conclusion the
1436// rules already reached.
1437func (g *Governor) Settle(who address, id int64) {
1438	g.settle(g.mustProposal(id))
1439}
1440
1441// sweep frees the slots of a few finished proposals. Bounded, and run when
1442// somebody proposes — the moment a full list matters, paid for by whoever wants
1443// the room. Unbounded here would make one unlucky proposer tidy the history.
1444//
1445
1446const sweepScan = 8
1447
1448func (g *Governor) sweep() {
1449	// openIdx cannot exceed maxLive — Propose refuses at the bound — so the
1450	// whole ring is a handful of windows. Trying them until one frees a slot is
1451	// still a BOUNDED scan; the bound that matters here is the index's, not the
1452	// history's, and it is the history that the per-window limit exists to keep
1453	// one unlucky proposer from paying to tidy.
1454	for w := 0; w <= maxLive/sweepScan; w++ {
1455		before := g.openIdx.Size()
1456		g.sweepWindow()
1457		if g.openIdx.Size() < before {
1458			return
1459		}
1460	}
1461}
1462
1463func (g *Governor) sweepWindow() {
1464	const scan = sweepScan
1465
1466	// Collected first, acted on after: settle removes from openIdx, and bptree
1467	// says a tree must not be modified during iteration (tree.gno). Calling it
1468	// from the callback removed the key the cursor stood on.
1469	//
1470	// No failure was observed and that is not evidence of safety — at this size
1471	// the tree tolerates it. The symptom, if it does not, is a slot that never
1472	// comes back, months later, under load.
1473	seen := 0
1474	last := ""
1475	var ids []string
1476	var stale []string
1477	g.openIdx.Iterate(g.sweepFrom, "", func(k string, v any) bool {
1478		seen++
1479		last = k
1480		if g.proposals.Get(v.(string)) == nil {
1481			stale = append(stale, k)
1482		} else {
1483			ids = append(ids, v.(string))
1484		}
1485		return seen >= scan
1486	})
1487	// Where to resume. A short window means the end of the index was reached,
1488	// so the next one starts over; otherwise it starts just past the last key
1489	// looked at. Appending a NUL gives the smallest string above a key, and the
1490	// keys are all the same length, so nothing can sort between the two.
1491	if seen < scan {
1492		g.sweepFrom = ""
1493	} else {
1494		g.sweepFrom = last + "\x00"
1495	}
1496
1497	for _, key := range ids {
1498		if p := g.proposals.Get(key); p != nil {
1499			g.settle(p.(*proposal))
1500		}
1501	}
1502	// Index entries whose proposal has gone entirely, which settle cannot
1503	// reach because there is nothing left to settle.
1504	for _, k := range stale {
1505		g.openIdx.Remove(k)
1506	}
1507}
1508
1509// Cancel withdraws a proposal. Only the proposer, only while it is still open.
1510func (g *Governor) Cancel(who address, id int64) {
1511	p := g.mustProposal(id)
1512	if who != p.proposer {
1513		panic("govern: only the proposer may cancel")
1514	}
1515	g.settle(p)
1516	if p.state != stateActive {
1517		panic("govern: too late to cancel")
1518	}
1519	// The one transition out of active that the rules do not make.
1520	g.setState(p, stateCanceled, "")
1521}
1522
1523// ----------------------------------------------------------------- reading --
1524
1525// State advances the clock before answering, so a reader never sees a proposal
1526// that is active only because nobody has poked it.
1527func (g *Governor) State(id int64) string {
1528	p := g.mustProposal(id)
1529	// The pure form: asking what a proposal's state is must not change it.
1530	st, _ := g.wouldBe(p, g.voters.Height())
1531	// COULD HAVE (v2): `return stateName(st)`. This switch is character-identical
1532	// to stateName six hundred lines below, and an exhaustive switch written
1533	// twice is a trap -- add an eighth state and whichever copy you forget
1534	// renders it as "expired", since both reach that string through the default
1535	// arm. Left as deployed: p/governor is on gnoland-1 and deploys once.
1536	switch st {
1537	case stateActive:
1538		return "active"
1539	case stateDefeated:
1540		return "defeated"
1541	case stateSucceeded:
1542		return "succeeded"
1543	case stateExecuted:
1544		return "executed"
1545	case stateFailed:
1546		return "failed"
1547	case stateCanceled:
1548		return "canceled"
1549	default:
1550		return "expired"
1551	}
1552}
1553
1554// Preview renders what a payload would say, before anybody proposes it — so an
1555// interface can show somebody their proposal, and Check refuses a malformed one
1556// without spending a transaction.
1557//
1558// It also pins the thing the extension point rests on: govern calling INTO a
1559// kind in another realm. A stored interface value is re-resolved from the store
1560// on every call, so the method that runs is the offering realm's code.
1561//
1562// Reads whether or not the kind is adopted. What a payload would say is not a
1563// power, and refusing to preview an unadopted one makes the adoption vote
1564// harder to judge rather than safer.
1565func (g *Governor) Preview(kind, payload string) string {
1566	// The same bound Propose applies, at the cheaper door. Propose is a
1567	// transaction and this is a read, so an unbounded payload here is the
1568	// easier of the two to hand over — and it reaches the same Describe and
1569	// Check with it. Bounding one door and not the other is not bounding
1570	// anything.
1571	if len(payload) > maxPayload {
1572		return "that payload is too long"
1573	}
1574	e := g.entryOf(kind)
1575	if e == nil {
1576		return "no kind by that name has been offered"
1577	}
1578	out := g.describeKind(e.kind, payload)
1579	if err := g.checkKind(e.kind, payload); err != nil {
1580		out += "\n\n_This would be refused: " + err.Error() + "_"
1581	}
1582	if !e.live {
1583		out += "\n\n_This kind has not been adopted, so it cannot be proposed yet._"
1584	}
1585	return out
1586}
1587
1588// Describe is what the vote is about, rendered by the kind from the payload
1589// alone — the same string Do will be handed.
1590func (g *Governor) Describe(id int64) string {
1591	p := g.mustProposal(id)
1592	return g.describeOf(p)
1593}
1594
1595// HasVoted reports whether an address has already voted on a proposal.
1596//
1597// OpenZeppelin has hasVoted; without it the only way to find out is to send a
1598// vote and be refused, spending a transaction to learn what the realm knows. A
1599// wallet needs it before deciding whether to offer the buttons.
1600//
1601// Keeps answering after a proposal closes, because the roll survives until
1602// somebody calls ReleaseRoll. Once it has been released this answers false, so
1603// it is "is their vote still on record here", not "did they ever" — the
1604// permanent record of who voted is the Voted events.
1605func (g *Governor) HasVoted(id int64, who address) bool {
1606	p := g.mustProposal(id)
1607	return p.voted != nil && who != rollSentinel && p.voted.Has(string(who))
1608}
1609
1610// secsPerBlock converts a VotingBlocks rule — configured in blocks, as every
1611// governor rule is — into the wall-clock window it was chosen to mean.
1612const secsPerBlock = int64(5)
1613
1614// votingClosed reports whether a proposal has stopped taking votes.
1615//
1616// THE DEADLINE IS THE PROMISE, THE HEIGHT IS THE FALLBACK. Counted in blocks a
1617// window advertised as "four days" is four days only while the chain holds its
1618// assumed pace; the report that started this work showed a vote "closing in ~7
1619// days" beside an answer dated five years earlier. A proposal opened before the
1620// stamps existed has closesTime 0 and keeps the height it was opened under.
1621func (g *Governor) votingClosed(p *proposal, now int64) bool {
1622	if p.closesTime != 0 {
1623		return g.voters.Now() >= p.closesTime
1624	}
1625	return now >= p.closes
1626}
1627
1628// TimingsAt is Timings' wall-clock half: when the proposal opened and when
1629// voting closes, as unix seconds, or 0 for a proposal opened before the stamps.
1630//
1631// A SIBLING RATHER THAN A WIDER Timings, because Timings is consumed by more
1632// than one realm and arity is the kind of change that should arrive with its
1633// readers rather than ahead of them. Its first reader lands in the same commit
1634// as this method — kourtv2's ClaimTimeline — which is the rule the clock plan
1635// applies to constants and which holds just as well for a read.
1636//
1637// The heights stay on Timings and are still the reference; this is the number
1638// the gate actually compares against, so a page built from it cannot promise a
1639// close the governor will not honour.
1640func (g *Governor) TimingsAt(id int64) (openedTime, closesTime int64) {
1641	p := g.mustProposal(id)
1642	return p.openedTime, p.closesTime
1643}
1644
1645// Timings is a proposal's clock: when it opened, when voting closes, when it
1646// becomes executable, and when that chance lapses. The companion to Tally —
1647// without it, anything showing a countdown parsed the page, which is prose
1648// written for people.
1649//
1650// Two of these are zero rather than absent, and both zeroes mean something:
1651//
1652//	ready == 0    the outcome is not recorded yet, so the timelock has not
1653//	              started. Settle starts it, and anybody may call it.
1654//	expires == 0  it never expires, which is what a grace period of zero means
1655//	              everywhere else in this realm.
1656func (g *Governor) Timings(id int64) (opened, closes, ready, expires int64) {
1657	p := g.mustProposal(id)
1658	at, ever := expiresAt(p)
1659	if !ever {
1660		at = 0
1661	}
1662	return p.opened, p.closes, p.ready, at
1663}
1664
1665// Tally is the vote so far: yes, no, abstain, and the supply they are weighed
1666// against.
1667//
1668// The fourth number is the one worth having. Every bar here is a fraction —
1669// quorum of the snapshot supply, threshold of what was cast — so three counts
1670// without their denominator cannot be checked against anything. It is the
1671// supply at the proposal's snapshot epoch, not the supply now.
1672func (g *Governor) Tally(id int64) (yes, no, abstain, total int64) {
1673	p := g.mustProposal(id)
1674	return p.yes, p.no, p.abstain, p.total
1675}
1676
1677// Render is the governance page.
1678//
1679// It matters more here than a Render usually does. This design's whole claim
1680// over one that carries code is that what a voter reads IS what executes —
1681// Describe and Do consume the same string. That claim is only worth anything
1682// if somebody actually reads it, so the description is on the page rather than
1683// behind a call nobody makes.
1684func (g *Governor) render(path, notes string) string {
1685	if path != "" {
1686		return g.renderOne(path)
1687	}
1688	out := ufmt.Sprintf("# %s (%s)\n\n", g.token.Name(), g.token.Symbol())
1689
1690	// The token first, because the governance below is only meaningful in
1691	// terms of it: every quorum is a fraction of this supply and every vote is
1692	// weighed out of it.
1693	out += ufmt.Sprintf("- supply: %s %s (%d at %d decimals)\n",
1694		g.units(g.token.TotalSupply()), g.token.Symbol(), g.token.TotalSupply(), g.token.Decimals())
1695	out += notes
1696	out += ufmt.Sprintf("- epoch: %d (votes are weighed at sealed epochs)\n\n", g.voters.Epoch())
1697	out += "## governance\n\n"
1698
1699	var open, ready, done string
1700	nOpen := 0
1701	now := g.voters.Height()
1702
1703	// The open list IS openIdx: a proposal holds its slot until it reaches a
1704	// final state, so what is in there is exactly what belongs above the fold.
1705	// Bounded by maxLive rather than by how many questions have ever been
1706	// asked.
1707	g.openIdx.Iterate("", "", func(_ string, v any) bool {
1708		pv := g.proposals.Get(v.(string))
1709		if pv == nil {
1710			return false
1711		}
1712		p := pv.(*proposal)
1713		st, _ := g.wouldBe(p, now)
1714		if st != stateActive && st != stateSucceeded {
1715			// Finished, and still holding its slot because nobody has written
1716			// that down. The scan below reaches it as history, which is what
1717			// it is.
1718			return false
1719		}
1720		if st == stateSucceeded {
1721			ready += proposalLine(p, st)
1722		} else {
1723			open += proposalLine(p, st)
1724		}
1725		nOpen++
1726		return false
1727	})
1728
1729	// Newest first, and it stops as soon as the tail is full.
1730	//
1731	// The cap is on the WORK, not just on what gets appended. One pass over
1732	// every proposal the realm has ever held, computing each state and
1733	// truncating at the end, would grow forever while the page stayed the same
1734	// size — and this is the read every holder makes.
1735	g.proposals.ReverseIterate("", "", func(_ string, v any) bool {
1736		if len(done) >= 2000 {
1737			return true
1738		}
1739		p := v.(*proposal)
1740		st, _ := g.wouldBe(p, now)
1741		if st == stateActive || st == stateSucceeded {
1742			return false // already above, from g.openIdx
1743		}
1744		done += proposalLine(p, st)
1745		return false
1746	})
1747
1748	// Split by what the reader is asked to DO, not by which list the realm
1749	// keeps them in. Both hold a slot, but a decided proposal waiting out its
1750	// timelock is not something to vote on, and putting it under a heading that
1751	// means "still being voted on" tells the reader to do the wrong thing.
1752	//
1753	// The slot count belongs to the page rather than to either section. nOpen
1754	// counts everything holding a slot, decided-and-unrun included, so under a
1755	// voting heading it would sit above a shorter list — and vanish entirely
1756	// when every slot is held by decided proposals, which is when being full
1757	// matters most.
1758	// And the lane, once it is the only thing left. Below that point the count
1759	// is the whole story; at or above it, a holder reads free slots and is
1760	// refused anyway, which is the page contradicting the realm.
1761	out += ufmt.Sprintf("%d of %d slots in use", nOpen, maxLive)
1762	if nOpen >= maxOpen {
1763		out += ufmt.Sprintf("; the last %d are kept for the governor's own kinds, "+
1764			"so nothing else can be opened until one comes back", maxLive-maxOpen)
1765	}
1766	out += ".\n\n"
1767	if open == "" {
1768		out += "_Nothing to vote on._\n"
1769	} else {
1770		out += "### to vote on\n\n" + open
1771	}
1772	if ready != "" {
1773		out += "\n### decided, waiting to be run\n\n" + ready
1774	}
1775	if done != "" {
1776		out += "\n### finished\n\n" + done
1777	}
1778	return out
1779}
1780
1781func (g *Governor) renderOne(path string) string {
1782	id, err := strconv.ParseInt(path, 10, 64)
1783	if err != nil {
1784		return "# not a proposal id\n"
1785	}
1786	v := g.proposals.Get(enc(uint64(id)))
1787	if v == nil {
1788		return "# no such proposal\n"
1789	}
1790	p := v.(*proposal)
1791	st, reason := g.wouldBe(p, g.voters.Height())
1792
1793	out := ufmt.Sprintf("# #%d — %s\n\n", p.id, p.title)
1794	// The description first, and rendered by the kind from the payload alone.
1795	// This is the text the vote is about.
1796	out += g.describeOf(p) + "\n\n"
1797	out += ufmt.Sprintf("- kind: `%s`\n- proposer: %s\n- state: **%s**\n",
1798		p.kind, p.proposer.String(), stateName(st))
1799	if reason != "" {
1800		out += "- reason: " + reason + "\n"
1801	}
1802	// The snapshot supply, rendered as the header renders the live one — it is
1803	// the same quantity, and it was raw here and in units there.
1804	//
1805	// The tally BELOW stays raw on purpose. Its stated job is to let a reader
1806	// check the arithmetic rather than take the state on trust, and mixing
1807	// units into numbers somebody is about to multiply would take that away.
1808	// Two renderings of the same kind of figure, for two different jobs, on one
1809	// page — which is worth saying because it looks like the inconsistency it
1810	// was just fixed for.
1811	out += ufmt.Sprintf("- weighed at epoch %d, when %s %s was in issue (%d)\n",
1812		p.epoch, g.units(p.total), g.token.Symbol(), p.total)
1813	out += ufmt.Sprintf("\n## votes\n\n- yes %d\n- no %d\n- abstain %d\n",
1814		p.yes, p.no, p.abstain)
1815	// Both bars, as counted, so a reader can check the arithmetic rather than
1816	// take the state on trust.
1817	cast := turnout(p)
1818	// Percentages, not basis points. The realm counts in bps because integers
1819	// are exact where a float is an argument waiting to happen, and pct() exists
1820	// precisely so that choice does not reach the page — a holder asked to read
1821	// "needs 6600 bps" is being asked to do arithmetic to find out whether their
1822	// vote mattered.
1823	// Against ENGAGED, because that is what quorum divides by. Equal to total
1824	// for this realm; an electorate that drops idle weight would otherwise show
1825	// a bar nobody is being measured against.
1826	//
1827	// A consumer-set absolute floor is rendered as the count it is, not a
1828	// fraction of engaged — the tally compares cast against that number, so the
1829	// page must show it or it contradicts the state it is describing.
1830	if p.quorumFloor > 0 {
1831		out += ufmt.Sprintf("\nturnout %d of %d, needs %d · ", cast, p.engaged, p.quorumFloor)
1832	} else {
1833		out += ufmt.Sprintf("\nturnout %d of %d, needs %s · ", cast, p.engaged, pct(p.rules.QuorumBps))
1834	}
1835	// Three cases, not two. The threshold weighs yes against yes+no, so it has
1836	// nothing to weigh when every vote was an abstention — but that is not the
1837	// same as nobody voting, and collapsing them prints a line that contradicts
1838	// itself:
1839	//
1840	//	turnout 1000 of 1000, needs 20.00% · no votes cast
1841	//
1842	// The whole supply voted. Saying so on the left and denying it on the right
1843	// is worst for the one case this realm treats most carefully: an
1844	// all-abstained proposal is the one that would otherwise pass with nobody
1845	// in favour, which is why the support bar exists at all.
1846	switch {
1847	case forAndAgainst(p) > 0:
1848		out += ufmt.Sprintf("yes is %d of %d cast, needs %s\n",
1849			p.yes, forAndAgainst(p), pct(p.rules.ThresholdBps))
1850	case p.abstain > 0:
1851		out += "every vote was an abstention, so the threshold has nothing to weigh\n"
1852	default:
1853		out += "no votes cast\n"
1854	}
1855
1856	// When voting closes. The block below was written for the succeeded state
1857	// on the reasoning that it is the one state where a reader has something to
1858	// do and no way to know when — which was right, and stopped one state
1859	// short: an active proposal is where they have the most to do.
1860	//
1861	// The subtraction is safe. wouldBe returns a terminal state once now has
1862	// reached p.closes, so a proposal reading active has not.
1863	if st == stateActive {
1864		// THE DATE, not a block count. "closes in 120,960 blocks" is a promise
1865		// only a reader who knows the chain's pace can check, and the pace is not
1866		// a promise — that mismatch is what put a vote "closing in ~7 days" beside
1867		// an answer dated five years earlier. A proposal opened before the stamps
1868		// has no date and keeps the block form it was opened under.
1869		if p.closesTime != 0 {
1870			// A COUNTDOWN AND AN ABSOLUTE, because they answer different
1871			// questions: the count tells a reader how long they have, and the
1872			// date is what the gate will actually compare against, so a page
1873			// read at one moment is still checkable at the next. The old line
1874			// gave a count in BLOCKS, which is only a duration to a reader who
1875			// knows the chain's pace — and the pace is what was wrong.
1876			out += ufmt.Sprintf("\n_Voting closes in %d seconds, at %d (block %d)._\n",
1877				p.closesTime-g.voters.Now(), p.closesTime, p.closes)
1878		} else {
1879			out += ufmt.Sprintf("\n_Voting closes in %d blocks, at height %d._\n",
1880				p.closes-g.voters.Height(), p.closes)
1881		}
1882	}
1883
1884	// What happens next, for a decision that has been taken and not yet done.
1885	//
1886	// Without this the page says "succeeded" and stops, which is the one state
1887	// where a reader has something to DO and no way to know when. It is also
1888	// the state that looks most like nothing is happening: the proposal sits on
1889	// the open list, apparently unfinished, while a timelock it cannot see runs
1890	// down.
1891	if st == stateSucceeded {
1892		now := g.voters.Height()
1893		expiry, expires := expiresAt(p)
1894		switch {
1895		case p.state != stateSucceeded:
1896			// Decided and not yet written down — what a proposal winning on its
1897			// DEADLINE looks like, since nobody has to be present when one
1898			// passes.
1899			//
1900			// p.ready is zero until then, so the lines below would be
1901			// arithmetic against nothing — "succeeded" and "expired" printed
1902			// together. Saying what is actually needed is the useful thing
1903			// anyway, because anybody may Settle it.
1904			out += "\n_Decided, and nobody has recorded it yet. The delay " +
1905				"starts when somebody calls Settle — anybody may._\n"
1906		case g.inDelay(p):
1907			// SECONDS AND THE ABSOLUTE, for the reason the voting close carries
1908			// both: a count in blocks is a duration only to a reader who knows
1909			// the chain's pace. A proposal settled before the stamps keeps the
1910			// block form, which is all it ever had.
1911			if p.readyTime != 0 {
1912				out += ufmt.Sprintf("\n_Waiting: executable in %d seconds, at %d (block %d)._\n",
1913					p.readyTime-g.voters.Now(), p.readyTime, p.ready)
1914			} else {
1915				out += ufmt.Sprintf("\n_Waiting: executable in %d blocks, at height %d._\n",
1916					p.ready-now, p.ready)
1917			}
1918		case g.expired(p):
1919			out += "\n_Expired: nobody executed it in time._\n"
1920		case expires:
1921			out += ufmt.Sprintf("\n**Executable now**, until height %d.\n", expiry)
1922		default:
1923			out += "\n**Executable now.**\n"
1924		}
1925	}
1926	return out
1927}
1928
1929// proposerBar renders the stake a proposer must hold, where zero is not "none
1930// required" so much as "no check at all".
1931func proposerBar(bps int64) string {
1932	if bps <= 0 {
1933		return "anybody, holding nothing"
1934	}
1935	return pct(bps) + " of the supply"
1936}
1937
1938// turnout is every vote cast, abstentions included. One definition because it
1939// was two: the tally computed it and the page computed it again, so the quorum
1940// a proposal was DECIDED by and the figure a holder READ could diverge. That
1941// line has already produced two page-versus-state contradictions.
1942//
1943// Abstain counts here because it counts towards quorum, which is why the
1944// support bar exists separately.
1945func turnout(p *proposal) int64 { return p.yes + p.no + p.abstain }
1946
1947// forAndAgainst is what the threshold weighs: the votes that took a side.
1948//
1949// Abstentions are deliberately absent — they count towards quorum and not
1950// towards the bar — and that rule was written once in the tally and again on
1951// the page, which is how a page comes to disagree with the state it describes.
1952func forAndAgainst(p *proposal) int64 { return p.yes + p.no }
1953
1954// inDelay is whether a decided proposal is still inside its timelock.
1955//
1956// Execute refuses while this holds and the page counts down while it holds, and
1957// those two must not disagree by even a block: a page offering to run what
1958// Execute will refuse is the same defect as a page calling a live proposal
1959// expired. One definition, so a boundary cannot be moved on one side only.
1960func (g *Governor) inDelay(p *proposal) bool {
1961	if p.readyTime != 0 {
1962		return g.voters.Now() < p.readyTime
1963	}
1964	return g.voters.Height() < p.ready
1965}
1966
1967// expired reports whether a decided proposal is past its execution window.
1968//
1969// THE TWO WINDOWS MOVE TOGETHER, and that is why they convert together: the
1970// delay exists so people can react, and the grace exists so a decision about a
1971// world that has moved cannot be executed. Both are measured from p.ready, so
1972// converting one and not the other would let a proposal leave its delay on one
1973// clock and expire on the other — a gap where it is neither waiting nor
1974// executable, or an overlap where it is both.
1975func (g *Governor) expired(p *proposal) bool {
1976	if at, ever := expiresAtTime(p); ever {
1977		return g.voters.Now() > at
1978	}
1979	at, ever := expiresAt(p)
1980	return ever && g.voters.Height() > at
1981}
1982
1983// expiresAtTime is expiresAt in wall-clock seconds, or (0, false) for a
1984// proposal settled before the stamps existed.
1985func expiresAtTime(p *proposal) (int64, bool) {
1986	if p.rules.GraceBlocks <= 0 || p.readyTime == 0 {
1987		return 0, false
1988	}
1989	return p.readyTime + p.rules.GraceBlocks*secsPerBlock, true
1990}
1991
1992// expiresAt is when a decided proposal stops being executable, and whether it
1993// ever does. saneRules refuses a grace of zero, so in practice it always does.
1994//
1995// One definition because it is easy to write three: the tally testing
1996// `now > ready+grace`, the page testing it again, and the page printing the sum
1997// a third time as the height it offers to run until. Three independent copies
1998// of one deadline is how a page comes to print "succeeded" and "expired"
1999// together.
2000func expiresAt(p *proposal) (int64, bool) {
2001	// Nothing expires before the outcome is written down, because the window is
2002	// measured from p.ready and p.ready is zero until Settle sets it. Adding a
2003	// grace period to nothing gives a deadline in the realm's first hour, which
2004	// is how a page once printed "succeeded" and "expired" together.
2005	//
2006	// The page guards that by checking the recorded state before it asks; the
2007	// guard belongs here, where the arithmetic is. Timings walked straight into
2008	// it the moment it exposed this to a caller who had not read the page's
2009	// comment.
2010	// saneRules refuses a grace of zero, so that arm is defence rather than
2011	// policy; p.ready is the live one.
2012	if p.rules.GraceBlocks <= 0 || p.ready == 0 {
2013		return 0, false
2014	}
2015	return p.ready + p.rules.GraceBlocks, true
2016}
2017
2018// span renders a period in blocks, with roughly how long that is.
2019//
2020// Correctness never depends on the wall clock, but "120960 blocks to vote"
2021// does not tell a reader whether that is an afternoon or a season. Both are
2022// printed and the approximation is marked as one.
2023//
2024// Five seconds a block, the same assumption the bootstrap rules were chosen
2025// under. At another cadence the block counts are still exact and the hours are
2026// not, which is why they are hedged.
2027func span(blocks int64) string {
2028	if blocks <= 0 {
2029		return "no period"
2030	}
2031	secs := blocks * 5
2032	switch {
2033	case secs < 60*60:
2034		return ufmt.Sprintf("%d blocks (about %s)", blocks, plural(secs/60, "minute"))
2035	case secs < 48*60*60:
2036		return ufmt.Sprintf("%d blocks (about %s)", blocks, plural(secs/3600, "hour"))
2037	default:
2038		return ufmt.Sprintf("%d blocks (about %s)", blocks, plural(secs/86400, "day"))
2039	}
2040}
2041
2042// plural writes a count with its unit, in the number the count deserves.
2043//
2044// "1 hours" reads as something a machine wrote, and a page that reads as
2045// machine-written gets skimmed — which is a poor outcome for the text somebody
2046// is meant to study before granting a power.
2047func plural(n int64, unit string) string {
2048	if n == 1 {
2049		return "1 " + unit
2050	}
2051	return ufmt.Sprintf("%d %ss", n, unit)
2052}
2053
2054// units renders a base-unit amount the way a holder counts it. The ledger is
2055// integers all the way down, which is exact and unreadable: "supply: 1000"
2056// beside "decimals: 6" asks somebody to divide before they know whether they
2057// hold a millionth of the token or all of it. Both are printed — this for
2058// reading, the raw figure for checking.
2059//
2060// scale is 10^decimals for the token being rendered — computed, not a constant,
2061// because Go has no constant exponentiation and the engine does not know what token
2062// it renders until given one (TestTheEngineRendersTheTokensOwnScale checks it).
2063// Decimals is CLAMPED to 18 first: 10^19 overflows int64 (and 10^k for k≥64 wraps to
2064// 0, which would divide-by-zero in units()), so an unclamped power on a pathological
2065// token would corrupt or panic Render. Render is a read, so a clamp on the rare bad
2066// token is the right trade; grc20votes reports a small fixed decimals and is unaffected.
2067func (g *Governor) scale() int64 {
2068	d := g.token.Decimals()
2069	if d > 18 {
2070		d = 18
2071	}
2072	out := int64(1)
2073	for i := 0; i < d; i++ {
2074		out *= 10
2075	}
2076	return out
2077}
2078
2079func (g *Governor) units(n int64) string {
2080	whole := n / g.scale()
2081	frac := n % g.scale()
2082	// The sign has to be taken from n, not from the whole part. Integer
2083	// division truncates towards zero, so everything between -1 and 0 has a
2084	// whole part of exactly 0 — and a "-0" that FormatInt prints as "0". Taking
2085	// the minus from whole therefore dropped it for that entire range, and
2086	// -0.5 rendered as 0.5: not a near miss but the opposite number.
2087	sign := ""
2088	if n < 0 {
2089		sign = "-"
2090		whole, frac = -whole, -frac
2091	}
2092	out := strconv.FormatInt(frac, 10)
2093	for len(out) < g.token.Decimals() {
2094		out = "0" + out
2095	}
2096	// Trailing zeroes are noise; a whole number should read as one.
2097	for len(out) > 1 && out[len(out)-1] == '0' {
2098		out = out[:len(out)-1]
2099	}
2100	if out == "0" {
2101		return sign + strconv.FormatInt(whole, 10)
2102	}
2103	return sign + strconv.FormatInt(whole, 10) + "." + out
2104}
2105
2106// proposalLine is one row of the governance list.
2107func proposalLine(p *proposal, st int8) string {
2108	return ufmt.Sprintf("- [#%d](:%d) **%s** — `%s` · %s\n",
2109		p.id, p.id, p.title, p.kind, stateName(st))
2110}
2111
2112// maxReason bounds what a kind may write into the permanent record.
2113//
2114// An adopted kind is trusted — the holders voted it the power to run — so this
2115// is not a defence against a hostile one, which could do far worse than store a
2116// long string. It is a defence against a buggy one: an error carrying a whole
2117// response body or a stack of context lands in a proposal that is kept forever
2118// and rendered every time somebody opens it.
2119const maxReason = 256
2120
2121// clip truncates at a rune boundary, so a cut message stays valid UTF-8 rather
2122// than ending in half a character.
2123func clip(s string) string {
2124	if len(s) <= maxReason {
2125		return s
2126	}
2127	// Walk back to the first byte that is not a continuation byte. Cutting
2128	// BEFORE that byte is already a whole-rune prefix — the character it
2129	// begins is simply left out.
2130	//
2131	// Backing off one further, to drop the lead byte as well, is wrong and
2132	// looked right: it takes the cut inside the character before, which is how
2133	// this was first written. The test that caught it decodes what survives
2134	// rather than measuring it.
2135	n := maxReason
2136	for n > 0 && s[n]&0xC0 == 0x80 {
2137		n--
2138	}
2139	return s[:n] + "…"
2140}
2141
2142// proposalSettledEvent is the single announcement of an outcome.
2143//
2144// One event with a state on it rather than one event per outcome, because the
2145// per-outcome shape is what let four of the six transitions go unannounced:
2146// Executed and Failed were emitted at two of Execute's paths, its other
2147// failure path and the retired-kind path said nothing, and a proposal that
2148// simply LOST — the ordinary result — was never announced anywhere. It opened,
2149// it collected votes, and then nothing was ever said about it again.
2150const (
2151	// kindOfferedEvent is the only announcement a kind gets before it is
2152	// adopted, and the only one at all if it never is.
2153	//
2154	// The registry is never iterated — an ungated one is unbounded, and walking
2155	// it would put somebody's spam on the page holders read — so without this
2156	// an offered kind could be found only by guessing its name, and the
2157	// extension point was undiscoverable.
2158	//
2159	// Adoption gets no event: it happens through a proposal, which is already
2160	// announced when it opens and when it settles.
2161	kindOfferedEvent = "KindOffered"
2162
2163	proposalOpenedEvent  = "ProposalOpened"
2164	votedEvent           = "Voted"
2165	proposalSettledEvent = "ProposalSettled"
2166)
2167
2168// setState is the only writer of p.state, and does everything that follows from
2169// a proposal reaching one, so no new code path has to remember. Called only
2170// with a state out of stateActive: nothing transitions back in.
2171//
2172// Three things:
2173//
2174//   - the reason is clipped, so a kind cannot write an unbounded string into a
2175//     record kept for the life of the realm;
2176//   - the slot goes, unless the proposal SUCCEEDED and is pending execution;
2177//   - the outcome is announced.
2178//
2179// Not the voter roll, which outlives the decision. A kind that pays the people
2180// who voted has to ask after the proposal has finished, so the roll goes on
2181// request instead, at ReleaseRoll — permissionless, with the deposit going to
2182// whoever calls it, which is the same bargain Settle makes for the slot.
2183func (g *Governor) setState(p *proposal, st int8, reason string) {
2184	p.state, p.reason = st, clip(reason)
2185	if st != stateSucceeded {
2186		g.release(p)
2187	}
2188	chain.Emit(proposalSettledEvent,
2189		"id", strconv.FormatInt(p.id, 10),
2190		"state", stateName(st),
2191		"reason", p.reason,
2192	)
2193}
2194
2195func stateName(s int8) string {
2196	switch s {
2197	case stateActive:
2198		return "active"
2199	case stateDefeated:
2200		return "defeated"
2201	case stateSucceeded:
2202		return "succeeded"
2203	case stateExecuted:
2204		return "executed"
2205	case stateFailed:
2206		return "failed"
2207	case stateCanceled:
2208		return "canceled"
2209	}
2210	return "expired"
2211}
2212
2213func (g *Governor) entryOf(name string) *entry {
2214	if v := g.kinds.Get(name); v != nil {
2215		return v.(*entry)
2216	}
2217	return nil
2218}
2219
2220// subPathOf maps a kind name onto a legal sub-realm path.
2221//
2222// Sub takes '/'-separated segments of [a-z0-9] with '_.-' inside a segment, and
2223// a kind name is any printable ASCII without spaces — "govern:adopt" among
2224// them. Anything outside the alphabet becomes '-', which keeps the mapping
2225// total, stable and readable: a governed realm gating on this sees the power it
2226// granted rather than the governor as a whole.
2227func subPathOf(kind string) string {
2228	out := []byte(kind)
2229	for i := 0; i < len(out); i++ {
2230		c := out[i]
2231		switch {
2232		case c >= 'a' && c <= 'z', c >= '0' && c <= '9':
2233		case c >= 'A' && c <= 'Z':
2234			out[i] = c + ('a' - 'A')
2235		default:
2236			out[i] = '-'
2237		}
2238	}
2239	return string(out)
2240}
2241
2242// liveEntry is what a proposal needs: a kind the holders have adopted.
2243//
2244// The two failures are told apart because the remedy differs. A name nobody
2245// offered is a typo; a name that IS offered and not adopted is waiting on a
2246// vote, and "no such kind" points that reader at their spelling when what they
2247// need is govern:adopt. Preview has always distinguished them.
2248func (g *Governor) liveEntry(name string) *entry {
2249	e := g.entryOf(name)
2250	if e == nil {
2251		panic("govern: no such kind: " + name)
2252	}
2253	if !e.live {
2254		panic("govern: the kind " + name + " has been offered but not adopted, " +
2255			"so it cannot be proposed yet — the holders adopt it with govern:adopt")
2256	}
2257	return e
2258}
2259
2260func (g *Governor) kindOf(name string) Kind { return g.liveEntry(name).kind }
2261
2262// anyKind is the kind whether or not it is still adopted.
2263//
2264// Reading is not doing. Retiring a kind withdraws the power to run it; it must
2265// not also erase the record of what was already proposed under it — and it did,
2266// because everything that renders a proposal went through the live lookup and
2267// panicked. One retirement would have taken every historical page with it.
2268func (g *Governor) anyKind(name string) Kind {
2269	e := g.entryOf(name)
2270	if e == nil {
2271		return nil
2272	}
2273	return e.kind
2274}
2275
2276// describeOf renders a proposal, surviving a kind that has since been retired
2277// or was never offered here at all.
2278func (g *Governor) describeOf(p *proposal) string {
2279	k := g.anyKind(p.kind)
2280	if k == nil {
2281		return "_the kind `" + p.kind + "` is no longer registered, so this " +
2282			"proposal can no longer describe itself. Its payload was:_\n\n" +
2283			g.indented(p.payload)
2284	}
2285	return g.describeKind(k, p.payload)
2286}
2287
2288// indented puts EVERY line of a payload inside the code block. Four spaces in
2289// front of the whole string indents line one and leaves the rest as live
2290// markdown, and payloads may contain newlines — govern:batch is defined in
2291// terms of them.
2292//
2293// Reached only when a kind has been retired or was never registered, which is
2294// the one place a payload is rendered with nothing left to have vetted it: the
2295// validation belonged to that kind's Check.
2296func (g *Governor) indented(s string) string {
2297	return "    " + strings.ReplaceAll(s, "\n", "\n    ")
2298}
2299
2300func (g *Governor) rulesOf(name string) Rules { return g.liveEntry(name).rules }
2301
2302func (g *Governor) mustProposal(id int64) *proposal {
2303	v := g.proposals.Get(enc(uint64(id)))
2304	if v == nil {
2305		panic("govern: no such proposal")
2306	}
2307	return v.(*proposal)
2308}
2309
2310// Errors a kind returns. Values rather than strings built at the call site, so
2311// a caller can compare them and Describe cannot drift from Check.
2312
2313type govError struct{ s string }
2314
2315func (e *govError) Error() string { return e.s }
2316func govErr(s string) error       { return &govError{s} }
2317
2318// digest identifies a question by what it asks, not by who asked it.
2319//
2320// Only ever used to refuse a duplicate while one is open. Identity stays a
2321// sequence number, because a number renders, sorts and paginates and a hash
2322// does none of those — OpenZeppelin derives the whole proposal id from the
2323// hash and pays for it every time a UI wants a list in order.
2324func (g *Governor) digest(kind, payload string) string {
2325	h := sha256.Sum256([]byte(kind + "\x00" + payload))
2326	return string(h[:16])
2327}
2328
2329// release frees a proposal's slot in the open index. Idempotent, because
2330// settle can reach a terminal state from more than one path.
2331func (g *Governor) release(p *proposal) { g.openIdx.Remove(g.digest(p.kind, p.payload)) }