PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

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/r/gnops/valopers

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
valopers
Namespace
gnops
Files
14 (gnomod.toml)
Exported functions
13
Module
gno.land/r/gnops/valopers
gno
0.9

Files (14)

  • gnomod.tomltoml
  • admin.gnogno
  • init.gnogno
  • valopers.gnogno
  • admin_test.gnogno
  • pubkey_type_test.gnogno
  • rotate_test.gnogno
  • valopers_test.gnogno
  • z_1_filetest.gnogno
  • z_2_filetest.gnogno
  • z_auth_readonly_filetest.gnogno
  • z_foreign_realm_capability_filetest.gnogno
  • z_govdao_only_principal_filetest.gnogno
  • z_operator_authlist_capability_filetest.gnogno
  • admin.gnogno
    1package valopers23import (4	"gno.land/p/moul/authz/v0"5	"gno.land/p/nt/ufmt/v0"6	"gno.land/r/gov/dao"7)8

    Functions

    • AddToAuthList(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, addr string, member string)

    • Auth() string

    • DeleteFromAuthList(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, addr string, member string)

    • GetByAddr(addr string) struct{Moniker string; Description string; ServerType string; OperatorAddress .uverse.address; SigningPubKey string; SigningAddress .uverse.address; LastRotationHeight int64; KeepRunning bool; auth *gno.land/p/nt/ownable/exts/authorizable/v0.Authorizable}

    • NewAuthorityRotationProposalRequest(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, newContractPath string) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

    • NewInstructionsProposalRequest(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, newInstructions string) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

    • Register(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, moniker string, description string, serverType string, addr string, pubKey string)

    • Render(fullPath string) string

    • UpdateDescription(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, addr string, description string)

    • UpdateKeepRunning(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, addr string, keepRunning bool)

    • UpdateMoniker(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, addr string, moniker string)

    • UpdateServerType(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, addr string, serverType string)

    • UpdateSigningKey(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, addr string, newPubKey string)

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

    Rendered

    RenderedRawgnoweb ↗
    9var auth *authz.Authorizer
    10
    11// Auth returns a read-only description of the realm's current governance
    12// authority (for rendering / inspection). It renders as
    13//
    14// contract_authority[contract=gno.land/r/gov/dao,proposer=contract-identity]
    15//
    16// i.e. "GovDAO governs this realm, and only GovDAO may drive it" — a
    17// statement an on-chain reader can act on. The proposer half is
    18// load-bearing: without it the string is byte-identical whether the
    19// authority is gated or wide open (see ContractAuthority.String).
    20//
    21// It deliberately does NOT return the live *authz.Authorizer: an
    22// exported handle to the authority would let any realm reach its
    23// mutators (Transfer, DoByPrevious, ...) directly. Returning a
    24// description instead of the handle keeps that surface unreachable from
    25// here in the first place. Valoper.AuthOwner follows the same rule for
    26// per-operator auth lists.
    27func Auth() string {
    28 return auth.String()
    29}
    30
    31// updateInstructions is the realm's only privileged write. It authorizes
    32// as the realm that CROSSED INTO valopers, not as valopers itself.
    33//
    34// Why DoByPrevious and not DoByCurrent: own-path + DoByCurrent is a
    35// tautology (see NewContractAuthority's godoc for the mechanism, once).
    36// `rlm.Previous()` is the caller — on the legitimate path r/gov/dao's
    37// executor frame, which is what init.gno's authority is pointed at.
    38//
    39// What it buys: it is the code-level guard against this realm's most
    40// likely regression, a maintainer later adding an exported crossing
    41// entrypoint that reaches here. Under DoByCurrent such an entrypoint
    42// authorizes for any caller; under DoByPrevious the caller's own address
    43// is the principal and the gate rejects it. Pinned by
    44// filetests/z_govdao_only_principal_filetest.gno.
    45//
    46// Two things it does NOT cover on its own, both closed elsewhere:
    47// re-exporting the privileged closure (guarded by the seal in
    48// NewInstructionsProposalRequest), and exporting a function whose
    49// signature is assignable to dao's `func(realm) error` callback type,
    50// which the proxy would invoke on an attacker's behalf. The second was a
    51// live bypass of this gate until SimpleExecutor.Execute began rejecting
    52// invocation from outside r/gov/dao (r/gov/dao/types.gno); keep BOTH
    53// conditions in mind before adding an exported symbol here.
    54//
    55// Returns the authorization error rather than panicking on it. That matters
    56// on the governance path: impl.ExecuteProposal turns an executor ERROR into
    57// status Denied plus a DeniedReason, but it cannot see a panic — a panic
    58// aborts the whole ExecuteProposal transaction, burning its gas and leaving
    59// the proposal stuck Accepted, retryable forever and never deniable. The
    60// refusal is currently unreachable on the approved route (Previous() there
    61// is always r/gov/dao), but init.gno's handler is explicitly offered as the
    62// seam for an intent check (timelock, quorum, audit trail), and the first
    63// such check to return an error would hit exactly that.
    64func updateInstructions(_ int, rlm realm, newInstructions string) error {
    65 return auth.DoByPrevious(0, rlm, "update-instructions", func() error {
    66 instructions = newInstructions
    67 return nil
    68 })
    69}
    70
    71// NewInstructionsProposalRequest builds the GovDAO proposal that rewrites
    72// this realm's instructions. It replaces the previously exported
    73// NewInstructionsProposalCallback.
    74//
    75// SECURITY: the privileged closure must never leave this package.
    76//
    77// The VM mints a crossing frame's `cur` from the CALLEE's declaring
    78// package, so a closure declared here always runs with valopers'
    79// identity no matter who invokes it — and whoever holds the closure
    80// chooses its Previous() by wrapping it in an executor of their own.
    81// Handing such a closure to a caller therefore hands out the ability to
    82// satisfy this realm's gate whichever principal it is pointed at: the
    83// handler in init.gno runs the action and `instructions` is rewritten
    84// with no proposal and no vote. That is what the exported callback did.
    85//
    86// Returning a dao.ProposalRequest instead seals the capability: the
    87// executor is an unexported field with no accessor (dao.ProposalRequest
    88// exposes only Title/Description/Filter), so the only way to reach the
    89// closure is for GovDAO to execute the proposal that contains it.
    90//
    91// Note this is deliberately stronger than returning a dao.Executor —
    92// even a dao.NewSafeExecutor-wrapped one. Executor.Execute is an
    93// exported method, so a returned Executor stays directly invocable by
    94// its holder, and SafeExecutor's only gate (InAllowedDAOs) FAILS OPEN
    95// while the allowedDAOs list is empty, which is the documented
    96// bootstrap state (see r/gov/dao/loader/v0). A sealed request has no
    97// such conditional.
    98//
    99// The rule for this realm: no exported function may return a crossing
    100// closure, a dao.Executor, or anything else that carries valopers'
    101// frame identity — and no exported function may itself BE such a thing,
    102// i.e. have a signature assignable to dao's `func(realm) error` callback
    103// type, since the proxy would then invoke it on an attacker's behalf.
    104// filetests/z_foreign_realm_capability_filetest.gno pins the first;
    105// filetests/z_govdao_only_principal_filetest.gno pins the second.
    106func NewInstructionsProposalRequest(cur realm, newInstructions string) dao.ProposalRequest {
    107 cb := func(cur realm) error {
    108 return updateInstructions(0, cur, newInstructions)
    109 }
    110
    111 title := instructionsProposalTitle
    112 description := ufmt.Sprintf("Update the instructions to: \n\n%s", newInstructions)
    113
    114 return dao.NewProposalRequest(title, description, dao.NewSimpleExecutor(0, cur, cb, ""))
    115}
    116
    117// instructionsProposalTitle is the on-chain title of the instructions
    118// proposal, named as a constant so a test can pin it: it is rendered to
    119// GovDAO voters and is the string off-chain tooling matches on. It was
    120// "/p/gnops/valopers: ..." before this realm's proposal construction moved
    121// here; the "/p/" was simply wrong (valopers is an /r/ realm).
    122const instructionsProposalTitle = "/r/gnops/valopers: Update instructions"
    123
    124// rotateAuthority replaces this realm's governance authority.
    125//
    126// Unexported, and reachable only through the sealed request built by
    127// NewAuthorityRotationProposalRequest — same discipline as
    128// updateInstructions, for the same reason.
    129//
    130// authz.Authorizer.Transfer derives its principal as
    131// rlm.Previous().Address(), so inside a GovDAO-executed callback declared
    132// here Previous() is r/gov/dao — exactly the principal init.gno's authority
    133// asserts. No same-package cross() trick is needed.
    134func rotateAuthority(_ int, rlm realm, newContractPath string) error {
    135 return auth.Transfer(0, rlm, authz.NewContractAuthority(
    136 newContractPath,
    137 func(_ string, action authz.PrivilegedAction) error {
    138 return action()
    139 },
    140 ))
    141}
    142
    143// NewAuthorityRotationProposalRequest builds the GovDAO proposal that
    144// re-points this realm's governance authority at `newContractPath`.
    145//
    146// WHY THIS EXISTS. Without it the authority installed by init.gno is
    147// permanently frozen: nothing else calls auth.Transfer, Auth() returns a
    148// description rather than the live Authorizer, and Transfer routes through
    149// the authority's own gate — so if the asserted principal ever stops being
    150// presentable, `instructions` becomes unwritable with no on-chain recovery.
    151// That is not hypothetical: the r/gov/dao proxy path is a governance
    152// artifact that can be superseded, and a well-formed but wrong path (say
    153// the impl path instead of the proxy) is accepted at construction and dead
    154// forever. Redeploying instead is expensive — r/sys/validators/v0/cache.gno
    155// hardcodes `const valopersRealmPath`, so a new pkgpath means editing a
    156// second genesis realm and re-registering every valoper. It must exist
    157// before deploy, because code cannot be added to a deployed realm.
    158//
    159// WHY A PATH AND NOT AN authz.Authority. Taking an Authority would make
    160// this an open-interface input (Class-3 impl-substitution): a proposal
    161// could install an always-approve or always-deny authority, and readers of
    162// Auth() could not tell from the rendered description alone. Taking a path
    163// keeps the installed authority canonical by construction — always a
    164// ContractAuthority with the pass-through handler and the contract-identity
    165// gate — so the only thing governance can change is WHICH principal is
    166// asserted. The path is validated by authz.NewContractAuthority, which
    167// panics on a malformed one, aborting the proposal execution rather than
    168// bricking the realm.
    169//
    170// This remains a privileged surface: a majority that can pass this proposal
    171// can point the authority at a principal it controls. That is the same
    172// power a majority already has over `instructions`, and it is the price of
    173// being recoverable at all.
    174func NewAuthorityRotationProposalRequest(cur realm, newContractPath string) dao.ProposalRequest {
    175 cb := func(cur realm) error {
    176 return rotateAuthority(0, cur, newContractPath)
    177 }
    178
    179 title := "/r/gnops/valopers: Rotate governance authority"
    180 description := ufmt.Sprintf(
    181 "Re-point the valopers governance authority at: \n\n%s\n\n"+
    182 "The authority stays a contract-identity ContractAuthority; only the asserted principal changes.",
    183 newContractPath,
    184 )
    185
    186 return dao.NewProposalRequest(title, description, dao.NewSimpleExecutor(0, cur, cb, ""))
    187}
    188
    189// NewInstructionsProposalCallback was removed, not deprecated: it was the
    190// capability leak described above, so an inert shim would be pointless and
    191// a working one would reopen the hole. Precedent + replay check: the
    192// min-fee callback below was already removed the same way even though it
    193// HAD been used on gnoland1 (GovDAO Prop #19), whereas the instructions
    194// callback has no on-chain trace at all — the live realm's instructions
    195// are byte-identical to the genesis default and none of gnoland1's 26
    196// GovDAO proposals is an "Update instructions" one.
    197//
    198// The min-fee callback was removed: the fee now lives in sysparams
    199// under node:valoper:register_fee, and
    200// proposal.ProposeNewMinFeeProposalRequest delegates to
    201// sys/params.NewSysParamUint64PropRequest. Removing avoids the
    202// forward-compat hazard of a no-op shim with no caller-auth gating.
    203

    vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.