Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: fix x/slashing operations test #12346

Merged
merged 7 commits into from
Jun 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion simapp/params/weights.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ const (
DefaultWeightMsgDeposit int = 100
DefaultWeightMsgVote int = 67
DefaultWeightMsgVoteWeighted int = 33
DefaultWeightMsgUnjail int = 100
DefaultWeightMsgCreateValidator int = 100
DefaultWeightMsgEditValidator int = 5
DefaultWeightMsgDelegate int = 100
Expand Down
58 changes: 34 additions & 24 deletions testutil/sims/app_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,29 +53,46 @@ var DefaultConsensusParams = &tmproto.ConsensusParams{
},
}

// Setup initializes a new runtime.App. A Nop logger is set in runtime.App.
// appConfig usually load from a `app.yaml` with `appconfig.LoadYAML`, defines the application configuration.
// extraOutputs defines the extra outputs to be assigned by the dependency injector (depinject).
// createDefaultRandomValidatorSet creates a validator set with one random validator
func createDefaultRandomValidatorSet() (*tmtypes.ValidatorSet, error) {
privVal := mock.NewPV()
pubKey, err := privVal.GetPubKey(context.TODO())
if err != nil {
return nil, fmt.Errorf("failed to get pub key: %w", err)
}

// create validator set with single validator
validator := tmtypes.NewValidator(pubKey, 1)

return tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}), nil
}

// Setup initializes a new runtime.App and can inject values into extraOutputs.
// It uses SetupWithConfiguration under the hood.
func Setup(appConfig depinject.Config, extraOutputs ...interface{}) (*runtime.App, error) {
return SetupWithBaseAppOption(appConfig, nil, false, extraOutputs...)
return SetupWithConfiguration(appConfig, createDefaultRandomValidatorSet, nil, false, extraOutputs...)
}

// SetupAtGenesis initializes a new runtime.App at genesis. A Nop logger is set in runtime.App.
// appConfig usually load from a `app.yaml` with `appconfig.LoadYAML`, defines the application configuration.
// extraOutputs defines the extra outputs to be assigned by the dependency injector (depinject).
// SetupAtGenesis initializes a new runtime.App at genesis and can inject values into extraOutputs.
// It uses SetupWithConfiguration under the hood.
func SetupAtGenesis(appConfig depinject.Config, extraOutputs ...interface{}) (*runtime.App, error) {
return SetupWithBaseAppOption(appConfig, nil, true, extraOutputs...)
return SetupWithConfiguration(appConfig, createDefaultRandomValidatorSet, nil, true, extraOutputs...)
}

// SetupWithBaseAppOption initializes a new runtime.App and can inject values into extraOutputs.
// With specific baseApp options. It uses SetupWithConfiguration under the hood.
func SetupWithBaseAppOption(appConfig depinject.Config, baseAppOption runtime.BaseAppOption, extraOutputs ...interface{}) (*runtime.App, error) {
return SetupWithConfiguration(appConfig, createDefaultRandomValidatorSet, baseAppOption, false, extraOutputs...)
}

// SetupWithBaseAppOption initializes a new runtime.App. A Nop logger is set in runtime.App.
// SetupWithConfiguration initializes a new runtime.App. A Nop logger is set in runtime.App.
// appConfig usually load from a `app.yaml` with `appconfig.LoadYAML`, defines the application configuration.
// validatorSet defines a custom validator set to be validating the app.
// baseAppOption defines the additional operations that must be run on baseapp before app start.
// extraOutputs defines the extra outputs to be assigned by the dependency injector (depinject).
// genesis defines if the app started should already have produced block or not.
func SetupWithBaseAppOption(appConfig depinject.Config, baseAppOption runtime.BaseAppOption, genesis bool, extraOutputs ...interface{}) (*runtime.App, error) {
//
// create app
//
// extraOutputs defines the extra outputs to be assigned by the dependency injector (depinject).
func SetupWithConfiguration(appConfig depinject.Config, validatorSet func() (*tmtypes.ValidatorSet, error), baseAppOption runtime.BaseAppOption, genesis bool, extraOutputs ...interface{}) (*runtime.App, error) {
// create the app with depinject
var (
app *runtime.App
appBuilder *runtime.AppBuilder
Expand All @@ -98,19 +115,12 @@ func SetupWithBaseAppOption(appConfig depinject.Config, baseAppOption runtime.Ba
return nil, fmt.Errorf("failed to load app: %w", err)
}

//
// create genesis and validator
//
privVal := mock.NewPV()
pubKey, err := privVal.GetPubKey(context.TODO())
// create validator set
valSet, err := validatorSet()
if err != nil {
return nil, fmt.Errorf("failed to get pub key: %w", err)
return nil, fmt.Errorf("failed to create validator set")
}

// create validator set with single validator
validator := tmtypes.NewValidator(pubKey, 1)
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})

// generate genesis account
senderPrivKey := secp256k1.GenPrivKey()
acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0)
Expand Down
1 change: 0 additions & 1 deletion x/capability/capability_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ func (suite *CapabilityTestSuite) SetupTest() {
func(ba *baseapp.BaseApp) {
ba.MountStores(suite.memKey)
},
false,
&suite.cdc,
&suite.keeper,
)
Expand Down
129 changes: 73 additions & 56 deletions x/slashing/simulation/operations_test.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package simulation_test

