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/validators/v0

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
v0
Namespace
sys / validators
Files
7 (gnomod.toml)
Exported functions
9
Module
gno.land/r/sys/validators/v0
gno
0.9

Files (7)

  • gnomod.tomltoml
  • cache.gnogno
  • proposal.gnogno
  • validators.gnogno
  • cache_test.gnogno
  • proposal_test.gnogno
  • validators_test.gnogno
cache_test.gnogno
1package validators23import (4	"testing"56	"gno.land/p/nt/bptree/v0"7	"gno.land/p/nt/testutils/v0"8

Functions

  • AssertGenesisValopersConsistent(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})

  • GetValidator(addr string) struct{Address .uverse.address; PubKey string; VotingPower uint64}

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

  • IsValidator(addr string) bool

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

  • NewValoperChange(operatorAddress string, power uint64) struct{OperatorAddress .uverse.address; Power uint64}

  • NotifyValoperChanged(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}, op string, signingPubKey string, signingAddress string, keepRunning bool)

  • Render(string) string

  • RotateValoperSigningKey(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}, op string, oldPubKey string, newPubKey string)

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

Rendered

RenderedRawgnoweb ↗

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.

"gno.land/p/nt/uassert/v0"
9 "gno.land/p/nt/urequire/v0"
10 sysparams "gno.land/r/sys/params"
11)
12
13// cur is a zero-value realm used as a placeholder when forwarding to
14// uassert/urequire dispatch helpers that gained an `rlm realm` param.
15// These tests pass `func()` callbacks (no crossing inside the callback),
16// so rlm is ignored — a nil realm here is safe.
17var cur realm
18
19// resetCache clears valoperCache so subtests don't leak state.
20func resetCache() {
21 valoperCache = bptree.NewBPTree32()
22}
23
24func TestNotifyValoperChanged_HappyPath(cur realm, t *testing.T) {
25 resetCache()
26
27 op := testutils.TestAddress("op-A")
28 signingAddr := mustAddr(t, pubKeyA)
29
30 // Caller realm = valopers; auth check passes.
31 testing.SetRealm(testing.NewCodeRealm(valopersRealmPath))
32
33 NotifyValoperChanged(cross(cur), op, pubKeyA, signingAddr, true)
34
35 rawEntry := valoperCache.Get(op.String())
36 urequire.NotNil(t, rawEntry, "cache entry must exist")
37 entry := rawEntry.(cacheEntry)
38 uassert.Equal(t, pubKeyA, entry.SigningPubKey)
39 uassert.Equal(t, signingAddr, entry.SigningAddress)
40 uassert.Equal(t, true, entry.KeepRunning)
41
42 // Subsequent call updates the same slot.
43 signingAddrB := mustAddr(t, pubKeyB)
44 NotifyValoperChanged(cross(cur), op, pubKeyB, signingAddrB, false)
45
46 rawEntry = valoperCache.Get(op.String())
47 urequire.NotNil(t, rawEntry)
48 entry = rawEntry.(cacheEntry)
49 uassert.Equal(t, pubKeyB, entry.SigningPubKey)
50 uassert.Equal(t, signingAddrB, entry.SigningAddress)
51 uassert.Equal(t, false, entry.KeepRunning)
52}
53
54func TestNotifyValoperChanged_RejectsNonValopersCaller(cur realm, t *testing.T) {
55 resetCache()
56
57 op := testutils.TestAddress("op-A")
58 signingAddr := mustAddr(t, pubKeyA)
59
60 // Caller realm = some other realm; auth check rejects.
61 testing.SetRealm(testing.NewCodeRealm("gno.land/r/attacker"))
62
63 uassert.AbortsContains(t, cur, "caller realm must be "+valopersRealmPath, func() {
64 NotifyValoperChanged(cross(cur), op, pubKeyA, signingAddr, true)
65 })
66
67 // User MsgCall — UserRealm has empty pkgpath; rejected the same way.
68 testing.SetRealm(testing.NewUserRealm(testutils.TestAddress("user")))
69
70 uassert.AbortsContains(t, cur, "caller realm must be "+valopersRealmPath, func() {
71 NotifyValoperChanged(cross(cur), op, pubKeyA, signingAddr, true)
72 })
73}
74
75func TestRotateValoperSigningKey_AppliesRotation(cur realm, t *testing.T) {
76 resetValset(t)
77 resetCache()
78
79 // Seed the valset with op-A signing under pubKeyA at power=10.
80 testing.SetSysParamStrings(module, submodule, currKey, []string{pubKeyA + ":10"})
81
82 op := testutils.TestAddress("op-A")
83 testing.SetRealm(testing.NewCodeRealm(valopersRealmPath))
84
85 RotateValoperSigningKey(cross(cur), op, pubKeyA, pubKeyB)
86
87 // After rotation the effective set (proposed-when-dirty) should
88 // contain pubKeyB at the same power; pubKeyA should be gone.
89 uassert.True(t, sysparams.ValsetDirty(), "dirty bit set after RotateValoperSigningKey")
90
91 effective := sysparams.GetValsetEffective()
92 urequire.Equal(t, 1, len(effective))
93 uassert.Equal(t, pubKeyB, effective[0].PubKey)
94 uassert.Equal(t, uint64(10), effective[0].VotingPower)
95}
96
97func TestRotateValoperSigningKey_OperatorNotInValset_NoOp(cur realm, t *testing.T) {
98 resetValset(t)
99 resetCache()
100
101 // Empty valset; the operator is not currently signing.
102 op := testutils.TestAddress("op-A")
103 testing.SetRealm(testing.NewCodeRealm(valopersRealmPath))
104
105 // Should not panic; no sysparams write expected (dirty stays false).
106 uassert.NotAborts(t, cur, func() {
107 RotateValoperSigningKey(cross(cur), op, pubKeyA, pubKeyB)
108 })
109
110 uassert.False(t, sysparams.ValsetDirty(), "dirty bit must remain false on no-op rotation")
111 uassert.Equal(t, 0, len(sysparams.GetValsetEffective()))
112}
113
114func TestRotateValoperSigningKey_RejectsNonValopersCaller(cur realm, t *testing.T) {
115 resetValset(t)
116 resetCache()
117 testing.SetSysParamStrings(module, submodule, currKey, []string{pubKeyA + ":10"})
118
119 op := testutils.TestAddress("op-A")
120
121 // Foreign realm — rejected.
122 testing.SetRealm(testing.NewCodeRealm("gno.land/r/attacker"))
123 uassert.AbortsContains(t, cur, "caller realm must be "+valopersRealmPath, func() {
124 RotateValoperSigningKey(cross(cur), op, pubKeyA, pubKeyB)
125 })
126
127 // User MsgCall — UserRealm pkgpath is "" — rejected.
128 testing.SetRealm(testing.NewUserRealm(testutils.TestAddress("user")))
129 uassert.AbortsContains(t, cur, "caller realm must be "+valopersRealmPath, func() {
130 RotateValoperSigningKey(cross(cur), op, pubKeyA, pubKeyB)
131 })
132
133 // Sanity: the valset wasn't mutated by the rejected calls (dirty
134 // bit stays false; effective set still equals the seeded current).
135 uassert.False(t, sysparams.ValsetDirty())
136 effective := sysparams.GetValsetEffective()
137 urequire.Equal(t, 1, len(effective))
138 uassert.Equal(t, pubKeyA, effective[0].PubKey)
139}
140
141func TestAssertGenesisValopersConsistent_HappyPath(cur realm, t *testing.T) {
142 resetValset(t)
143 resetCache()
144 testing.SetHeight(0) // assertion is genesis-mode only
145
146 // Seed valset:current with two genesis validators.
147 testing.SetSysParamStrings(module, submodule, currKey, []string{
148 pubKeyA + ":10",
149 pubKeyB + ":5",
150 })
151
152 // Seed valoperCache with profiles whose SigningAddress matches.
153 opA := testutils.TestAddress("op-A")
154 opB := testutils.TestAddress("op-B")
155 seedCache(t, []struct {
156 op address
157 pubKey string
158 keepRunning bool
159 }{
160 {op: opA, pubKey: pubKeyA, keepRunning: true},
161 {op: opB, pubKey: pubKeyB, keepRunning: true},
162 })
163
164 uassert.NotAborts(t, cur, func() {
165 AssertGenesisValopersConsistent(cross(cur))
166 })
167}
168
169func TestAssertGenesisValopersConsistent_PanicsOnMissingProfile(cur realm, t *testing.T) {
170 resetValset(t)
171 resetCache()
172 testing.SetHeight(0)
173
174 // Two validators in valset:current but only one has a profile.
175 testing.SetSysParamStrings(module, submodule, currKey, []string{
176 pubKeyA + ":10",
177 pubKeyB + ":5",
178 })
179
180 opA := testutils.TestAddress("op-A")
181 seedCache(t, []struct {
182 op address
183 pubKey string
184 keepRunning bool
185 }{
186 {op: opA, pubKey: pubKeyA, keepRunning: true},
187 // op for pubKeyB intentionally missing.
188 })
189
190 uassert.AbortsContains(t, cur, "no corresponding valoper profile", func() {
191 AssertGenesisValopersConsistent(cross(cur))
192 })
193}
194
195func TestAssertGenesisValopersConsistent_EmptyValsetTrivial(cur realm, t *testing.T) {
196 resetValset(t)
197 resetCache()
198 testing.SetHeight(0)
199
200 // Empty valset → assertion trivially holds (no entries to check).
201 uassert.NotAborts(t, cur, func() {
202 AssertGenesisValopersConsistent(cross(cur))
203 })
204}
205
206func TestAssertGenesisValopersConsistent_RejectsPostGenesis(cur realm, t *testing.T) {
207 resetValset(t)
208 resetCache()
209 // Default test height is non-zero (123); the assertion must
210 // refuse to run outside genesis-mode replay.
211 uassert.AbortsContains(t, cur, "only callable during genesis-mode replay", func() {
212 AssertGenesisValopersConsistent(cross(cur))
213 })
214}
215
216func TestRotateValoperSigningKey_AccumulatesAcrossSameBlock(cur realm, t *testing.T) {
217 resetValset(t)
218 resetCache()
219
220 // Seed valset with two operators signing under pubKeyA and pubKeyC.
221 testing.SetSysParamStrings(module, submodule, currKey, []string{
222 pubKeyA + ":10",
223 pubKeyC + ":5",
224 })
225
226 opA := testutils.TestAddress("op-A")
227 opC := testutils.TestAddress("op-C")
228 testing.SetRealm(testing.NewCodeRealm(valopersRealmPath))
229
230 // First rotation: A → B. Read-modify-write of GetValsetEffective.
231 RotateValoperSigningKey(cross(cur), opA, pubKeyA, pubKeyB)
232
233 // Second rotation in the same block: C → A. Should not clobber
234 // the first rotation; should read proposed-when-dirty as baseline.
235 RotateValoperSigningKey(cross(cur), opC, pubKeyC, pubKeyA)
236
237 // Final effective set: {pubKeyB:10, pubKeyA:5}. Order may differ
238 // because GetValsetEffective parses sysparams' sorted-string slot
239 // and returns []Validator preserving that order.
240 effective := sysparams.GetValsetEffective()
241 urequire.Equal(t, 2, len(effective))
242
243 // Build a power-by-pubkey map and assert.
244 powerOf := map[string]uint64{}
245 for _, v := range effective {
246 powerOf[v.PubKey] = v.VotingPower
247 }
248 uassert.Equal(t, uint64(10), powerOf[pubKeyB])
249 uassert.Equal(t, uint64(5), powerOf[pubKeyA])
250 _, ok := powerOf[pubKeyC]
251 uassert.False(t, ok, "pubKeyC should be replaced by pubKeyA at the rotated slot")
252}
253