valopers_test.gno
22.04 Kb · 698 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/v0/exts/authorizable"
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 t.Run("squat guard rejects mismatched OriginCaller", func(cur realm, t *testing.T) {
142 resetState()
143
144 info := validValidatorInfo(t)
145 // Caller is NOT info.Address: post-genesis squat guard fires.
146 testing.SetRealm(testing.NewUserRealm(testutils.TestAddress("attacker")))
147 testing.SetOriginSend(chain.Coins{minFee})
148
149 uassert.AbortsWithMessage(t, cur, ErrOperatorSquatGuard.Error(), func() {
150 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
151 })
152 })
153
154 t.Run("successful registration", func(cur realm, t *testing.T) {
155 resetState()
156
157 info := validValidatorInfo(t)
158 testing.SetRealm(testing.NewUserRealm(info.Address))
159
160 // Send coins.
161 testing.SetOriginSend(chain.Coins{minFee})
162
163 uassert.NotAborts(t, cur, func() {
164 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
165 })
166
167 uassert.NotPanics(t, cur, func() {
168 valoper := GetByAddr(info.Address)
169
170 uassert.Equal(t, info.Moniker, valoper.Moniker)
171 uassert.Equal(t, info.Description, valoper.Description)
172 uassert.Equal(t, info.ServerType, valoper.ServerType)
173 uassert.Equal(t, info.Address, valoper.OperatorAddress)
174 uassert.Equal(t, info.PubKey, valoper.SigningPubKey)
175 uassert.Equal(t, true, valoper.KeepRunning)
176
177 // SigningAddress is derived from the pubkey and present.
178 derived, err := chain.PubKeyAddress(info.PubKey)
179 uassert.NoError(t, err)
180 uassert.Equal(t, derived, valoper.SigningAddress)
181
182 // signingRegistry tracks the active entry.
183 uassert.True(t, signingRegistry.Has(derived.String()), "signingRegistry must contain the active entry")
184 })
185 })
186
187 t.Run("signing-key reuse rejected", func(cur realm, t *testing.T) {
188 resetState()
189
190 info := validValidatorInfo(t)
191 testing.SetRealm(testing.NewUserRealm(info.Address))
192 testing.SetOriginSend(chain.Coins{minFee})
193
194 // First registration succeeds.
195 uassert.NotAborts(t, cur, func() {
196 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
197 })
198
199 // Second attempt with a different operator addr but the same
200 // pubkey must fail signingRegistry uniqueness.
201 other := testutils.TestAddress("other-op")
202 testing.SetRealm(testing.NewUserRealm(other))
203 testing.SetOriginSend(chain.Coins{minFee})
204
205 uassert.AbortsWithMessage(t, cur, ErrSigningKeyTaken.Error(), func() {
206 Register(cross(cur), info.Moniker, info.Description, info.ServerType, other, info.PubKey)
207 })
208 })
209
210 t.Run("front-running guard rejects post-genesis if signing addr already validates", func(cur realm, t *testing.T) {
211 resetState()
212
213 info := validValidatorInfo(t)
214 // Seed v3's valset:current with the very signing address that
215 // `info.PubKey` derives to (g1sp8v98...). Any post-genesis
216 // Register attempting the same pubkey now trips
217 // `ChainHeight()>0 && validators.IsValidator(signingAddr)`.
218 testing.SetSysParamStrings("node", "valset", "current", []string{info.PubKey + ":1"})
219
220 testing.SetRealm(testing.NewUserRealm(info.Address))
221 testing.SetOriginSend(chain.Coins{minFee})
222
223 uassert.AbortsWithMessage(t, cur, ErrFrontrunValidator.Error(), func() {
224 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
225 })
226
227 // Cleanup: clear the seeded valset to avoid leaking into
228 // later subtests if the package state isn't reset between
229 // them in this test runner mode.
230 testing.SetSysParamStrings("node", "valset", "current", []string{})
231 })
232}
233
234func TestValopers_Register_AuthOwnerIsOperatorAddress(cur realm, t *testing.T) {
235 // Pin: the Authorizable owner is bound to the OperatorAddress
236 // (the addr arg), NOT to OriginCaller. This matters in the
237 // genesis-mode deployer pattern: one signer (e.g., the hardfork
238 // ceremony deployer) registers profiles for many operators.
239 // Each operator must end up on their own profile's auth list
240 // so they can manage it post-genesis without depending on the
241 // deployer.
242 t.Run("genesis deployer pattern: operator (not deployer) is owner", func(cur realm, t *testing.T) {
243 resetState()
244
245 info := validValidatorInfo(t)
246 deployer := testutils.TestAddress("deployer")
247
248 // Genesis mode: ChainHeight()==0 bypasses the squat guard so
249 // deployer (OriginCaller) can register a profile for a
250 // different operator addr.
251 testing.SetHeight(0)
252 testing.SetRealm(testing.NewUserRealm(deployer))
253 testing.SetOriginCaller(deployer)
254 testing.SetOriginSend(chain.Coins{minFee})
255
256 uassert.NotPanics(t, cur, func() {
257 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
258 })
259
260 // Auth owner must be the operator addr (info.Address), NOT
261 // the deployer.
262 v := GetByAddr(info.Address)
263 uassert.Equal(t, info.Address.String(), v.Auth().Owner().String(),
264 "auth owner must equal OperatorAddress, not OriginCaller")
265
266 // Operator can manage their own profile post-genesis.
267 testing.SetHeight(100)
268 testing.SetRealm(testing.NewUserRealm(info.Address))
269 testing.SetOriginCaller(info.Address)
270 uassert.NotPanics(t, cur, func() {
271 UpdateMoniker(cross(cur), info.Address, "operator-renamed")
272 })
273 uassert.Equal(t, "operator-renamed", GetByAddr(info.Address).Moniker)
274
275 // Deployer cannot manage the operator's profile (not on the
276 // auth list).
277 testing.SetRealm(testing.NewUserRealm(deployer))
278 testing.SetOriginCaller(deployer)
279 uassert.AbortsContains(t, cur, "caller is not in authorized list", func() {
280 UpdateMoniker(cross(cur), info.Address, "deployer-attempt")
281 })
282 })
283
284 t.Run("post-genesis self-Register: operator is owner", func(cur realm, t *testing.T) {
285 // At H>0 the squat guard forces OriginCaller==addr, so owner
286 // would be the same regardless. This subtest pins that the
287 // post-genesis behavior is unchanged.
288 resetState()
289
290 info := validValidatorInfo(t)
291 testing.SetHeight(100)
292 testing.SetRealm(testing.NewUserRealm(info.Address))
293 testing.SetOriginCaller(info.Address)
294 testing.SetOriginSend(chain.Coins{minFee})
295
296 uassert.NotPanics(t, cur, func() {
297 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
298 })
299
300 v := GetByAddr(info.Address)
301 uassert.Equal(t, info.Address.String(), v.Auth().Owner().String())
302 })
303}
304
305func TestValopers_UpdateAuthMembers(cur realm, t *testing.T) {
306 test2Address := testutils.TestAddress("test2")
307
308 t.Run("unauthorized member adds member", func(cur realm, t *testing.T) {
309 resetState()
310
311 info := validValidatorInfo(t)
312 testing.SetRealm(testing.NewUserRealm(info.Address))
313 testing.SetOriginSend(chain.Coins{minFee})
314
315 // Add the valoper.
316 uassert.NotPanics(t, cur, func() {
317 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
318 })
319
320 // A different caller (not on the auth list) tries to add a member.
321 testing.SetRealm(testing.NewUserRealm(test2Address))
322
323 uassert.AbortsWithMessage(t, cur, authorizable.ErrNotSuperuser.Error(), func() {
324 AddToAuthList(cross(cur), info.Address, test2Address)
325 })
326 })
327
328 t.Run("unauthorized member deletes member", func(cur realm, t *testing.T) {
329 resetState()
330
331 info := validValidatorInfo(t)
332 testing.SetRealm(testing.NewUserRealm(info.Address))
333 testing.SetOriginSend(chain.Coins{minFee})
334
335 uassert.NotPanics(t, cur, func() {
336 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
337 })
338
339 uassert.NotPanics(t, cur, func() {
340 AddToAuthList(cross(cur), info.Address, test2Address)
341 })
342
343 // A different caller tries to delete a member.
344 testing.SetRealm(testing.NewUserRealm(testutils.TestAddress("attacker")))
345
346 uassert.AbortsWithMessage(t, cur, authorizable.ErrNotSuperuser.Error(), func() {
347 DeleteFromAuthList(cross(cur), info.Address, test2Address)
348 })
349 })
350
351 t.Run("authorized member adds member", func(cur realm, t *testing.T) {
352 resetState()
353
354 info := validValidatorInfo(t)
355 testing.SetRealm(testing.NewUserRealm(info.Address))
356 testing.SetOriginSend(chain.Coins{minFee})
357
358 uassert.NotPanics(t, cur, func() {
359 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
360 })
361
362 uassert.NotPanics(t, cur, func() {
363 AddToAuthList(cross(cur), info.Address, test2Address)
364 })
365
366 testing.SetRealm(testing.NewUserRealm(test2Address))
367
368 newMoniker := "new moniker"
369 uassert.NotPanics(t, cur, func() {
370 UpdateMoniker(cross(cur), info.Address, newMoniker)
371 })
372
373 uassert.NotPanics(t, cur, func() {
374 valoper := GetByAddr(info.Address)
375 uassert.Equal(t, newMoniker, valoper.Moniker)
376 })
377 })
378}
379
380func TestValopers_UpdateMoniker(cur realm, t *testing.T) {
381 test2Address := testutils.TestAddress("test2")
382
383 t.Run("non-existing valoper", func(cur realm, t *testing.T) {
384 resetState()
385
386 info := validValidatorInfo(t)
387
388 uassert.AbortsWithMessage(t, cur, ErrValoperMissing.Error(), func() {
389 UpdateMoniker(cross(cur), info.Address, "new moniker")
390 })
391 })
392
393 t.Run("invalid caller", func(cur realm, t *testing.T) {
394 resetState()
395
396 info := validValidatorInfo(t)
397 testing.SetRealm(testing.NewUserRealm(info.Address))
398 testing.SetOriginSend(chain.Coins{minFee})
399
400 uassert.NotPanics(t, cur, func() {
401 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
402 })
403
404 // Change the caller to someone not on the auth list.
405 testing.SetRealm(testing.NewUserRealm(test2Address))
406
407 uassert.AbortsWithMessage(t, cur, authorizable.ErrNotInAuthList.Error(), func() {
408 UpdateMoniker(cross(cur), info.Address, "new moniker")
409 })
410 })
411
412 t.Run("invalid moniker", func(cur realm, t *testing.T) {
413 resetState()
414
415 info := validValidatorInfo(t)
416 testing.SetRealm(testing.NewUserRealm(info.Address))
417 testing.SetOriginSend(chain.Coins{minFee})
418
419 uassert.NotPanics(t, cur, func() {
420 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
421 })
422
423 invalidMonikers := []string{
424 "", // Empty
425 " ", // Whitespace
426 "a", // Too short
427 "a very long moniker that is longer than 32 characters", // Too long
428 "!@#$%^&*()+{}|:<>?/.,;'", // Invalid characters
429 " space in front",
430 "space in back ",
431 }
432
433 for _, invalidMoniker := range invalidMonikers {
434 uassert.AbortsWithMessage(t, cur, ErrInvalidMoniker.Error(), func() {
435 UpdateMoniker(cross(cur), info.Address, invalidMoniker)
436 })
437 }
438 })
439
440 t.Run("too long moniker", func(cur realm, t *testing.T) {
441 resetState()
442
443 info := validValidatorInfo(t)
444 testing.SetRealm(testing.NewUserRealm(info.Address))
445 testing.SetOriginSend(chain.Coins{minFee})
446
447 uassert.NotPanics(t, cur, func() {
448 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
449 })
450
451 uassert.AbortsWithMessage(t, cur, ErrInvalidMoniker.Error(), func() {
452 UpdateMoniker(cross(cur), info.Address, strings.Repeat("a", MonikerMaxLength+1))
453 })
454 })
455
456 t.Run("successful update", func(cur realm, t *testing.T) {
457 resetState()
458
459 info := validValidatorInfo(t)
460 testing.SetRealm(testing.NewUserRealm(info.Address))
461 testing.SetOriginSend(chain.Coins{minFee})
462
463 uassert.NotPanics(t, cur, func() {
464 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
465 })
466
467 newMoniker := "new moniker"
468 uassert.NotPanics(t, cur, func() {
469 UpdateMoniker(cross(cur), info.Address, newMoniker)
470 })
471
472 uassert.NotPanics(t, cur, func() {
473 valoper := GetByAddr(info.Address)
474 uassert.Equal(t, newMoniker, valoper.Moniker)
475 })
476 })
477}
478
479func TestValopers_UpdateDescription(cur realm, t *testing.T) {
480 test2Address := testutils.TestAddress("test2")
481
482 t.Run("non-existing valoper", func(cur realm, t *testing.T) {
483 resetState()
484
485 uassert.AbortsWithMessage(t, cur, ErrValoperMissing.Error(), func() {
486 UpdateDescription(cross(cur), validValidatorInfo(t).Address, "new description")
487 })
488 })
489
490 t.Run("invalid caller", func(cur realm, t *testing.T) {
491 resetState()
492
493 info := validValidatorInfo(t)
494 testing.SetRealm(testing.NewUserRealm(info.Address))
495 testing.SetOriginSend(chain.Coins{minFee})
496
497 uassert.NotPanics(t, cur, func() {
498 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
499 })
500
501 testing.SetRealm(testing.NewUserRealm(test2Address))
502
503 uassert.AbortsWithMessage(t, cur, authorizable.ErrNotInAuthList.Error(), func() {
504 UpdateDescription(cross(cur), info.Address, "new description")
505 })
506 })
507
508 t.Run("empty description", func(cur realm, t *testing.T) {
509 resetState()
510
511 info := validValidatorInfo(t)
512 testing.SetRealm(testing.NewUserRealm(info.Address))
513 testing.SetOriginSend(chain.Coins{minFee})
514
515 uassert.NotPanics(t, cur, func() {
516 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
517 })
518
519 uassert.AbortsWithMessage(t, cur, ErrInvalidDescription.Error(), func() {
520 UpdateDescription(cross(cur), info.Address, "")
521 })
522 })
523
524 t.Run("too long description", func(cur realm, t *testing.T) {
525 resetState()
526
527 info := validValidatorInfo(t)
528 testing.SetRealm(testing.NewUserRealm(info.Address))
529 testing.SetOriginSend(chain.Coins{minFee})
530
531 uassert.NotPanics(t, cur, func() {
532 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
533 })
534
535 uassert.AbortsWithMessage(t, cur, ErrInvalidDescription.Error(), func() {
536 UpdateDescription(cross(cur), info.Address, strings.Repeat("a", DescriptionMaxLength+1))
537 })
538 })
539
540 t.Run("successful update", func(cur realm, t *testing.T) {
541 resetState()
542
543 info := validValidatorInfo(t)
544 testing.SetRealm(testing.NewUserRealm(info.Address))
545 testing.SetOriginSend(chain.Coins{minFee})
546
547 uassert.NotPanics(t, cur, func() {
548 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
549 })
550
551 newDescription := "new description"
552 uassert.NotPanics(t, cur, func() {
553 UpdateDescription(cross(cur), info.Address, newDescription)
554 })
555
556 uassert.NotPanics(t, cur, func() {
557 valoper := GetByAddr(info.Address)
558 uassert.Equal(t, newDescription, valoper.Description)
559 })
560 })
561}
562
563func TestValopers_UpdateKeepRunning(cur realm, t *testing.T) {
564 test2Address := testutils.TestAddress("test2")
565
566 t.Run("non-existing valoper", func(cur realm, t *testing.T) {
567 resetState()
568
569 uassert.AbortsWithMessage(t, cur, ErrValoperMissing.Error(), func() {
570 UpdateKeepRunning(cross(cur), validValidatorInfo(t).Address, false)
571 })
572 })
573
574 t.Run("invalid caller", func(cur realm, t *testing.T) {
575 resetState()
576
577 info := validValidatorInfo(t)
578 testing.SetRealm(testing.NewUserRealm(info.Address))
579 testing.SetOriginSend(chain.Coins{minFee})
580
581 uassert.NotPanics(t, cur, func() {
582 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
583 })
584
585 testing.SetRealm(testing.NewUserRealm(test2Address))
586
587 uassert.AbortsWithMessage(t, cur, authorizable.ErrNotInAuthList.Error(), func() {
588 UpdateKeepRunning(cross(cur), info.Address, false)
589 })
590 })
591
592 t.Run("successful update", func(cur realm, t *testing.T) {
593 resetState()
594
595 info := validValidatorInfo(t)
596 testing.SetRealm(testing.NewUserRealm(info.Address))
597 testing.SetOriginSend(chain.Coins{minFee})
598
599 uassert.NotPanics(t, cur, func() {
600 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
601 })
602
603 uassert.NotPanics(t, cur, func() {
604 UpdateKeepRunning(cross(cur), info.Address, false)
605 })
606
607 uassert.NotPanics(t, cur, func() {
608 valoper := GetByAddr(info.Address)
609 uassert.Equal(t, false, valoper.KeepRunning)
610 })
611 })
612}
613
614func TestValopers_UpdateServerType(cur realm, t *testing.T) {
615 test2Address := testutils.TestAddress("test2")
616
617 t.Run("non-existing valoper", func(cur realm, t *testing.T) {
618 resetState()
619
620 uassert.AbortsWithMessage(t, cur, ErrValoperMissing.Error(), func() {
621 UpdateServerType(cross(cur), validValidatorInfo(t).Address, ServerTypeCloud)
622 })
623 })
624
625 t.Run("invalid caller", func(cur realm, t *testing.T) {
626 resetState()
627
628 info := validValidatorInfo(t)
629 testing.SetRealm(testing.NewUserRealm(info.Address))
630 testing.SetOriginSend(chain.Coins{minFee})
631
632 uassert.NotPanics(t, cur, func() {
633 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
634 })
635
636 testing.SetRealm(testing.NewUserRealm(test2Address))
637
638 uassert.AbortsWithMessage(t, cur, authorizable.ErrNotInAuthList.Error(), func() {
639 UpdateServerType(cross(cur), info.Address, ServerTypeCloud)
640 })
641 })
642
643 t.Run("invalid server type", func(cur realm, t *testing.T) {
644 resetState()
645
646 info := validValidatorInfo(t)
647 testing.SetRealm(testing.NewUserRealm(info.Address))
648 testing.SetOriginSend(chain.Coins{minFee})
649
650 uassert.NotPanics(t, cur, func() {
651 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
652 })
653
654 invalidServerTypes := []string{
655 "",
656 "invalid",
657 "Cloud", // case sensitive
658 "ON-PREM", // case sensitive
659 "datacenter", // wrong format
660 }
661
662 for _, invalidType := range invalidServerTypes {
663 uassert.AbortsWithMessage(t, cur, ErrInvalidServerType.Error(), func() {
664 UpdateServerType(cross(cur), info.Address, invalidType)
665 })
666 }
667 })
668
669 t.Run("successful update", func(cur realm, t *testing.T) {
670 resetState()
671
672 info := validValidatorInfo(t)
673 testing.SetRealm(testing.NewUserRealm(info.Address))
674 testing.SetOriginSend(chain.Coins{minFee})
675
676 uassert.NotPanics(t, cur, func() {
677 Register(cross(cur), info.Moniker, info.Description, info.ServerType, info.Address, info.PubKey)
678 })
679
680 uassert.NotPanics(t, cur, func() {
681 UpdateServerType(cross(cur), info.Address, ServerTypeCloud)
682 })
683
684 uassert.NotPanics(t, cur, func() {
685 valoper := GetByAddr(info.Address)
686 uassert.Equal(t, ServerTypeCloud, valoper.ServerType)
687 })
688
689 uassert.NotPanics(t, cur, func() {
690 UpdateServerType(cross(cur), info.Address, ServerTypeDataCenter)
691 })
692
693 uassert.NotPanics(t, cur, func() {
694 valoper := GetByAddr(info.Address)
695 uassert.Equal(t, ServerTypeDataCenter, valoper.ServerType)
696 })
697 })
698}