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