validators.gno
2.59 Kb ยท 118 lines
1package validators
2
3import (
4 "chain"
5 "chain/runtime"
6
7 "gno.land/p/nt/avl"
8 "gno.land/p/nt/seqid"
9 "gno.land/p/nt/ufmt"
10 "gno.land/p/sys/validators"
11)
12
13var (
14 vp validators.ValsetProtocol // p is the underlying validator set protocol
15 changes *avl.Tree // changes holds any valset changes; seqid(block number) -> []change
16)
17
18// change represents a single valset change, tied to a specific block number
19type change struct {
20 blockNum int64 // the block number associated with the valset change
21 validator validators.Validator // the validator update
22}
23
24// addValidator adds a new validator to the validator set.
25// If the validator is already present, the method errors out
26func addValidator(validator validators.Validator) {
27 val, err := vp.AddValidator(validator.Address, validator.PubKey, validator.VotingPower)
28 if err != nil {
29 panic(err)
30 }
31
32 // Validator added, note the change
33 ch := change{
34 blockNum: runtime.ChainHeight(),
35 validator: val,
36 }
37
38 saveChange(ch)
39
40 // Emit the validator set change
41 chain.Emit(validators.ValidatorAddedEvent)
42}
43
44// removeValidator removes the given validator from the set.
45// If the validator is not present in the set, the method errors out
46func removeValidator(address_XXX address) {
47 val, err := vp.RemoveValidator(address_XXX)
48 if err != nil {
49 panic(err)
50 }
51
52 // Validator removed, note the change
53 ch := change{
54 blockNum: runtime.ChainHeight(),
55 validator: validators.Validator{
56 Address: val.Address,
57 PubKey: val.PubKey,
58 VotingPower: 0, // nullified the voting power indicates removal
59 },
60 }
61
62 saveChange(ch)
63
64 // Emit the validator set change
65 chain.Emit(validators.ValidatorRemovedEvent)
66}
67
68// saveChange saves the valset change
69func saveChange(ch change) {
70 id := getBlockID(ch.blockNum)
71
72 setRaw, exists := changes.Get(id)
73 if !exists {
74 changes.Set(id, []change{ch})
75
76 return
77 }
78
79 // Save the change
80 set := setRaw.([]change)
81 set = append(set, ch)
82
83 changes.Set(id, set)
84}
85
86// getBlockID converts the block number to a sequential ID
87func getBlockID(blockNum int64) string {
88 return seqid.ID(uint64(blockNum)).String()
89}
90
91func Render(_ string) string {
92 var (
93 size = changes.Size()
94 maxDisplay = 10
95 )
96
97 if size == 0 {
98 return "No valset changes to apply."
99 }
100
101 output := "Valset changes:\n"
102 changes.ReverseIterateByOffset(size-maxDisplay, maxDisplay, func(_ string, value any) bool {
103 chs := value.([]change)
104
105 for _, ch := range chs {
106 output += ufmt.Sprintf(
107 "- #%d: %s (%d)\n",
108 ch.blockNum,
109 ch.validator.Address.String(),
110 ch.validator.VotingPower,
111 )
112 }
113
114 return false
115 })
116
117 return output
118}