import (
"fmt"
"math/rand"
"testing"
"time"

"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
tmtypes "github.com/tendermint/tendermint/types"

"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/runtime"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand All @@ -34,7 +36,9 @@ import (
type SimTestSuite struct {
suite.Suite

ctx sdk.Context
ctx sdk.Context
r *rand.Rand
accounts []simtypes.Account

app *runtime.App
legacyAmino *codec.LegacyAmino
Expand All @@ -46,12 +50,31 @@ type SimTestSuite struct {
slashingKeeper slashingkeeper.Keeper
distrKeeper distributionkeeper.Keeper
mintKeeper mintkeeper.Keeper
accs []simtypes.Account
}

func (suite *SimTestSuite) SetupTest() {
app, err := simtestutil.Setup(
s := rand.NewSource(1)
suite.r = rand.New(s)
accounts := simtypes.RandomAccounts(suite.r, 4)

// create validator (non random as using a seed)
createValidator := func() (*tmtypes.ValidatorSet, error) {
account := accounts[0]
tmPk, err := cryptocodec.ToTmPubKeyInterface(account.PubKey)
if err != nil {
return nil, fmt.Errorf("failed to create pubkey: %w", err)
}

validator := tmtypes.NewValidator(tmPk, 1)

return tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}), nil
}

app, err := simtestutil.SetupWithConfiguration(
testutil.AppConfig,
createValidator,
nil,
false,
&suite.legacyAmino,
&suite.codec,
&suite.interfaceRegistry,
Expand All @@ -67,34 +90,30 @@ func (suite *SimTestSuite) SetupTest() {
suite.app = app
suite.ctx = app.BaseApp.NewContext(false, tmproto.Header{})

s := rand.NewSource(1)
r := rand.New(s)
accounts := simtypes.RandomAccounts(r, 3)
// remove genesis validator account
suite.accounts = accounts[1:]

ctx := app.BaseApp.NewContext(false, tmproto.Header{})
initAmt := suite.stakingKeeper.TokensFromConsensusPower(ctx, 200)
initAmt := suite.stakingKeeper.TokensFromConsensusPower(suite.ctx, 200)
initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt))

// add coins to the accounts
for _, account := range accounts {
acc := suite.accountKeeper.NewAccountWithAddress(ctx, account.Address)
suite.accountKeeper.SetAccount(ctx, acc)
suite.Require().NoError(banktestutil.FundAccount(suite.bankKeeper, ctx, account.Address, initCoins))
for _, account := range suite.accounts {
acc := suite.accountKeeper.NewAccountWithAddress(suite.ctx, account.Address)
suite.accountKeeper.SetAccount(suite.ctx, acc)
suite.Require().NoError(banktestutil.FundAccount(suite.bankKeeper, suite.ctx, account.Address, initCoins))
}

suite.mintKeeper.SetParams(ctx, minttypes.DefaultParams())
suite.mintKeeper.SetMinter(ctx, minttypes.DefaultInitialMinter())
suite.accs = accounts
suite.mintKeeper.SetParams(suite.ctx, minttypes.DefaultParams())
suite.mintKeeper.SetMinter(suite.ctx, minttypes.DefaultInitialMinter())
}

// TestWeightedOperations tests the weights of the operations.
func (suite *SimTestSuite) TestWeightedOperations(t *testing.T) {
s := rand.NewSource(1)
r := rand.New(s)
app, ctx, accs := suite.app, suite.ctx, suite.accs
ctx.WithChainID("test-chain")
func TestSimTestSuite(t *testing.T) {
suite.Run(t, new(SimTestSuite))
}

cdc := suite.codec
// TestWeightedOperations tests the weights of the operations.
func (suite *SimTestSuite) TestWeightedOperations() {
ctx := suite.ctx.WithChainID("test-chain")
appParams := make(simtypes.AppParams)

expected := []struct {
Expand All @@ -103,40 +122,34 @@ func (suite *SimTestSuite) TestWeightedOperations(t *testing.T) {
opMsgName string
}{{simtestutil.DefaultWeightMsgUnjail, types.ModuleName, types.TypeMsgUnjail}}

weightesOps := simulation.WeightedOperations(appParams, cdc, suite.accountKeeper, suite.bankKeeper, suite.slashingKeeper, suite.stakingKeeper)
weightesOps := simulation.WeightedOperations(appParams, suite.codec, suite.accountKeeper, suite.bankKeeper, suite.slashingKeeper, suite.stakingKeeper)
for i, w := range weightesOps {
operationMsg, _, err := w.Op()(r, app.BaseApp, ctx, accs, ctx.ChainID())
require.NoError(t, err)
operationMsg, _, err := w.Op()(suite.r, suite.app.BaseApp, ctx, suite.accounts, ctx.ChainID())
suite.Require().NoError(err)

// the following checks are very much dependent from the ordering of the output given
// by WeightedOperations. if the ordering in WeightedOperations changes some tests
// will fail
suite.Require().Equal(t, expected[i].weight, w.Weight(), "weight should be the same")
suite.Require().Equal(t, expected[i].opMsgRoute, operationMsg.Route, "route should be the same")
suite.Require().Equal(t, expected[i].opMsgName, operationMsg.Name, "operation Msg name should be the same")
suite.Require().Equal(expected[i].weight, w.Weight(), "weight should be the same")
suite.Require().Equal(expected[i].opMsgRoute, operationMsg.Route, "route should be the same")
suite.Require().Equal(expected[i].opMsgName, operationMsg.Name, "operation Msg name should be the same")
}
}

// TestSimulateMsgUnjail tests the normal scenario of a valid message of type types.MsgUnjail.
// Abonormal scenarios, where the message is created by an errors, are not tested here.
func (suite *SimTestSuite) TestSimulateMsgUnjail(t *testing.T) {
// setup 3 accounts
s := rand.NewSource(5)
r := rand.New(s)
app, ctx, accounts := suite.app, suite.ctx, suite.accs
func (suite *SimTestSuite) TestSimulateMsgUnjail() {
blockTime := time.Now().UTC()
ctx = ctx.WithBlockTime(blockTime)

// remove genesis validator account
accounts = accounts[1:]
ctx := suite.ctx.WithBlockTime(blockTime)

// setup accounts[0] as validator0
validator0 := suite.getTestingValidator0(ctx, accounts)
validator0, err := getTestingValidator0(ctx, suite.stakingKeeper, suite.accounts)
suite.Require().NoError(err)

// setup validator0 by consensus address
suite.stakingKeeper.SetValidatorByConsAddr(ctx, validator0)
val0ConsAddress, err := validator0.GetConsAddr()
require.NoError(t, err)
suite.Require().NoError(err)
info := types.NewValidatorSigningInfo(val0ConsAddress, int64(4), int64(3),
time.Unix(2, 0), false, int64(10))
suite.slashingKeeper.SetValidatorSigningInfo(ctx, val0ConsAddress, info)
Expand All @@ -148,47 +161,51 @@ func (suite *SimTestSuite) TestSimulateMsgUnjail(t *testing.T) {
delTokens := suite.stakingKeeper.TokensFromConsensusPower(ctx, 2)
validator0, issuedShares := validator0.AddTokensFromDel(delTokens)
val0AccAddress, err := sdk.ValAddressFromBech32(validator0.OperatorAddress)
require.NoError(t, err)
suite.Require().NoError(err)
selfDelegation := stakingtypes.NewDelegation(val0AccAddress.Bytes(), validator0.GetOperator(), issuedShares)
suite.stakingKeeper.SetDelegation(ctx, selfDelegation)
suite.distrKeeper.SetDelegatorStartingInfo(ctx, validator0.GetOperator(), val0AccAddress.Bytes(), distrtypes.NewDelegatorStartingInfo(2, sdk.OneDec(), 200))

// begin a new block
app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash, Time: blockTime}})
suite.app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: suite.app.LastBlockHeight() + 1, AppHash: suite.app.LastCommitID().Hash, Time: blockTime}})

// execute operation
op := simulation.SimulateMsgUnjail(codec.NewProtoCodec(suite.interfaceRegistry), suite.accountKeeper, suite.bankKeeper, suite.slashingKeeper, suite.stakingKeeper)
operationMsg, futureOperations, err := op(r, app.BaseApp, ctx, accounts, "")
require.NoError(t, err)
operationMsg, futureOperations, err := op(suite.r, suite.app.BaseApp, ctx, suite.accounts, "")
suite.Require().NoError(err)

var msg types.MsgUnjail
types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)

require.True(t, operationMsg.OK)
require.Equal(t, types.TypeMsgUnjail, msg.Type())
require.Equal(t, "cosmosvaloper17s94pzwhsn4ah25tec27w70n65h5t2scgxzkv2", msg.ValidatorAddr)
require.Len(t, futureOperations, 0)
suite.Require().True(operationMsg.OK)
suite.Require().Equal(types.TypeMsgUnjail, msg.Type())
suite.Require().Equal("cosmosvaloper1p8wcgrjr4pjju90xg6u9cgq55dxwq8j7epjs3u", msg.ValidatorAddr)
suite.Require().Len(futureOperations, 0)
}

