PathrockNetwork Gno Explorer
HomeBlocksTransactionsRealmsPackagesValidators

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/p/g1leu8d2vsplhehcfkjg50mwgdpxdkt8tztu95wr/governor/v0

Package
Open in gnoweb ↗

Overview

Kind
Pure package
Name
v0
Namespace
g1leu8d2vsplhehcfkjg50mwgdpxdkt8tztu95wr / governor
Files
8 (gnomod.toml)
Exported functions
n/a — not supported for pure packages by the node (vm/qfuncs)
Module
gno.land/p/g1leu8d2vsplhehcfkjg50mwgdpxdkt8tztu95wr/governor/v0
gno
0.9

Files (8)

  • gnomod.tomltoml
  • batch.gnogno
  • builtin.gnogno
  • electorate.gnogno
  • governor.gnogno
  • introspect.gnogno
  • keys.gnogno
  • rules.gnogno
  • governor.gnogno
    1// Package governor is a proposal engine: it decides what a body of holders has2// agreed to, and it decides nothing about what agreement means.3//4// THE SPLIT IS THE POINT. A Governor holds proposals, epochs, quorum floors, the5// roll of eligible voters and the tally; it does not hold a treasury, a token, or6// any idea of what "adopt this" should DO. Adoption produces a KIND and a7

    Functions

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

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

    // 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)) }
    2332