validators.gno

2.56 Kb ยท 117 lines
  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}