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/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
  • rotate_test.gnogno
    1package valopers23import (4	"chain"5	"testing"67	"gno.land/p/nt/testutils/v0"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 ↗
    "gno.land/p/nt/uassert/v0"
    9 "gno.land/p/nt/urequire/v0"
    10)
    11
    12const (
    13 // Second valid pubkey used as the rotation target. Distinct from
    14 // validValidatorInfo's pubkey so the signingRegistry uniqueness
    15 // check is exercised.
    16 rotateTargetPubKey = "gpub1pggj7ard9eg82cjtv4u52epjx56nzwgjyg9zq3ds6sdvc0shfkq02h6xx5g0jp04aadexfnpsmgjxu72xz9y30aqfrlpny"
    17
    18 // Test-local mirror of the rotation_period_blocks sys-param's
    19 // default. resetState() seeds the same value into sysparams.
    20 testRotationPeriodBlocks = int64(600)
    21)
    22
    23// registerForRotation does the boilerplate setup that every rotation
    24// test starts from: clear state, register the valoper as info.Address,
    25// and return the info struct. rlm is threaded into Register via
    26// cross(rlm) — it's a non-first parameter so the helper stays a
    27// regular (non-crossing) function.
    28func registerForRotation(t *testing.T, rlm realm) struct {
    29 Moniker string
    30 Description string
    31 ServerType string
    32 Address address
    33 PubKey string
    34} {
    35 t.Helper()
    36 resetState()
    37 info := validValidatorInfo(t)
    38 testing.SetRealm(testing.NewUserRealm(info.Address))
    39 testing.SetOriginSend(chain.Coins{minFee})
    40 Register(cross(rlm), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
    41 return info
    42}
    43
    44func TestUpdateSigningKey_HappyPath(cur realm, t *testing.T) {
    45 info := registerForRotation(t, cur)
    46
    47 // Advance past the throttle window. SkipHeights doesn't preserve
    48 // the realm context across the boundary, so re-set it before the
    49 // next cross-call.
    50 testing.SkipHeights(testRotationPeriodBlocks + 1)
    51 testing.SetRealm(testing.NewUserRealm(info.Address))
    52
    53 uassert.NotAborts(t, cur, func() {
    54 UpdateSigningKey(cross(cur), info.Address, rotateTargetPubKey)
    55 })
    56
    57 v := GetByAddr(info.Address)
    58 uassert.Equal(t, rotateTargetPubKey, v.SigningPubKey)
    59
    60 newSigningAddr, err := chain.PubKeyAddress(rotateTargetPubKey)
    61 urequire.NoError(t, err)
    62 uassert.Equal(t, newSigningAddr, v.SigningAddress)
    63
    64 // New entry active in registry.
    65 rawNew := signingRegistry.Get(newSigningAddr.String())
    66 urequire.NotNil(t, rawNew, "new signing addr in registry")
    67 newEntry := rawNew.(regEntry)
    68 uassert.Equal(t, info.Address, newEntry.OperatorAddress)
    69 uassert.Equal(t, int64(0), newEntry.RetiredAtHeight)
    70
    71 // Old entry retired (still present, RetiredAtHeight > 0).
    72 oldSigningAddr, err := chain.PubKeyAddress(info.PubKey)
    73 urequire.NoError(t, err)
    74 rawOld := signingRegistry.Get(oldSigningAddr.String())
    75 urequire.NotNil(t, rawOld, "old signing addr retained as retired")
    76 oldEntry := rawOld.(regEntry)
    77 uassert.Equal(t, info.Address, oldEntry.OperatorAddress)
    78 uassert.True(t, oldEntry.RetiredAtHeight > 0, "old entry must be retired (RetiredAtHeight > 0)")
    79}
    80
    81func TestUpdateSigningKey_ThrottleRejection(cur realm, t *testing.T) {
    82 info := registerForRotation(t, cur)
    83 testing.SetRealm(testing.NewUserRealm(info.Address))
    84
    85 // Try to rotate immediately, before throttle elapses.
    86 uassert.AbortsWithMessage(t, cur, ErrRotationThrottled.Error(), func() {
    87 UpdateSigningKey(cross(cur), info.Address, rotateTargetPubKey)
    88 })
    89
    90 // Advance just shy of the threshold; still rejected.
    91 testing.SkipHeights(testRotationPeriodBlocks - 1)
    92 testing.SetRealm(testing.NewUserRealm(info.Address))
    93 uassert.AbortsWithMessage(t, cur, ErrRotationThrottled.Error(), func() {
    94 UpdateSigningKey(cross(cur), info.Address, rotateTargetPubKey)
    95 })
    96
    97 // One more block — now exactly at the threshold; allowed.
    98 testing.SkipHeights(1)
    99 testing.SetRealm(testing.NewUserRealm(info.Address))
    100 uassert.NotAborts(t, cur, func() {
    101 UpdateSigningKey(cross(cur), info.Address, rotateTargetPubKey)
    102 })
    103}
    104
    105func TestUpdateSigningKey_RejectsNonAuthListCaller(cur realm, t *testing.T) {
    106 info := registerForRotation(t, cur)
    107 testing.SkipHeights(testRotationPeriodBlocks + 1)
    108
    109 // Switch to a caller not on the auth list.
    110 testing.SetRealm(testing.NewUserRealm(testutils.TestAddress("attacker")))
    111
    112 // Pin the exact authorizable error so this catches an auth
    113 // regression rather than any abort. Empty-substring match (the
    114 // previous form) accepted any panic, including unrelated ones.
    115 uassert.AbortsContains(t, cur, "not in authorized list", func() {
    116 UpdateSigningKey(cross(cur), info.Address, rotateTargetPubKey)
    117 })
    118}
    119
    120func TestUpdateSigningKey_RejectsReuseOfActiveKey(cur realm, t *testing.T) {
    121 info := registerForRotation(t, cur)
    122 testing.SkipHeights(testRotationPeriodBlocks + 1)
    123 testing.SetRealm(testing.NewUserRealm(info.Address))
    124
    125 // Try to "rotate" to the same key — already in registry.
    126 uassert.AbortsWithMessage(t, cur, ErrSigningKeyTaken.Error(), func() {
    127 UpdateSigningKey(cross(cur), info.Address, info.PubKey)
    128 })
    129}
    130
    131func TestUpdateSigningKey_RejectsRotationOntoActiveValidator(cur realm, t *testing.T) {
    132 // Front-running guard: a rotation whose derived signing address is
    133 // already an active validator must be rejected. Mirrors the same
    134 // guard in Register (valopers.gno: ErrFrontrunValidator). Without
    135 // this, any valoper could rotate onto an unregistered (e.g.
    136 // genesis-seeded) validator slot — v0's executor would overwrite
    137 // the active validator's entry in the effective valset with this
    138 // operator's claim, then a subsequent govDAO remove-op proposal
    139 // would delete it. signingRegistry uniqueness alone doesn't catch
    140 // this case: a genesis-seeded validator never went through
    141 // Register or UpdateSigningKey, so its signing address is absent
    142 // from signingRegistry.
    143 info := registerForRotation(t, cur)
    144
    145 // Seed v0's valset:current with the address that rotateTargetPubKey
    146 // derives to. ValsetEffective is read from valset:current when the
    147 // dirty flag is unset, which is the default.
    148 testing.SetSysParamStrings("node", "valset", "current",
    149 []string{rotateTargetPubKey + ":1"})
    150
    151 testing.SkipHeights(testRotationPeriodBlocks + 1)
    152 testing.SetRealm(testing.NewUserRealm(info.Address))
    153
    154 uassert.AbortsWithMessage(t, cur, ErrFrontrunValidator.Error(), func() {
    155 UpdateSigningKey(cross(cur), info.Address, rotateTargetPubKey)
    156 })
    157
    158 // Cleanup: clear the seeded valset to avoid leaking into sibling
    159 // subtests if the runner doesn't reset package state between them.
    160 testing.SetSysParamStrings("node", "valset", "current", []string{})
    161}
    162
    163func TestUpdateSigningKey_RejectsReuseOfRetiredKey(cur realm, t *testing.T) {
    164 info := registerForRotation(t, cur)
    165
    166 // First rotation: info.PubKey -> rotateTargetPubKey. info.PubKey
    167 // becomes retired.
    168 testing.SkipHeights(testRotationPeriodBlocks + 1)
    169 testing.SetRealm(testing.NewUserRealm(info.Address))
    170 UpdateSigningKey(cross(cur), info.Address, rotateTargetPubKey)
    171
    172 // Second rotation back to info.PubKey must fail — it's retired
    173 // but signingRegistry retains it forever.
    174 testing.SkipHeights(testRotationPeriodBlocks + 1)
    175 testing.SetRealm(testing.NewUserRealm(info.Address))
    176 uassert.AbortsWithMessage(t, cur, ErrSigningKeyTaken.Error(), func() {
    177 UpdateSigningKey(cross(cur), info.Address, info.PubKey)
    178 })
    179}
    180
    181func TestUpdateSigningKey_LastRotationHeightAdvances(cur realm, t *testing.T) {
    182 info := registerForRotation(t, cur)
    183 testing.SkipHeights(testRotationPeriodBlocks + 1)
    184 testing.SetRealm(testing.NewUserRealm(info.Address))
    185 UpdateSigningKey(cross(cur), info.Address, rotateTargetPubKey)
    186
    187 v := GetByAddr(info.Address)
    188 uassert.True(t, v.LastRotationHeight > 0, "LastRotationHeight set on rotation")
    189
    190 // Immediately after, throttle rejects again.
    191 uassert.AbortsWithMessage(t, cur, ErrRotationThrottled.Error(), func() {
    192 UpdateSigningKey(cross(cur), info.Address, "gpub1pgfj7ard9eg82cjtv4u4xetrwqer2dntxyfzxz3pqddddqg2glc8x4fl7vxjlnr7p5a3czm5kcdp4239sg6yqdc4rc2r5cjrffs")
    193 })
    194}
    195

    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.