func (suite *SimTestSuite) getTestingValidator0(ctx sdk.Context, accounts []simtypes.Account) stakingtypes.Validator {
func getTestingValidator0(ctx sdk.Context, stakingKeeper *stakingkeeper.Keeper, accounts []simtypes.Account) (stakingtypes.Validator, error) {
commission0 := stakingtypes.NewCommission(sdk.ZeroDec(), sdk.OneDec(), sdk.OneDec())
return suite.getTestingValidator(commission0, 0)
return getTestingValidator(ctx, stakingKeeper, accounts, commission0, 0)
}

func (suite *SimTestSuite) getTestingValidator(commission stakingtypes.Commission, n int) stakingtypes.Validator {
ctx, accounts := suite.ctx, suite.accs
func getTestingValidator(ctx sdk.Context, stakingKeeper *stakingkeeper.Keeper, accounts []simtypes.Account, commission stakingtypes.Commission, n int) (stakingtypes.Validator, error) {
account := accounts[n]
valPubKey := account.ConsKey.PubKey()
valAddr := sdk.ValAddress(account.PubKey.Address().Bytes())
validator, err := stakingtypes.NewValidator(valAddr, valPubKey, stakingtypes.Description{})
suite.Require().NoError(err)
if err != nil {
return stakingtypes.Validator{}, fmt.Errorf("failed to create validator: %w", err)
}

validator, err = validator.SetInitialCommission(commission)
suite.Require().NoError(err)
if err != nil {
return stakingtypes.Validator{}, fmt.Errorf("failed to set initial commission: %w", err)
}

validator.DelegatorShares = sdk.NewDec(100)
validator.Tokens = sdk.NewInt(1000000)

suite.stakingKeeper.SetValidator(ctx, validator)
stakingKeeper.SetValidator(ctx, validator)

return validator
return validator, nil
}
18 changes: 13 additions & 5 deletions x/slashing/testutil/app.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,22 @@ modules:
config:
"@type": cosmos.app.runtime.v1alpha1.Module

app_name: SlashApp
app_name: SlashingApp

begin_blockers: [mint, staking, auth, bank, genutil, slashing, params]
end_blockers: [mint, staking, auth, bank, genutil, slashing, params]
init_genesis: [auth, bank, staking, mint, slashing, genutil, params]
begin_blockers:
[mint, distribution, staking, auth, bank, genutil, slashing, params]
end_blockers:
[staking, auth, bank, genutil, distribution, mint, slashing, params]
init_genesis:
[auth, bank, distribution, staking, mint, slashing, genutil, params]

- name: auth
config:
"@type": cosmos.auth.module.v1.Module
bech32_prefix: cosmos
module_account_permissions:
- account: fee_collector
- account: distribution
- account: mint
permissions: [minter]
- account: bonded_tokens_pool
Expand Down Expand Up @@ -44,8 +48,12 @@ modules:

- name: genutil
config:
"@type": cosmos.genutil.module.v1.Module
"@type": cosmos.genutil.module.v1.Module

- name: mint
config:
"@type": cosmos.mint.module.v1.Module

- name: distribution
config:
"@type": cosmos.distribution.module.v1.Module
1 change: 1 addition & 0 deletions x/slashing/testutil/app_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
_ "github.com/cosmos/cosmos-sdk/x/auth"
_ "github.com/cosmos/cosmos-sdk/x/auth/tx/module"
_ "github.com/cosmos/cosmos-sdk/x/bank"
_ "github.com/cosmos/cosmos-sdk/x/distribution"
_ "github.com/cosmos/cosmos-sdk/x/genutil"
_ "github.com/cosmos/cosmos-sdk/x/mint"
_ "github.com/cosmos/cosmos-sdk/x/params"
Expand Down