cosmos-sdk/simsx/v2/valset.go
Alexander Peters cf721a6540
feat(sims): Integration with app v2 (#23013)
Co-authored-by: Alex | Interchain Labs <alex@skip.money>
2025-01-09 08:19:35 +00:00

109 lines
2.7 KiB
Go

package v2
import (
"bytes"
"crypto/sha256"
"math/rand"
"slices"
appmodulev2 "cosmossdk.io/core/appmodule/v2"
"cosmossdk.io/core/comet"
"github.com/cosmos/cosmos-sdk/simsx"
)
// WeightedValidator represents a validator for usage in the sims runner.
type WeightedValidator struct {
Power int64
Address []byte
Offline bool
}
// Compare determines the order between two WeightedValidator instances.
// Returns -1 if the caller has higher Power, 1 if it has lower Power, and defaults to comparing their Address bytes.
func (a WeightedValidator) Compare(b WeightedValidator) int {
switch {
case a.Power < b.Power:
return 1
case a.Power > b.Power:
return -1
default:
return bytes.Compare(a.Address, b.Address)
}
}
// NewValSet constructor
func NewValSet() WeightedValidators {
return make(WeightedValidators, 0)
}
// WeightedValidators represents a slice of WeightedValidator, used for managing and processing validator sets.
type WeightedValidators []WeightedValidator
func (v WeightedValidators) Update(updates []appmodulev2.ValidatorUpdate) WeightedValidators {
if len(updates) == 0 {
return v
}
const truncatedSize = 20
valUpdates := simsx.Collect(updates, func(u appmodulev2.ValidatorUpdate) WeightedValidator {
hash := sha256.Sum256(u.PubKey)
return WeightedValidator{Power: u.Power, Address: hash[:truncatedSize]}
})
newValset := slices.Clone(v)
for _, u := range valUpdates {
pos := slices.IndexFunc(newValset, func(val WeightedValidator) bool {
return bytes.Equal(u.Address, val.Address)
})
if pos == -1 { // new address
if u.Power > 0 {
newValset = append(newValset, u)
}
continue
}
if u.Power == 0 {
newValset = append(newValset[0:pos], newValset[pos+1:]...)
continue
}
newValset[pos].Power = u.Power
}
newValset = slices.DeleteFunc(newValset, func(validator WeightedValidator) bool {
return validator.Power == 0
})
// sort vals by Power
slices.SortFunc(newValset, func(a, b WeightedValidator) int {
return a.Compare(b)
})
return newValset
}
// NewCommitInfo build Comet commit info for the validator set
func (v WeightedValidators) NewCommitInfo(r *rand.Rand) comet.CommitInfo {
if len(v) == 0 {
return comet.CommitInfo{Votes: make([]comet.VoteInfo, 0)}
}
if r.Intn(10) == 0 {
v[r.Intn(len(v))].Offline = r.Intn(2) == 0
}
votes := make([]comet.VoteInfo, 0, len(v))
for i := range v {
if v[i].Offline {
continue
}
votes = append(votes, comet.VoteInfo{
Validator: comet.Validator{Address: v[i].Address, Power: v[i].Power},
BlockIDFlag: comet.BlockIDFlagCommit,
})
}
return comet.CommitInfo{Round: int32(r.Uint32()), Votes: votes}
}
func (v WeightedValidators) TotalPower() int64 {
var r int64
for _, val := range v {
r += val.Power
}
return r
}