valopers_test.gno
23.55 Kb · 729 lines
1package valopers
2
3import (
4 "chain"
5 "strings"
6 "testing"
7
8 "gno.land/p/nt/avl/v0"
9 "gno.land/p/nt/bptree/v0"
10 "gno.land/p/nt/ownable/exts/authorizable/v0"
11 "gno.land/p/nt/testutils/v0"
12 "gno.land/p/nt/uassert/v0"
13 "gno.land/p/nt/ufmt/v0"
14)
15
16// Test-local fee constant. Production reads register_fee from sysparams;
17// these tests use this value as a reference Coin for OriginSend setup
18// and (when needed) seed it via testing.SetSysParamUint64.
19var minFee = chain.NewCoin("ugnot", 20*1_000_000)
20
21// cur is a zero-value realm used as a placeholder when forwarding to
22// uassert dispatch helpers that gained an `rlm realm` param. These tests
23// pass `func()` callbacks (no crossing inside the callback), so rlm is
24// ignored — a nil realm here is safe.
25var cur realm
26
27// resetState clears realm-level state and zeroes the valoper sys-params
28// so subtests don't leak through valopers (operator slots),
29// signingRegistry (signing-address uniqueness), or sys-param values.
30func resetState() {
31 valopers = avl.NewTree()
32 signingRegistry = bptree.NewBPTree32()
33 testing.SetSysParamUint64("node", "valoper", "register_fee", 0)
34 testing.SetSysParamUint64("node", "valoper", "rotation_fee", 0)
35 testing.SetSysParamInt64("node", "valoper", "rotation_period_blocks", 600)
36}
37
38// enableRegisterFee seeds register_fee = minFee.Amount in sysparams
39// so the Register fee path fires. Subtests that exercise fee
40// rejection or sufficient-fee acceptance call this after resetState.
41func enableRegisterFee() {
42 testing.SetSysParamUint64("node", "valoper", "register_fee", uint64(minFee.Amount))
43}
44
45func validValidatorInfo(t *testing.T) struct {
46 Moniker string
47 Description string
48 ServerType string
49 Address address
50 PubKey string
51} {
52 t.Helper()
53
54 return struct {
55 Moniker string
56 Description string
57 ServerType string
58 Address address
59 PubKey string
60 }{
61 Moniker: "test-1",
62 Description: "test-1's description",
63 ServerType: ServerTypeOnPrem,
64 Address: address("g1sp8v98h2gadm5jggtzz9w5ksexqn68ympsd68h"),
65 PubKey: "gpub1pggj7ard9eg82cjtv4u52epjx56nzwgjyg9zqwpdwpd0f9fvqla089ndw5g9hcsufad77fml2vlu73fk8q8sh8v72cza5p",
66 }
67}
68
69func TestValopers_Register(cur realm, t *testing.T) {
70 t.Run("already a valoper", func(cur realm, t *testing.T) {
71 resetState()
72
73 info := validValidatorInfo(t)
74 testing.SetRealm(testing.NewUserRealm(info.Address))
75
76 v := Valoper{
77 Moniker: info.Moniker,
78 Description: info.Description,
79 ServerType: info.ServerType,
80 OperatorAddress: info.Address,
81 SigningPubKey: info.PubKey,
82 KeepRunning: true,
83 }
84
85 // Add the valoper directly to the slot.
86 valopers.Set(v.OperatorAddress.String(), v)
87
88 // Send coins.
89 testing.SetOriginSend(chain.Coins{minFee})
90
91 uassert.AbortsWithMessage(t, cur, ErrValoperExists.Error(), func() {
92 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
93 })
94 })
95
96 t.Run("no coins deposited", func(cur realm, t *testing.T) {
97 resetState()
98 enableRegisterFee()
99
100 info := validValidatorInfo(t)
101 testing.SetRealm(testing.NewUserRealm(info.Address))
102
103 // Send no coins.
104 testing.SetOriginSend(chain.Coins{chain.NewCoin("ugnot", 0)})
105
106 uassert.AbortsWithMessage(t, cur, ufmt.Sprintf("payment must not be less than %d%s", minFee.Amount, minFee.Denom), func() {
107 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
108 })
109 })
110
111 t.Run("insufficient coins amount deposited", func(cur realm, t *testing.T) {
112 resetState()
113 enableRegisterFee()
114
115 info := validValidatorInfo(t)
116 testing.SetRealm(testing.NewUserRealm(info.Address))
117
118 // Send invalid coins.
119 testing.SetOriginSend(chain.Coins{chain.NewCoin("ugnot", minFee.Amount-1)})
120
121 uassert.AbortsWithMessage(t, cur, ufmt.Sprintf("payment must not be less than %d%s", minFee.Amount, minFee.Denom), func() {
122 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
123 })
124 })
125
126 t.Run("coin amount deposited is not ugnot", func(cur realm, t *testing.T) {
127 resetState()
128 enableRegisterFee()
129
130 info := validValidatorInfo(t)
131 testing.SetRealm(testing.NewUserRealm(info.Address))
132
133 // Send invalid coins.
134 testing.SetOriginSend(chain.Coins{chain.NewCoin("gnogno", minFee.Amount)})
135
136 uassert.AbortsWithMessage(t, cur, "incompatible coin denominations: gnogno, ugnot", func() {
137 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
138 })
139 })
140
141 // A fee above MaxInt64 wraps negative in Coin.Amount, which would make
142 // the IsLT amount check false for every payment: the realm would read
143 // the fee as configured and collect 1ugnot. uint64(int64(-1)) is what
144 // valopers/proposal.ProposeNewMinFeeProposalRequest stores for a
145 // negative newMinFee, so this is reachable from one governance typo.
146 t.Run("unrepresentable fee fails closed", func(cur realm, t *testing.T) {
147 resetState()
148 testing.SetSysParamUint64("node", "valoper", "register_fee", ^uint64(0))
149
150 info := validValidatorInfo(t)
151 testing.SetRealm(testing.NewUserRealm(info.Address))
152
153 // Nowhere near the configured fee, and previously accepted.
154 testing.SetOriginSend(chain.Coins{chain.NewCoin("ugnot", 1)})
155
156 uassert.AbortsWithMessage(t, cur, ErrFeeParamOutOfRange.Error(), func() {
157 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
158 })
159 uassert.False(t, isValoper(info.Address), "must not register")
160 })
161
162 t.Run("squat guard rejects mismatched OriginCaller", func(cur realm, t *testing.T) {
163 resetState()
164
165 info := validValidatorInfo(t)
166 // Caller is NOT info.Address: post-genesis squat guard fires.
167 testing.SetRealm(testing.NewUserRealm(testutils.TestAddress("attacker")))
168 testing.SetOriginSend(chain.Coins{minFee})
169
170 uassert.AbortsWithMessage(t, cur, ErrOperatorSquatGuard.Error(), func() {
171 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
172 })
173 })
174
175 t.Run("successful registration", func(cur realm, t *testing.T) {
176 resetState()
177
178 info := validValidatorInfo(t)
179 testing.SetRealm(testing.NewUserRealm(info.Address))
180
181 // Send coins.
182 testing.SetOriginSend(chain.Coins{minFee})
183
184 uassert.NotAborts(t, cur, func() {
185 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
186 })
187
188 uassert.NotPanics(t, cur, func() {
189 valoper := GetByAddr(info.Address)
190
191 uassert.Equal(t, info.Moniker, valoper.Moniker)
192 uassert.Equal(t, info.Description, valoper.Description)
193 uassert.Equal(t, info.ServerType, valoper.ServerType)
194 uassert.Equal(t, info.Address, valoper.OperatorAddress)
195 uassert.Equal(t, info.PubKey, valoper.SigningPubKey)
196 uassert.Equal(t, true, valoper.KeepRunning)
197
198 // SigningAddress is derived from the pubkey and present.
199 derived, err := chain.PubKeyAddress(info.PubKey)
200 uassert.NoError(t, err)
201 uassert.Equal(t, derived, valoper.SigningAddress)
202
203 // signingRegistry tracks the active entry.
204 uassert.True(t, signingRegistry.Has(derived.String()), "signingRegistry must contain the active entry")
205 })
206 })
207
208 t.Run("signing-key reuse rejected", func(cur realm, t *testing.T) {
209 resetState()
210
211 info := validValidatorInfo(t)
212 testing.SetRealm(testing.NewUserRealm(info.Address))
213 testing.SetOriginSend(chain.Coins{minFee})
214
215 // First registration succeeds.
216 uassert.NotAborts(t, cur, func() {
217 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
218 })
219
220 // Second attempt with a different operator addr but the same
221 // pubkey must fail signingRegistry uniqueness.
222 other := testutils.TestAddress("other-op")
223 testing.SetRealm(testing.NewUserRealm(other))
224 testing.SetOriginSend(chain.Coins{minFee})
225
226 uassert.AbortsWithMessage(t, cur, ErrSigningKeyTaken.Error(), func() {
227 Register(cross(cur), info.Moniker, info.Description, info.ServerType, other, info.PubKey)
228 })
229 })
230
231 t.Run("front-running guard rejects post-genesis if signing addr already validates", func(cur realm, t *testing.T) {
232 resetState()
233
234 info := validValidatorInfo(t)
235 // Seed v0's valset:current with the very signing address that
236 // `info.PubKey` derives to (g1sp8v98...). Any post-genesis
237 // Register attempting the same pubkey now trips
238 // `ChainHeight()>0 && validators.IsValidator(signingAddr)`.
239 testing.SetSysParamStrings("node", "valset", "current", []string{info.PubKey + ":1"})
240
241 testing.SetRealm(testing.NewUserRealm(info.Address))
242 testing.SetOriginSend(chain.Coins{minFee})
243
244 uassert.AbortsWithMessage(t, cur, ErrFrontrunValidator.Error(), func() {
245 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
246 })
247
248 // Cleanup: clear the seeded valset to avoid leaking into
249 // later subtests if the package state isn't reset between
250 // them in this test runner mode.
251 testing.SetSysParamStrings("node", "valset", "current", []string{})
252 })
253}
254
255func TestValopers_Register_AuthOwnerIsOperatorAddress(cur realm, t *testing.T) {
256 // Pin: the Authorizable owner is bound to the OperatorAddress
257 // (the addr arg), NOT to OriginCaller. This matters in the
258 // genesis-mode deployer pattern: one signer (e.g., the hardfork
259 // ceremony deployer) registers profiles for many operators.
260 // Each operator must end up on their own profile's auth list
261 // so they can manage it post-genesis without depending on the
262 // deployer.
263 t.Run("genesis deployer pattern: operator (not deployer) is owner", func(cur realm, t *testing.T) {
264 resetState()
265
266 info := validValidatorInfo(t)
267 deployer := testutils.TestAddress("deployer")
268
269 // Genesis mode: ChainHeight()==0 bypasses the squat guard so
270 // deployer (OriginCaller) can register a profile for a
271 // different operator addr.
272 testing.SetHeight(0)
273 testing.SetRealm(testing.NewUserRealm(deployer))
274 testing.SetOriginCaller(deployer)
275 testing.SetOriginSend(chain.Coins{minFee})
276
277 uassert.NotPanics(t, cur, func() {
278 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
279 })
280
281 // Auth owner must be the operator addr (info.Address), NOT
282 // the deployer.
283 //
284 // Asserted through the exported AuthOwner() accessor, not the
285 // private v.auth: AuthOwner is the API that replaced the removed
286 // Auth() capability leak, so it is what external readers see. A
287 // second assertion against the underlying Authorizable pins that
288 // the accessor actually reports the auth list's owner rather
289 // than echoing OperatorAddress, which is what a plausible
290 // "simplification" of AuthOwner would do.
291 v := GetByAddr(info.Address)
292 uassert.Equal(t, info.Address.String(), v.AuthOwner().String(),
293 "auth owner must equal OperatorAddress, not OriginCaller")
294 uassert.Equal(t, v.auth.Owner().String(), v.AuthOwner().String(),
295 "AuthOwner must report the Authorizable's owner")
296
297 // Operator can manage their own profile post-genesis.
298 testing.SetHeight(100)
299 testing.SetRealm(testing.NewUserRealm(info.Address))
300 testing.SetOriginCaller(info.Address)
301 uassert.NotPanics(t, cur, func() {
302 UpdateMoniker(cross(cur), info.Address, "operator-renamed")
303 })
304 uassert.Equal(t, "operator-renamed", GetByAddr(info.Address).Moniker)
305
306 // Deployer cannot manage the operator's profile (not on the
307 // auth list).
308 testing.SetRealm(testing.NewUserRealm(deployer))
309 testing.SetOriginCaller(deployer)
310 uassert.AbortsContains(t, cur, "caller is not in authorized list", func() {
311 UpdateMoniker(cross(cur), info.Address, "deployer-attempt")
312 })
313 })
314
315 t.Run("post-genesis self-Register: operator is owner", func(cur realm, t *testing.T) {
316 // At H>0 the squat guard forces OriginCaller==addr, so owner
317 // would be the same regardless. This subtest pins that the
318 // post-genesis behavior is unchanged.
319 resetState()
320
321 info := validValidatorInfo(t)
322 testing.SetHeight(100)
323 testing.SetRealm(testing.NewUserRealm(info.Address))
324 testing.SetOriginCaller(info.Address)
325 testing.SetOriginSend(chain.Coins{minFee})
326
327 uassert.NotPanics(t, cur, func() {
328 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
329 })
330
331 v := GetByAddr(info.Address)
332 uassert.Equal(t, info.Address.String(), v.AuthOwner().String())
333 })
334}
335
336func TestValopers_UpdateAuthMembers(cur realm, t *testing.T) {
337 test2Address := testutils.TestAddress("test2")
338
339 t.Run("unauthorized member adds member", func(cur realm, t *testing.T) {
340 resetState()
341
342 info := validValidatorInfo(t)
343 testing.SetRealm(testing.NewUserRealm(info.Address))
344 testing.SetOriginSend(chain.Coins{minFee})
345
346 // Add the valoper.
347 uassert.NotPanics(t, cur, func() {
348 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
349 })
350
351 // A different caller (not on the auth list) tries to add a member.
352 testing.SetRealm(testing.NewUserRealm(test2Address))
353
354 uassert.AbortsWithMessage(t, cur, authorizable.ErrNotSuperuser.Error(), func() {
355 AddToAuthList(cross(cur), info.Address, test2Address)
356 })
357 })
358
359 t.Run("unauthorized member deletes member", func(cur realm, t *testing.T) {
360 resetState()
361
362 info := validValidatorInfo(t)
363 testing.SetRealm(testing.NewUserRealm(info.Address))
364 testing.SetOriginSend(chain.Coins{minFee})
365
366 uassert.NotPanics(t, cur, func() {
367 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
368 })
369
370 uassert.NotPanics(t, cur, func() {
371 AddToAuthList(cross(cur), info.Address, test2Address)
372 })
373
374 // A different caller tries to delete a member.
375 testing.SetRealm(testing.NewUserRealm(testutils.TestAddress("attacker")))
376
377 uassert.AbortsWithMessage(t, cur, authorizable.ErrNotSuperuser.Error(), func() {
378 DeleteFromAuthList(cross(cur), info.Address, test2Address)
379 })
380 })
381
382 t.Run("authorized member adds member", func(cur realm, t *testing.T) {
383 resetState()
384
385 info := validValidatorInfo(t)
386 testing.SetRealm(testing.NewUserRealm(info.Address))
387 testing.SetOriginSend(chain.Coins{minFee})
388
389 uassert.NotPanics(t, cur, func() {
390 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
391 })
392
393 uassert.NotPanics(t, cur, func() {
394 AddToAuthList(cross(cur), info.Address, test2Address)
395 })
396
397 testing.SetRealm(testing.NewUserRealm(test2Address))
398
399 newMoniker := "new moniker"
400 uassert.NotPanics(t, cur, func() {
401 UpdateMoniker(cross(cur), info.Address, newMoniker)
402 })
403
404 uassert.NotPanics(t, cur, func() {
405 valoper := GetByAddr(info.Address)
406 uassert.Equal(t, newMoniker, valoper.Moniker)
407 })
408 })
409}
410
411func TestValopers_UpdateMoniker(cur realm, t *testing.T) {
412 test2Address := testutils.TestAddress("test2")
413
414 t.Run("non-existing valoper", func(cur realm, t *testing.T) {
415 resetState()
416
417 info := validValidatorInfo(t)
418
419 uassert.AbortsWithMessage(t, cur, ErrValoperMissing.Error(), func() {
420 UpdateMoniker(cross(cur), info.Address, "new moniker")
421 })
422 })
423
424 t.Run("invalid caller", func(cur realm, t *testing.T) {
425 resetState()
426
427 info := validValidatorInfo(t)
428 testing.SetRealm(testing.NewUserRealm(info.Address))
429 testing.SetOriginSend(chain.Coins{minFee})
430
431 uassert.NotPanics(t, cur, func() {
432 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
433 })
434
435 // Change the caller to someone not on the auth list.
436 testing.SetRealm(testing.NewUserRealm(test2Address))
437
438 uassert.AbortsWithMessage(t, cur, authorizable.ErrNotInAuthList.Error(), func() {
439 UpdateMoniker(cross(cur), info.Address, "new moniker")
440 })
441 })
442
443 t.Run("invalid moniker", func(cur realm, t *testing.T) {
444 resetState()
445
446 info := validValidatorInfo(t)
447 testing.SetRealm(testing.NewUserRealm(info.Address))
448 testing.SetOriginSend(chain.Coins{minFee})
449
450 uassert.NotPanics(t, cur, func() {
451 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
452 })
453
454 invalidMonikers := []string{
455 "", // Empty
456 " ", // Whitespace
457 "a", // Too short
458 "a very long moniker that is longer than 32 characters", // Too long
459 "!@#$%^&*()+{}|:<>?/.,;'", // Invalid characters
460 " space in front",
461 "space in back ",
462 }
463
464 for _, invalidMoniker := range invalidMonikers {
465 uassert.AbortsWithMessage(t, cur, ErrInvalidMoniker.Error(), func() {
466 UpdateMoniker(cross(cur), info.Address, invalidMoniker)
467 })
468 }
469 })
470
471 t.Run("too long moniker", func(cur realm, t *testing.T) {
472 resetState()
473
474 info := validValidatorInfo(t)
475 testing.SetRealm(testing.NewUserRealm(info.Address))
476 testing.SetOriginSend(chain.Coins{minFee})
477
478 uassert.NotPanics(t, cur, func() {
479 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
480 })
481
482 uassert.AbortsWithMessage(t, cur, ErrInvalidMoniker.Error(), func() {
483 UpdateMoniker(cross(cur), info.Address, strings.Repeat("a", MonikerMaxLength+1))
484 })
485 })
486
487 t.Run("successful update", func(cur realm, t *testing.T) {
488 resetState()
489
490 info := validValidatorInfo(t)
491 testing.SetRealm(testing.NewUserRealm(info.Address))
492 testing.SetOriginSend(chain.Coins{minFee})
493
494 uassert.NotPanics(t, cur, func() {
495 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
496 })
497
498 newMoniker := "new moniker"
499 uassert.NotPanics(t, cur, func() {
500 UpdateMoniker(cross(cur), info.Address, newMoniker)
501 })
502
503 uassert.NotPanics(t, cur, func() {
504 valoper := GetByAddr(info.Address)
505 uassert.Equal(t, newMoniker, valoper.Moniker)
506 })
507 })
508}
509
510func TestValopers_UpdateDescription(cur realm, t *testing.T) {
511 test2Address := testutils.TestAddress("test2")
512
513 t.Run("non-existing valoper", func(cur realm, t *testing.T) {
514 resetState()
515
516 uassert.AbortsWithMessage(t, cur, ErrValoperMissing.Error(), func() {
517 UpdateDescription(cross(cur), validValidatorInfo(t).Address, "new description")
518 })
519 })
520
521 t.Run("invalid caller", func(cur realm, t *testing.T) {
522 resetState()
523
524 info := validValidatorInfo(t)
525 testing.SetRealm(testing.NewUserRealm(info.Address))
526 testing.SetOriginSend(chain.Coins{minFee})
527
528 uassert.NotPanics(t, cur, func() {
529 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
530 })
531
532 testing.SetRealm(testing.NewUserRealm(test2Address))
533
534 uassert.AbortsWithMessage(t, cur, authorizable.ErrNotInAuthList.Error(), func() {
535 UpdateDescription(cross(cur), info.Address, "new description")
536 })
537 })
538
539 t.Run("empty description", func(cur realm, t *testing.T) {
540 resetState()
541
542 info := validValidatorInfo(t)
543 testing.SetRealm(testing.NewUserRealm(info.Address))
544 testing.SetOriginSend(chain.Coins{minFee})
545
546 uassert.NotPanics(t, cur, func() {
547 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
548 })
549
550 uassert.AbortsWithMessage(t, cur, ErrInvalidDescription.Error(), func() {
551 UpdateDescription(cross(cur), info.Address, "")
552 })
553 })
554
555 t.Run("too long description", func(cur realm, t *testing.T) {
556 resetState()
557
558 info := validValidatorInfo(t)
559 testing.SetRealm(testing.NewUserRealm(info.Address))
560 testing.SetOriginSend(chain.Coins{minFee})
561
562 uassert.NotPanics(t, cur, func() {
563 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
564 })
565
566 uassert.AbortsWithMessage(t, cur, ErrInvalidDescription.Error(), func() {
567 UpdateDescription(cross(cur), info.Address, strings.Repeat("a", DescriptionMaxLength+1))
568 })
569 })
570
571 t.Run("successful update", func(cur realm, t *testing.T) {
572 resetState()
573
574 info := validValidatorInfo(t)
575 testing.SetRealm(testing.NewUserRealm(info.Address))
576 testing.SetOriginSend(chain.Coins{minFee})
577
578 uassert.NotPanics(t, cur, func() {
579 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
580 })
581
582 newDescription := "new description"
583 uassert.NotPanics(t, cur, func() {
584 UpdateDescription(cross(cur), info.Address, newDescription)
585 })
586
587 uassert.NotPanics(t, cur, func() {
588 valoper := GetByAddr(info.Address)
589 uassert.Equal(t, newDescription, valoper.Description)
590 })
591 })
592}
593
594func TestValopers_UpdateKeepRunning(cur realm, t *testing.T) {
595 test2Address := testutils.TestAddress("test2")
596
597 t.Run("non-existing valoper", func(cur realm, t *testing.T) {
598 resetState()
599
600 uassert.AbortsWithMessage(t, cur, ErrValoperMissing.Error(), func() {
601 UpdateKeepRunning(cross(cur), validValidatorInfo(t).Address, false)
602 })
603 })
604
605 t.Run("invalid caller", func(cur realm, t *testing.T) {
606 resetState()
607
608 info := validValidatorInfo(t)
609 testing.SetRealm(testing.NewUserRealm(info.Address))
610 testing.SetOriginSend(chain.Coins{minFee})
611
612 uassert.NotPanics(t, cur, func() {
613 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
614 })
615
616 testing.SetRealm(testing.NewUserRealm(test2Address))
617
618 uassert.AbortsWithMessage(t, cur, authorizable.ErrNotInAuthList.Error(), func() {
619 UpdateKeepRunning(cross(cur), info.Address, false)
620 })
621 })
622
623 t.Run("successful update", func(cur realm, t *testing.T) {
624 resetState()
625
626 info := validValidatorInfo(t)
627 testing.SetRealm(testing.NewUserRealm(info.Address))
628 testing.SetOriginSend(chain.Coins{minFee})
629
630 uassert.NotPanics(t, cur, func() {
631 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
632 })
633
634 uassert.NotPanics(t, cur, func() {
635 UpdateKeepRunning(cross(cur), info.Address, false)
636 })
637
638 uassert.NotPanics(t, cur, func() {
639 valoper := GetByAddr(info.Address)
640 uassert.Equal(t, false, valoper.KeepRunning)
641 })
642 })
643}
644
645func TestValopers_UpdateServerType(cur realm, t *testing.T) {
646 test2Address := testutils.TestAddress("test2")
647
648 t.Run("non-existing valoper", func(cur realm, t *testing.T) {
649 resetState()
650
651 uassert.AbortsWithMessage(t, cur, ErrValoperMissing.Error(), func() {
652 UpdateServerType(cross(cur), validValidatorInfo(t).Address, ServerTypeCloud)
653 })
654 })
655
656 t.Run("invalid caller", func(cur realm, t *testing.T) {
657 resetState()
658
659 info := validValidatorInfo(t)
660 testing.SetRealm(testing.NewUserRealm(info.Address))
661 testing.SetOriginSend(chain.Coins{minFee})
662
663 uassert.NotPanics(t, cur, func() {
664 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
665 })
666
667 testing.SetRealm(testing.NewUserRealm(test2Address))
668
669 uassert.AbortsWithMessage(t, cur, authorizable.ErrNotInAuthList.Error(), func() {
670 UpdateServerType(cross(cur), info.Address, ServerTypeCloud)
671 })
672 })
673
674 t.Run("invalid server type", func(cur realm, t *testing.T) {
675 resetState()
676
677 info := validValidatorInfo(t)
678 testing.SetRealm(testing.NewUserRealm(info.Address))
679 testing.SetOriginSend(chain.Coins{minFee})
680
681 uassert.NotPanics(t, cur, func() {
682 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
683 })
684
685 invalidServerTypes := []string{
686 "",
687 "invalid",
688 "Cloud", // case sensitive
689 "ON-PREM", // case sensitive
690 "datacenter", // wrong format
691 }
692
693 for _, invalidType := range invalidServerTypes {
694 uassert.AbortsWithMessage(t, cur, ErrInvalidServerType.Error(), func() {
695 UpdateServerType(cross(cur), info.Address, invalidType)
696 })
697 }
698 })
699
700 t.Run("successful update", func(cur realm, t *testing.T) {
701 resetState()
702
703 info := validValidatorInfo(t)
704 testing.SetRealm(testing.NewUserRealm(info.Address))
705 testing.SetOriginSend(chain.Coins{minFee})
706
707 uassert.NotPanics(t, cur, func() {
708 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
709 })
710
711 uassert.NotPanics(t, cur, func() {
712 UpdateServerType(cross(cur), info.Address, ServerTypeCloud)
713 })
714
715 uassert.NotPanics(t, cur, func() {
716 valoper := GetByAddr(info.Address)
717 uassert.Equal(t, ServerTypeCloud, valoper.ServerType)
718 })
719
720 uassert.NotPanics(t, cur, func() {
721 UpdateServerType(cross(cur), info.Address, ServerTypeDataCenter)
722 })
723
724 uassert.NotPanics(t, cur, func() {
725 valoper := GetByAddr(info.Address)
726 uassert.Equal(t, ServerTypeDataCenter, valoper.ServerType)
727 })
728 })
729}