cosmos-sdk/tests/integration/v2/staking/vote_extensions_test.go

159 lines
4.8 KiB
Go

package staking
import (
"bytes"
"sort"
"testing"
abci "github.com/cometbft/cometbft/api/cometbft/abci/v1"
cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1"
protoio "github.com/cosmos/gogoproto/io"
"github.com/cosmos/gogoproto/proto"
gogotypes "github.com/cosmos/gogoproto/types"
"gotest.tools/v3/assert"
"cosmossdk.io/core/comet"
"cosmossdk.io/core/header"
"cosmossdk.io/math"
"cosmossdk.io/x/staking/testutil"
stakingtypes "cosmossdk.io/x/staking/types"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/tests/integration/v2"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
)
const chainID = "chain-id-123"
// TestValidateVoteExtensions is a unit test function that tests the validation of vote extensions.
// It sets up the necessary fixtures and validators, generates vote extensions for each validator,
// and validates the vote extensions using the baseapp.ValidateVoteExtensions function.
func TestValidateVoteExtensions(t *testing.T) {
t.Parallel()
f := initFixture(t, true)
// enable vote extensions
cp := simtestutil.DefaultConsensusParams
cp.Feature = &cmtproto.FeatureParams{VoteExtensionsEnableHeight: &gogotypes.Int64Value{Value: 1}}
assert.NilError(t, f.consensusKeeper.ParamsStore.Set(f.ctx, *cp))
f.ctx = integration.SetHeaderInfo(f.ctx, header.Info{Height: 2, ChainID: chainID})
// setup the validators
numVals := 1
privKeys := []cryptotypes.PrivKey{}
for i := 0; i < numVals; i++ {
privKeys = append(privKeys, ed25519.GenPrivKey())
}
vals := []stakingtypes.Validator{}
for _, v := range privKeys {
valAddr := sdk.ValAddress(v.PubKey().Address())
acc := f.accountKeeper.NewAccountWithAddress(f.ctx, sdk.AccAddress(v.PubKey().Address()))
f.accountKeeper.SetAccount(f.ctx, acc)
simtestutil.AddTestAddrsFromPubKeys(f.bankKeeper, f.stakingKeeper, f.ctx, []cryptotypes.PubKey{v.PubKey()}, math.NewInt(100000000000))
vals = append(vals, testutil.NewValidator(t, valAddr, v.PubKey()))
}
votes := []abci.ExtendedVoteInfo{}
for i, v := range vals {
v.Tokens = math.NewInt(1000000)
v.Status = stakingtypes.Bonded
assert.NilError(t, f.stakingKeeper.SetValidator(f.ctx, v))
assert.NilError(t, f.stakingKeeper.SetValidatorByConsAddr(f.ctx, v))
assert.NilError(t, f.stakingKeeper.SetNewValidatorByPowerIndex(f.ctx, v))
_, err := f.stakingKeeper.Delegate(f.ctx, sdk.AccAddress(privKeys[i].PubKey().Address()), v.Tokens, stakingtypes.Unbonded, v, true)
assert.NilError(t, err)
// each val produces a vote
voteExt := []byte("something" + v.OperatorAddress)
cve := cmtproto.CanonicalVoteExtension{
Extension: voteExt,
Height: integration.HeaderInfoFromContext(f.ctx).Height - 1, // the vote extension was signed in the previous height
Round: 0,
ChainId: chainID,
}
extSignBytes, err := mashalVoteExt(&cve)
assert.NilError(t, err)
sig, err := privKeys[i].Sign(extSignBytes)
assert.NilError(t, err)
valbz, err := f.stakingKeeper.ValidatorAddressCodec().StringToBytes(v.GetOperator())
assert.NilError(t, err)
ve := abci.ExtendedVoteInfo{
Validator: abci.Validator{
Address: valbz,
Power: 1000,
},
VoteExtension: voteExt,
ExtensionSignature: sig,
BlockIdFlag: cmtproto.BlockIDFlagCommit,
}
votes = append(votes, ve)
}
eci, ci := extendedCommitToLastCommit(abci.ExtendedCommitInfo{Round: 0, Votes: votes})
f.ctx = integration.SetCometInfo(f.ctx, ci)
err := baseapp.ValidateVoteExtensionsWithParams(f.ctx, *cp,
integration.HeaderInfoFromContext(f.ctx), ci, f.stakingKeeper, eci)
assert.NilError(t, err)
}
func mashalVoteExt(msg proto.Message) ([]byte, error) {
var buf bytes.Buffer
if err := protoio.NewDelimitedWriter(&buf).WriteMsg(msg); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func extendedCommitToLastCommit(ec abci.ExtendedCommitInfo) (abci.ExtendedCommitInfo, comet.Info) {
// sort the extended commit info
sort.Sort(extendedVoteInfos(ec.Votes))
// convert the extended commit info to last commit info
lastCommit := comet.CommitInfo{
Round: ec.Round,
Votes: make([]comet.VoteInfo, len(ec.Votes)),
}
for i, vote := range ec.Votes {
lastCommit.Votes[i] = comet.VoteInfo{
Validator: comet.Validator{
Address: vote.Validator.Address,
Power: vote.Validator.Power,
},
}
}
return ec, comet.Info{
LastCommit: lastCommit,
}
}
type extendedVoteInfos []abci.ExtendedVoteInfo
func (v extendedVoteInfos) Len() int {
return len(v)
}
func (v extendedVoteInfos) Less(i, j int) bool {
if v[i].Validator.Power == v[j].Validator.Power {
return bytes.Compare(v[i].Validator.Address, v[j].Validator.Address) == -1
}
return v[i].Validator.Power > v[j].Validator.Power
}
func (v extendedVoteInfos) Swap(i, j int) {
v[i], v[j] = v[j], v[i]
}