cosmos-sdk/simsx/v2/valset_history.go
Alexander Peters 8cdae287f7
test: Add more sims test scenarios (#23278)
Co-authored-by: Alex | Interchain Labs <alex@skip.money>
2025-01-13 09:50:55 +00:00

82 lines
2.5 KiB
Go

package v2
import (
"math/rand"
"slices"
"time"
"cosmossdk.io/core/comet"
"github.com/cosmos/cosmos-sdk/simsx"
)
type historicValSet struct {
blockTime time.Time
vals WeightedValidators
}
type ValSetHistory struct {
maxElements int
blockOffset uint64
vals []historicValSet
}
// NewValSetHistory constructor. The maximum of historic valsets must not exceed the block or time limit for
// valid evidence.
func NewValSetHistory(initialHeight uint64) *ValSetHistory {
return &ValSetHistory{
maxElements: 1,
blockOffset: initialHeight,
vals: make([]historicValSet, 0, 1),
}
}
func (h *ValSetHistory) Add(blockTime time.Time, vals WeightedValidators) {
vals = slices.DeleteFunc(vals, func(validator WeightedValidator) bool {
return validator.Power == 0
})
slices.SortFunc(vals, func(a, b WeightedValidator) int {
return b.Compare(a)
})
newEntry := historicValSet{blockTime: blockTime, vals: vals}
if len(h.vals) >= h.maxElements {
h.vals = append(h.vals[1:], newEntry)
h.blockOffset++
return
}
h.vals = append(h.vals, newEntry)
}
// MissBehaviour determines if a random validator misbehaves, creating and returning evidence for duplicate voting.
// Returns a slice of comet.Evidence if misbehavior is detected; otherwise, returns nil.
// Has a 1% chance of generating evidence for a validator's misbehavior.
// Recursively checks for other misbehavior instances and combines their evidence if any.
// Utilizes a random generator to select a validator and evidence-related attributes.
func (h *ValSetHistory) MissBehaviour(r *rand.Rand) []comet.Evidence {
if r.Intn(100) != 0 { // 1% chance
return nil
}
n := r.Intn(len(h.vals))
badVal := simsx.OneOf(r, h.vals[n].vals)
evidence := comet.Evidence{
Type: comet.DuplicateVote,
Validator: comet.Validator{Address: badVal.Address, Power: badVal.Power},
Height: int64(h.blockOffset) + int64(n),
Time: h.vals[n].blockTime,
TotalVotingPower: h.vals[n].vals.TotalPower(),
}
if otherEvidence := h.MissBehaviour(r); otherEvidence != nil {
return append([]comet.Evidence{evidence}, otherEvidence...)
}
return []comet.Evidence{evidence}
}
// SetMaxHistory sets the maximum number of historical validator sets to retain. Reduces retained history if it exceeds the limit.
func (h *ValSetHistory) SetMaxHistory(v int) {
h.maxElements = v
if len(h.vals) > h.maxElements {
diff := len(h.vals) - h.maxElements
h.vals = h.vals[diff:]
h.blockOffset += uint64(diff)
}
}