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/sys/params

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
params
Namespace
sys
Files
14 (gnomod.toml)
Exported functions
33
Module
gno.land/r/sys/params
gno
0.9

Files (14)

  • gnomod.tomltoml
  • delegate.gnogno
  • fee_collector.gnogno
  • halt.gnogno
  • params.gnogno
  • render.gnogno
  • run_submitters.gnogno
  • unlock.gnogno
  • valoper.gnogno
  • valset.gnogno
  • delegate_test.gnogno
  • fee_collector_test.gnogno
  • params_test.gnogno
  • unlock_test.gnogno
  • delegate_test.gnogno
    1package params23import (4	"testing"56	prms "sys/params"78	

    Functions

    • AddRunSubmitters(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}, addrs []string)

    • GetRunSubmitters() []string

    • GetValoperRegisterFee() uint64

    • GetValoperRotationFee() uint64

    • GetValoperRotationPeriodBlocks() int64

    • GetValsetEffective() []gno.land/p/sys/validators/v0.Validator

    • GetValsetEntries() []gno.land/p/sys/validators/v0.Validator

    • GetValsetPubKeyTypes() []string

    • IsRunSubmittersDelegate(pkgpath string) bool

    • NewSetFeeCollectorRequest(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) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

    • NewSetHaltRequest(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}, height int64, minVersion string) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

    • NewSysParamBoolPropRequest(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}, module string, submodule string, name string, value bool) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

    • NewSysParamBytesPropRequest(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}, module string, submodule string, name string, value []uint8) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

    • NewSysParamInt64PropRequest(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}, module string, submodule string, name string, value int64) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

    • NewSysParamStringPropRequest(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}, module string, submodule string, name string, value string) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

    • NewSysParamStringsPropRequest(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}, module string, submodule string, name string, value []string) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

    • NewSysParamStringsPropRequestAddWithTitle(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}, module string, submodule string, name string, title string, value []string) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

    • NewSysParamStringsPropRequestRemoveWithTitle(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}, module string, submodule string, name string, title string, value []string) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

    • NewSysParamStringsPropRequestWithTitle(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}, module string, submodule string, name string, title string, value []string) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

    • NewSysParamUint64PropRequest(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}, module string, submodule string, name string, value uint64) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

    • ProposeAddUnrestrictedAcctsRequest(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}, addrs ....uverse.address) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

    • ProposeClearRunSubmittersManager(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}) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

    • ProposeLockTransferRequest(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}) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

    • ProposeRemoveUnrestrictedAcctsRequest(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}, addrs ....uverse.address) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

    • ProposeSetRunSubmitters(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}, addrs []string) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

    • ProposeSetRunSubmittersManager(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}, pkgpath string) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

    • ProposeUnlockTransferRequest(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}) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

    • RemoveRunSubmitters(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}, addrs []string)

    • Render(path string) string

    • RunSubmittersGrantedBy(addr string) bool

    • RunSubmittersManager() string

    • SetValsetProposal(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}, entries []string)

    • ValsetDirty() bool

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

    Rendered

    RenderedRawgnoweb ↗
    "gno.land/p/moul/addrset/v0"
    9 "gno.land/p/nt/testutils/v0"
    10 "gno.land/p/nt/uassert/v0"
    11)
    12
    13const (
    14 testDelegate = "gno.land/r/test/delegate"
    15 testOther = "gno.land/r/test/other"
    16 // A sub-realm identity, the form a single DAO hosted by a multi-tenant
    17 // realm presents. "#" cannot occur in a real package path.
    18 testSubDelegate = "gno.land/r/nt/commondao/v0#dao/42"
    19)
    20
    21// resetDelegation returns the slot to undelegated. The realm's tests share
    22// package state, so anything touching the slot must put it back.
    23func resetDelegation() {
    24 runSubmittersMgr = ""
    25 runSubmittersGrants = addrset.Set{}
    26}
    27
    28// armRunSubmitters puts addresses on the list the way GovDAO does: by writing
    29// the parameter, not through the delegate.
    30//
    31// Tests need it because the delegate may no longer arm an empty list. An empty
    32// run_submitters means the gate is off, so the first add would switch a
    33// chain-wide restriction on rather than curate one, and that is a vote.
    34func armRunSubmitters(addrs ...string) {
    35 prms.UpdateSysParamStrings(vmModulePrefix, vmParamsSubmodule, runSubmittersKey, addrs, true)
    36}
    37
    38// unarmRunSubmitters drops addresses the way a GovDAO vote does, bypassing the
    39// delegate's grant-scoping. Used to build a list whose every remaining entry was
    40// granted by the delegate, which is the only state where the non-empty floor is
    41// the binding constraint.
    42func unarmRunSubmitters(addrs ...string) {
    43 prms.UpdateSysParamStrings(vmModulePrefix, vmParamsSubmodule, runSubmittersKey, addrs, false)
    44}
    45
    46// TestRunSubmittersUndelegatedDeniesEveryone is the single most important test
    47// here: with no delegate configured, the slot is "" and a direct user call also
    48// presents "". A gate that compared the two without checking for empty first
    49// would admit every account on the chain.
    50func TestRunSubmittersUndelegatedDeniesEveryone(cur realm, t *testing.T) {
    51 resetDelegation()
    52 defer resetDelegation()
    53
    54 uassert.Equal(t, "", RunSubmittersManager())
    55
    56 // A user account: PkgPath() is empty, matching the empty slot.
    57 testing.SetRealm(testing.NewUserRealm(testutils.TestAddress("nobody")))
    58 uassert.AbortsContains(t, cur, "no delegate is configured", func() {
    59 AddRunSubmitters(cross(cur), []string{testutils.TestAddress("victim").String()})
    60 })
    61
    62 // And a code realm, for completeness.
    63 testing.SetRealm(testing.NewCodeRealm(testOther))
    64 uassert.AbortsContains(t, cur, "no delegate is configured", func() {
    65 AddRunSubmitters(cross(cur), []string{testutils.TestAddress("victim").String()})
    66 })
    67}
    68
    69// TestRunSubmittersOnlyTheDelegateMayWrite pins that authorization is by exact
    70// package path.
    71func TestRunSubmittersOnlyTheDelegateMayWrite(cur realm, t *testing.T) {
    72 resetDelegation()
    73 defer resetDelegation()
    74
    75 runSubmittersMgr = testDelegate
    76 armRunSubmitters(testutils.TestAddress("seeded-by-vote").String())
    77 addr := testutils.TestAddress("granted").String()
    78
    79 // A different realm is refused.
    80 testing.SetRealm(testing.NewCodeRealm(testOther))
    81 uassert.AbortsContains(t, cur, "unauthorized", func() {
    82 AddRunSubmitters(cross(cur), []string{addr})
    83 })
    84
    85 // A user account is refused: an empty path must not match a set slot.
    86 testing.SetRealm(testing.NewUserRealm(testutils.TestAddress("nobody")))
    87 uassert.AbortsContains(t, cur, "unauthorized", func() {
    88 AddRunSubmitters(cross(cur), []string{addr})
    89 })
    90
    91 // The delegate itself succeeds.
    92 testing.SetRealm(testing.NewCodeRealm(testDelegate))
    93 AddRunSubmitters(cross(cur), []string{addr})
    94 uassert.True(t, contains(GetRunSubmitters(), addr),
    95 "the delegate's addition must reach the parameter")
    96}
    97
    98// TestRunSubmittersSubRealmIdentityIsExact pins that delegate matching is exact
    99// string equality, which is what makes a per-DAO delegation safe.
    100//
    101// A sub-realm identity minted by cur.Sub(subpath) presents "host#subpath", so a
    102// single DAO hosted by a multi-tenant realm can hold the capability. Matching by
    103// prefix instead would hand it to every DAO that host serves -- and CommonDAO
    104// membership, while invite-gated, is unlimited once invited.
    105//
    106// Asserted through the pure predicate rather than by crossing: constructing a
    107// live sub-realm cur is not something the test harness can do (NewCodeRealm
    108// rejects "#", and MakeRealm does not satisfy IsCurrent), and the comparison
    109// under test is the same one assertDelegate performs.
    110func TestRunSubmittersSubRealmIdentityIsExact(t *testing.T) {
    111 resetDelegation()
    112 defer resetDelegation()
    113
    114 runSubmittersMgr = testSubDelegate
    115
    116 uassert.True(t, IsRunSubmittersDelegate(testSubDelegate),
    117 "the named DAO holds the capability")
    118 uassert.False(t, IsRunSubmittersDelegate("gno.land/r/nt/commondao/v0"),
    119 "the host realm must not inherit its sub-identity's authority")
    120 uassert.False(t, IsRunSubmittersDelegate("gno.land/r/nt/commondao/v0#dao/43"),
    121 "a sibling DAO of the same host must not match")
    122 uassert.False(t, IsRunSubmittersDelegate("gno.land/r/nt/commondao/v0#dao/4"),
    123 "a prefix of the subpath must not match")
    124 uassert.False(t, IsRunSubmittersDelegate(""),
    125 "an empty path must never match a configured delegate")
    126}
    127
    128// TestRunSubmittersRemoveIsScopedToOwnGrants pins that the delegate cannot
    129// remove an address it did not add, so a list GovDAO curated survives a rogue
    130// delegate. The companion bound -- that it can never take the list to zero by
    131// any route -- is TestRunSubmittersCannotEmptyTheList.
    132func TestRunSubmittersRemoveIsScopedToOwnGrants(cur realm, t *testing.T) {
    133 resetDelegation()
    134 defer resetDelegation()
    135
    136 preexisting := testutils.TestAddress("breakglass").String()
    137 testing.SetSysParamStrings(vmModulePrefix, vmParamsSubmodule, runSubmittersKey,
    138 []string{preexisting})
    139
    140 runSubmittersMgr = testDelegate
    141 armRunSubmitters(testutils.TestAddress("seeded-by-vote").String())
    142 own := testutils.TestAddress("ownadd").String()
    143
    144 testing.SetRealm(testing.NewCodeRealm(testDelegate))
    145 AddRunSubmitters(cross(cur), []string{own})
    146
    147 // It may remove what it granted.
    148 uassert.True(t, RunSubmittersGrantedBy(address(own)))
    149 RemoveRunSubmitters(cross(cur), []string{own})
    150 uassert.False(t, contains(GetRunSubmitters(), own))
    151
    152 // It may NOT remove the address that predated the delegation.
    153 uassert.False(t, RunSubmittersGrantedBy(address(preexisting)))
    154 uassert.AbortsContains(t, cur, "only GovDAO may remove it", func() {
    155 RemoveRunSubmitters(cross(cur), []string{preexisting})
    156 })
    157 uassert.True(t, contains(GetRunSubmitters(), preexisting),
    158 "the pre-existing entry must survive a refused removal")
    159}
    160
    161// TestRunSubmittersCannotEmptyTheList pins the non-empty floor.
    162//
    163// An empty run_submitters means the gate is OFF: anyone on the chain may
    164// MsgRun. So emptying the list is not a smaller version of removing one
    165// address, it is the unilateral revocation of the whole restriction GovDAO
    166// voted for -- the one thing this capability must not be able to do.
    167//
    168// Grant-scoping alone does not prevent it. It holds only while an entry the
    169// delegate did not grant survives, and GovDAO replacing the list wholesale can
    170// remove its own entries without touching the grant record, which is exactly
    171// the state set up below.
    172func TestRunSubmittersCannotEmptyTheList(cur realm, t *testing.T) {
    173 resetDelegation()
    174 defer resetDelegation()
    175
    176 runSubmittersMgr = testDelegate
    177 seed := testutils.TestAddress("seeded-by-vote").String()
    178 armRunSubmitters(seed)
    179 a := testutils.TestAddress("granted-a").String()
    180 b := testutils.TestAddress("granted-b").String()
    181
    182 testing.SetRealm(testing.NewCodeRealm(testDelegate))
    183 AddRunSubmitters(cross(cur), []string{a, b})
    184
    185 // GovDAO then drops its own seed by vote, which grant-scoping does not
    186 // constrain. This is the only way to reach a list whose every entry was
    187 // granted by the delegate, now that the delegate cannot arm an empty one --
    188 // and it is the state where the floor is the last thing standing.
    189 unarmRunSubmitters(seed)
    190 uassert.Equal(t, 2, len(GetRunSubmitters()))
    191
    192 // Every listed address is now one the delegate granted, so grant-scoping
    193 // permits removing all of them. The floor is the only thing left.
    194 uassert.True(t, RunSubmittersGrantedBy(address(a)))
    195 uassert.True(t, RunSubmittersGrantedBy(address(b)))
    196
    197 // Down to one is fine: shrinking the list is the delegate's job.
    198 RemoveRunSubmitters(cross(cur), []string{a})
    199 uassert.Equal(t, 1, len(GetRunSubmitters()))
    200
    201 // The last one is not.
    202 uassert.AbortsContains(t, cur, "refusing to empty", func() {
    203 RemoveRunSubmitters(cross(cur), []string{b})
    204 })
    205 uassert.True(t, contains(GetRunSubmitters(), b),
    206 "the last entry must survive a refused removal")
    207
    208 // Nor in one call, and nor by naming addresses that are not listed: the
    209 // count is taken against the parameter, not the argument.
    210 uassert.AbortsContains(t, cur, "refusing to empty", func() {
    211 RemoveRunSubmitters(cross(cur), []string{b, b})
    212 })
    213 uassert.True(t, contains(GetRunSubmitters(), b))
    214
    215 // And the delegate is not locked out of its ordinary work: adding still
    216 // works, and once there are two again it may remove one.
    217 AddRunSubmitters(cross(cur), []string{a})
    218 RemoveRunSubmitters(cross(cur), []string{b})
    219 uassert.True(t, contains(GetRunSubmitters(), a))
    220 uassert.False(t, contains(GetRunSubmitters(), b))
    221}
    222
    223// TestRunSubmittersRevocationDropsGrantRecord pins that a new holder does not
    224// inherit removal authority over its predecessor's grants.
    225func TestRunSubmittersRevocationDropsGrantRecord(cur realm, t *testing.T) {
    226 resetDelegation()
    227 defer resetDelegation()
    228
    229 runSubmittersMgr = testDelegate
    230 armRunSubmitters(testutils.TestAddress("seeded-by-vote").String())
    231 addr := testutils.TestAddress("byfirst").String()
    232 testing.SetRealm(testing.NewCodeRealm(testDelegate))
    233 AddRunSubmitters(cross(cur), []string{addr})
    234 uassert.True(t, RunSubmittersGrantedBy(address(addr)))
    235
    236 // Hand the capability over, as the proposal executor would.
    237 runSubmittersMgr = testOther
    238 runSubmittersGrants = addrset.Set{}
    239
    240 testing.SetRealm(testing.NewCodeRealm(testOther))
    241 uassert.False(t, RunSubmittersGrantedBy(address(addr)))
    242 uassert.AbortsContains(t, cur, "only GovDAO may remove it", func() {
    243 RemoveRunSubmitters(cross(cur), []string{addr})
    244 })
    245}
    246
    247// TestDelegatePathValidation pins what may be stored in a slot. An ephemeral
    248// `maketx run` realm has a NON-empty path, so a check for "is this code" would
    249// let one through; only the gno.land/r/ requirement excludes it.
    250func TestDelegatePathValidation(t *testing.T) {
    251 for _, bad := range []string{
    252 "",
    253 "gno.land/p/nt/avl/v0",
    254 "gno.land/e/g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5/run",
    255 "gno.land/r/",
    256 // Paths no caller could ever present. Storing one would leave GovDAO
    257 // believing it delegated while the delegate is refused on every call.
    258 "gno.land/r/test/delegate ", // trailing space
    259 " gno.land/r/test/delegate", // leading space
    260 "gno.land/r/nt/commondao/v0#DAO/42", // uppercase subpath
    261 "gno.land/r/nt/commondao/v0#dao/42#dao/43", // two separators
    262 } {
    263 // PanicsContains, not AbortsContains: this is a same-realm call, so
    264 // the panic never crosses a realm boundary and is not an abort.
    265 uassert.PanicsContains(t, cur, "invalid delegate", func() {
    266 assertDelegatePath(bad)
    267 })
    268 }
    269 // Sound paths, including a sub-realm identity.
    270 assertDelegatePath(testDelegate)
    271 assertDelegatePath(testSubDelegate)
    272}
    273
    274// TestValsetGateRejectsForeignRealm closes a pre-existing coverage gap found
    275// while factoring the shared gate: assertValsetCaller had no test in this realm
    276// at all, so nothing asserted that a realm other than r/sys/validators/v0 is
    277// refused.
    278func TestValsetGateRejectsForeignRealm(cur realm, t *testing.T) {
    279 testing.SetRealm(testing.NewCodeRealm(testOther))
    280 uassert.AbortsContains(t, cur, "unauthorized", func() {
    281 SetValsetProposal(cross(cur), []string{"somepubkey:1"})
    282 })
    283
    284 // A user account must be refused identically -- the empty-path case.
    285 testing.SetRealm(testing.NewUserRealm(testutils.TestAddress("nobody")))
    286 uassert.AbortsContains(t, cur, "unauthorized", func() {
    287 SetValsetProposal(cross(cur), []string{"somepubkey:1"})
    288 })
    289}
    290
    291// TestAssertNotValsetKeyRejectsGenericFactory closes the other gap: the guard
    292// whose own comment says it stops "any GovDAO supermajority" from writing
    293// validator-set state through the generic param factory had no test.
    294func TestAssertNotValsetKeyRejectsGenericFactory(cur realm, t *testing.T) {
    295 testing.SetRealm(testing.NewUserRealm(testutils.TestAddress("proposer")))
    296 uassert.AbortsContains(t, cur, "reserved for", func() {
    297 NewSysParamStringsPropRequest(cross(cur), "node", "valset", "proposed",
    298 []string{"somepubkey:1"})
    299 })
    300}
    301
    302func contains(haystack []string, needle string) bool {
    303 for _, h := range haystack {
    304 if h == needle {
    305 return true
    306 }
    307 }
    308 return false
    309}
    310
    311// TestRunSubmittersGrantLaunderingIsRefused reproduces a real hole in the first
    312// version of this code, found by audit.
    313//
    314// UpdateSysParamStrings dedupes on add, so re-adding an address already on the
    315// list is a no-op on the parameter. The first implementation recorded a grant
    316// for every argument regardless, which let the delegate launder authority over
    317// entries it never granted:
    318//
    319// read the list -> re-add all of it -> remove all of it
    320//
    321// The parameter never changed on the middle step, but every address became
    322// "granted by me", so the removal was permitted and the allowlist ended empty --
    323// including the entry that predated the delegation. Since GovDAO proposal
    324// creation is MsgRun-only, an empty run_submitters means no proposal can be
    325// created to revoke the delegate or restore the list. That is a chain brick
    326// recoverable only by relaunch.
    327func TestRunSubmittersGrantLaunderingIsRefused(cur realm, t *testing.T) {
    328 resetDelegation()
    329 defer resetDelegation()
    330
    331 breakglass := testutils.TestAddress("breakglass2").String()
    332 testing.SetSysParamStrings(vmModulePrefix, vmParamsSubmodule, runSubmittersKey,
    333 []string{breakglass})
    334
    335 runSubmittersMgr = testDelegate
    336 armRunSubmitters(testutils.TestAddress("seeded-by-vote").String())
    337 testing.SetRealm(testing.NewCodeRealm(testDelegate))
    338
    339 // Step 1: re-add what is already there. A no-op on the parameter, and it
    340 // must NOT create a grant.
    341 AddRunSubmitters(cross(cur), GetRunSubmitters())
    342 uassert.False(t, RunSubmittersGrantedBy(address(breakglass)),
    343 "re-adding an existing address must not record a grant for it")
    344
    345 // Step 2: the removal must therefore still be refused.
    346 uassert.AbortsContains(t, cur, "only GovDAO may remove it", func() {
    347 RemoveRunSubmitters(cross(cur), []string{breakglass})
    348 })
    349 uassert.True(t, contains(GetRunSubmitters(), breakglass),
    350 "the pre-existing entry must survive")
    351
    352 // And the whole-list version of the same attack, which is how it would
    353 // actually be run.
    354 AddRunSubmitters(cross(cur), GetRunSubmitters())
    355 uassert.AbortsContains(t, cur, "only GovDAO may remove it", func() {
    356 RemoveRunSubmitters(cross(cur), GetRunSubmitters())
    357 })
    358 uassert.True(t, len(GetRunSubmitters()) > 0,
    359 "the allowlist must never end up empty at a delegate's hand")
    360
    361 // A genuinely new address still works normally.
    362 fresh := testutils.TestAddress("freshgrant").String()
    363 AddRunSubmitters(cross(cur), []string{fresh})
    364 uassert.True(t, RunSubmittersGrantedBy(address(fresh)))
    365 RemoveRunSubmitters(cross(cur), []string{fresh})
    366 uassert.False(t, contains(GetRunSubmitters(), fresh))
    367}
    368
    369// TestRenderShowsDelegationState pins that the page actually reports the state
    370// it exists to report.
    371//
    372// The value of a Render here is that someone auditing the chain can see whether
    373// a parameter is delegated without knowing to ask. A page that renders the same
    374// text whether or not a delegation exists would defeat that, so both states are
    375// checked.
    376func TestRenderShowsDelegationState(t *testing.T) {
    377 resetDelegation()
    378 defer resetDelegation()
    379
    380 addr := testutils.TestAddress("rendered").String()
    381 testing.SetSysParamStrings(vmModulePrefix, vmParamsSubmodule, runSubmittersKey,
    382 []string{addr})
    383
    384 // Undelegated: it must say so rather than leave the reader guessing.
    385 out := Render("")
    386 uassert.True(t, contains2(out, "nobody"),
    387 "an undelegated parameter must be reported as such")
    388 uassert.False(t, contains2(out, testDelegate),
    389 "no delegate should be named when none is set")
    390
    391 // Delegated: the holder is named.
    392 runSubmittersMgr = testDelegate
    393 armRunSubmitters(testutils.TestAddress("seeded-by-vote").String())
    394 out = Render("")
    395 uassert.True(t, contains2(out, testDelegate),
    396 "the delegate holding the capability must be named")
    397 uassert.True(t, contains2(out, addr),
    398 "the addresses the parameter currently allows must be listed")
    399
    400 // The valset writer is fixed in source, not delegated, and the page should
    401 // not blur the two.
    402 uassert.True(t, contains2(out, valsetAuthorizedRealm),
    403 "the realm that writes valset params must be shown too")
    404}
    405
    406// contains2 reports whether s contains sub.
    407func contains2(s, sub string) bool {
    408 if len(sub) == 0 {
    409 return true
    410 }
    411 for i := 0; i+len(sub) <= len(s); i++ {
    412 if s[i:i+len(sub)] == sub {
    413 return true
    414 }
    415 }
    416 return false
    417}
    418
    419// TestRunSubmittersDelegateCannotArmTheGate covers the direction the non-empty
    420// floor does not: turning the allowlist ON.
    421//
    422// An empty run_submitters means the gate is off and anyone may MsgRun. So a
    423// delegate adding the first address is not curating a list, it is switching a
    424// chain-wide restriction on and choosing who it admits -- leaving that address
    425// the only one on the chain that may run code.
    426//
    427// That is unrepairable in band. Creating a GovDAO proposal needs MsgRun, so
    428// once the gate is armed against the members they cannot propose the vote that
    429// would reset the list or revoke the delegation, and the floor in
    430// RemoveRunSubmitters stops the delegate from undoing it either.
    431func TestRunSubmittersDelegateCannotArmTheGate(cur realm, t *testing.T) {
    432 resetDelegation()
    433 defer resetDelegation()
    434
    435 runSubmittersMgr = testDelegate
    436 attacker := testutils.TestAddress("attacker").String()
    437
    438 // The gate starts off.
    439 uassert.Equal(t, 0, len(GetRunSubmitters()))
    440
    441 testing.SetRealm(testing.NewCodeRealm(testDelegate))
    442 uassert.AbortsContains(t, cur, "refusing to arm", func() {
    443 AddRunSubmitters(cross(cur), []string{attacker})
    444 })
    445 uassert.Equal(t, 0, len(GetRunSubmitters()),
    446 "a refused arm must leave the gate off")
    447
    448 // Once GovDAO has armed it, the delegate may curate as before.
    449 seeded := testutils.TestAddress("seeded-by-vote").String()
    450 armRunSubmitters(seeded)
    451 testing.SetRealm(testing.NewCodeRealm(testDelegate))
    452 AddRunSubmitters(cross(cur), []string{attacker})
    453 uassert.Equal(t, 2, len(GetRunSubmitters()),
    454 "curating an armed list is still the delegate's job")
    455}
    456
    457// TestRunSubmittersKeyIsReservedFromGenericFactories pins that the whole-list
    458// path is the dedicated constructor and nothing else.
    459//
    460// The generic factories take module, submodule and name as arguments, so
    461// without this any of the nine could write run_submitters and walk past the
    462// proposer rule in ProposeSetRunSubmitters. Same shape as the valset
    463// reservation next to it.
    464func TestRunSubmittersKeyIsReservedFromGenericFactories(cur realm, t *testing.T) {
    465 addr := testutils.TestAddress("someone").String()
    466
    467 uassert.AbortsContains(t, cur, "reserved for ProposeSetRunSubmitters", func() {
    468 NewSysParamStringsPropRequest(cross(cur), "vm", "p", runSubmittersKey, []string{addr})
    469 })
    470 uassert.AbortsContains(t, cur, "reserved for ProposeSetRunSubmitters", func() {
    471 NewSysParamStringsPropRequestWithTitle(cross(cur), "vm", "p", runSubmittersKey, "t", []string{addr})
    472 })
    473 uassert.AbortsContains(t, cur, "reserved for ProposeSetRunSubmitters", func() {
    474 NewSysParamStringsPropRequestAddWithTitle(cross(cur), "vm", "p", runSubmittersKey, "t", []string{addr})
    475 })
    476 uassert.AbortsContains(t, cur, "reserved for ProposeSetRunSubmitters", func() {
    477 NewSysParamStringsPropRequestRemoveWithTitle(cross(cur), "vm", "p", runSubmittersKey, "t", []string{addr})
    478 })
    479 uassert.AbortsContains(t, cur, "reserved for ProposeSetRunSubmitters", func() {
    480 NewSysParamStringPropRequest(cross(cur), "vm", "p", runSubmittersKey, addr)
    481 })
    482
    483 // The four typed factories too. They cannot carry a run_submitters value,
    484 // but they can name the key, and the reservation is about the key -- all
    485 // nine share one check on the funnel they return through, so all nine are
    486 // listed here rather than the five that happen to take strings.
    487 uassert.AbortsContains(t, cur, "reserved for ProposeSetRunSubmitters", func() {
    488 NewSysParamInt64PropRequest(cross(cur), "vm", "p", runSubmittersKey, 1)
    489 })
    490 uassert.AbortsContains(t, cur, "reserved for ProposeSetRunSubmitters", func() {
    491 NewSysParamUint64PropRequest(cross(cur), "vm", "p", runSubmittersKey, 1)
    492 })
    493 uassert.AbortsContains(t, cur, "reserved for ProposeSetRunSubmitters", func() {
    494 NewSysParamBoolPropRequest(cross(cur), "vm", "p", runSubmittersKey, true)
    495 })
    496 uassert.AbortsContains(t, cur, "reserved for ProposeSetRunSubmitters", func() {
    497 NewSysParamBytesPropRequest(cross(cur), "vm", "p", runSubmittersKey, []byte{1})
    498 })
    499
    500 // A different key in the same module is unaffected.
    501 uassert.NotAborts(t, cur, func() {
    502 NewSysParamStringsPropRequest(cross(cur), "vm", "p", "code_submitters", []string{addr})
    503 })
    504}
    505
    506// TestProposeSetRunSubmittersRequiresProposerOnTheList covers the rule that a
    507// non-empty allowlist must include whoever proposed it.
    508//
    509// A list naming nobody who can create a proposal cannot be undone, because
    510// creating one needs MsgRun. Requiring the proposer's own address proves the
    511// list is usable: GovDAO refuses a proposal from a non-member, and the proposer
    512// just signed the transaction, so that address demonstrably holds a key.
    513func TestProposeSetRunSubmittersRequiresProposerOnTheList(cur realm, t *testing.T) {
    514 other := testutils.TestAddress("someone-else").String()
    515
    516 // A list without the proposer is refused.
    517 uassert.AbortsContains(t, cur, "omits the proposer", func() {
    518 ProposeSetRunSubmitters(cross(cur), []string{other})
    519 })
    520
    521 // Emptying the list is always allowed: that switches the gate off, which
    522 // cannot lock anyone out.
    523 uassert.NotAborts(t, cur, func() {
    524 ProposeSetRunSubmitters(cross(cur), []string{})
    525 })
    526
    527 // A list that does include the proposer goes through.
    528 proposer := testutils.TestAddress("proposer")
    529 testing.SetRealm(testing.NewUserRealm(proposer))
    530 uassert.NotAborts(t, cur, func() {
    531 ProposeSetRunSubmitters(cross(cur), []string{other, proposer.String()})
    532 })
    533}
    534
    535// TestSetRunSubmittersReplacesTheList covers what the whole-list setter does to
    536// a list that is not empty.
    537//
    538// This realm reserves run_submitters from the generic factories, so its own
    539// setter is the only route by vote. If that setter appended instead of
    540// replacing, the parameter would be append-only chain-wide: a compromised
    541// address could never be de-listed and the gate could never be turned back off,
    542// while the proposal shown to voters would say otherwise.
    543//
    544// Every other test here starts from an empty list, where appending and
    545// replacing look identical, which is why this one starts armed.
    546func TestSetRunSubmittersReplacesTheList(cur realm, t *testing.T) {
    547 resetDelegation()
    548 defer resetDelegation()
    549
    550 a := testutils.TestAddress("keep-a").String()
    551 b := testutils.TestAddress("drop-b").String()
    552 armRunSubmitters(a, b)
    553 uassert.Equal(t, 2, len(GetRunSubmitters()))
    554
    555 // Dropping b must actually drop it.
    556 setRunSubmitters([]string{a})
    557 got := GetRunSubmitters()
    558 uassert.Equal(t, 1, len(got), "the list must be replaced, not appended to")
    559 uassert.True(t, contains(got, a))
    560 uassert.False(t, contains(got, b), "a de-listed address must be gone")
    561
    562 // And emptying must switch the gate off, which is what the proposal says.
    563 setRunSubmitters([]string{})
    564 uassert.Equal(t, 0, len(GetRunSubmitters()),
    565 "an empty list must be reachable, or the gate can never be turned off")
    566}
    567
    568// TestAssertDelegateRejectsANonLiveRealm covers the IsCurrent check in
    569// assertDelegate.
    570//
    571// This is the shape where the check can actually fire. assertDelegate takes its
    572// realm as an ordinary parameter, so a caller can hand it a stashed or
    573// sibling-frame value; without IsCurrent it would then compare that value's
    574// Previous() against the delegate path and admit whoever assembled it.
    575//
    576// Crossing functions cannot be tested this way, and do not need to be: the
    577// compiler refuses anything but `cur` or `cross(rlm)` as their first argument,
    578// so their cur is live by construction.
    579func TestAssertDelegateRejectsANonLiveRealm(cur realm, t *testing.T) {
    580 resetDelegation()
    581 defer resetDelegation()
    582
    583 runSubmittersMgr = testDelegate
    584
    585 // A synthetic realm whose Previous() names the delegate. The path check
    586 // alone would admit it; IsCurrent is the only thing that does not.
    587 fake := testing.MakeRealm(
    588 testutils.TestAddress("impostor"), "gno.land/r/impostor",
    589 testing.MakeRealm(testutils.TestAddress("d"), testDelegate, testing.OriginRealm()),
    590 )
    591 uassert.Equal(t, testDelegate, fake.Previous().PkgPath(),
    592 "premise: the forged realm must pass the path check, or this proves nothing")
    593
    594 // PanicsContains, not Aborts: assertDelegate is called directly here, in
    595 // this realm, so the refusal is a panic. It surfaces as an abort only when
    596 // it happens across a realm boundary.
    597 uassert.PanicsContains(t, cur, "not the caller's live cur", func() {
    598 assertDelegate(0, fake, runSubmittersMgr, "the "+runSubmittersKey+" allowlist")
    599 })
    600}
    601

    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.