Use module accounts in MsgSend and MsgMultiSend tests in bank module (#9075)
* first draft * unable to cast to simtypes.Account * fix test * add for loop in TestSimulateModuleAccountMsgSend * TestSimulateModuleAccountMsgMultiSend * refactoring, r4r * change fromSimAcc, toSimAcc to from,to respectively * Update x/bank/simulation/operations.go Co-authored-by: Robert Zaremba <robert@zaremba.ch> * Update x/bank/simulation/operations.go Co-authored-by: Robert Zaremba <robert@zaremba.ch> * getModuleAccounts * fix for loop * applied reviewers suggestions, r4r * Update x/bank/simulation/operations.go Co-authored-by: Robert Zaremba <robert@zaremba.ch> * minor changes * fix typo * all simulation package tests pass, r4r Co-authored-by: anilCSE <anil@vitwit.com> Co-authored-by: Robert Zaremba <robert@zaremba.ch> Co-authored-by: Cory <cjlevinson@gmail.com> Co-authored-by: Aaron Craelius <aaron@regen.network> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
parent
f2cea6a137
commit
8997074028
|
@ -12,6 +12,7 @@ import (
|
|||
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank/keeper"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/simulation"
|
||||
)
|
||||
|
||||
|
@ -58,7 +59,7 @@ func SimulateMsgSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Operatio
|
|||
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
accs []simtypes.Account, chainID string,
|
||||
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
||||
simAccount, toSimAcc, coins, skip := randomSendFields(r, ctx, accs, bk, ak)
|
||||
from, to, coins, skip := randomSendFields(r, ctx, accs, bk, ak)
|
||||
|
||||
// Check send_enabled status of each coin denom
|
||||
if err := bk.IsSendEnabledCoins(ctx, coins...); err != nil {
|
||||
|
@ -69,9 +70,39 @@ func SimulateMsgSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Operatio
|
|||
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgSend, "skip all transfers"), nil, nil
|
||||
}
|
||||
|
||||
msg := types.NewMsgSend(simAccount.Address, toSimAcc.Address, coins)
|
||||
msg := types.NewMsgSend(from.Address, to.Address, coins)
|
||||
|
||||
err := sendMsgSend(r, app, bk, ak, msg, ctx, chainID, []cryptotypes.PrivKey{simAccount.PrivKey})
|
||||
err := sendMsgSend(r, app, bk, ak, msg, ctx, chainID, []cryptotypes.PrivKey{from.PrivKey})
|
||||
if err != nil {
|
||||
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "invalid transfers"), nil, err
|
||||
}
|
||||
|
||||
return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
// SimulateMsgSendToModuleAccount tests and runs a single msg send where both
|
||||
// accounts already exist.
|
||||
func SimulateMsgSendToModuleAccount(ak types.AccountKeeper, bk keeper.Keeper, moduleAccCount int) simtypes.Operation {
|
||||
return func(
|
||||
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
accs []simtypes.Account, chainID string,
|
||||
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
||||
from := accs[0]
|
||||
|
||||
to := getModuleAccounts(ak, ctx, moduleAccCount)[0]
|
||||
|
||||
spendable := bk.SpendableCoins(ctx, from.Address)
|
||||
coins := simtypes.RandSubsetCoins(r, spendable)
|
||||
|
||||
// Check send_enabled status of each coin denom
|
||||
if err := bk.IsSendEnabledCoins(ctx, coins...); err != nil {
|
||||
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgSend, err.Error()), nil, nil
|
||||
}
|
||||
|
||||
msg := types.NewMsgSend(from.Address, to.Address, coins)
|
||||
|
||||
err := sendMsgSend(r, app, bk, ak, msg, ctx, chainID, []cryptotypes.PrivKey{from.PrivKey})
|
||||
if err != nil {
|
||||
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "invalid transfers"), nil, err
|
||||
}
|
||||
|
@ -150,11 +181,11 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Ope
|
|||
var totalSentCoins sdk.Coins
|
||||
for i := range inputs {
|
||||
// generate random input fields, ignore to address
|
||||
simAccount, _, coins, skip := randomSendFields(r, ctx, accs, bk, ak)
|
||||
from, _, coins, skip := randomSendFields(r, ctx, accs, bk, ak)
|
||||
|
||||
// make sure account is fresh and not used in previous input
|
||||
for usedAddrs[simAccount.Address.String()] {
|
||||
simAccount, _, coins, skip = randomSendFields(r, ctx, accs, bk, ak)
|
||||
for usedAddrs[from.Address.String()] {
|
||||
from, _, coins, skip = randomSendFields(r, ctx, accs, bk, ak)
|
||||
}
|
||||
|
||||
if skip {
|
||||
|
@ -162,13 +193,13 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Ope
|
|||
}
|
||||
|
||||
// set input address in used address map
|
||||
usedAddrs[simAccount.Address.String()] = true
|
||||
usedAddrs[from.Address.String()] = true
|
||||
|
||||
// set signer privkey
|
||||
privs[i] = simAccount.PrivKey
|
||||
privs[i] = from.PrivKey
|
||||
|
||||
// set next input and accumulate total sent coins
|
||||
inputs[i] = types.NewInput(simAccount.Address, coins)
|
||||
inputs[i] = types.NewInput(from.Address, coins)
|
||||
totalSentCoins = totalSentCoins.Add(coins...)
|
||||
}
|
||||
|
||||
|
@ -195,8 +226,8 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Ope
|
|||
}
|
||||
|
||||
// remove any output that has no coins
|
||||
i := 0
|
||||
for i < len(outputs) {
|
||||
|
||||
for i := 0; i < len(outputs); {
|
||||
if outputs[i].Coins.Empty() {
|
||||
outputs[i] = outputs[len(outputs)-1]
|
||||
outputs = outputs[:len(outputs)-1]
|
||||
|
@ -210,7 +241,73 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Ope
|
|||
Inputs: inputs,
|
||||
Outputs: outputs,
|
||||
}
|
||||
err := sendMsgMultiSend(r, app, bk, ak, msg, ctx, chainID, privs)
|
||||
if err != nil {
|
||||
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "invalid transfers"), nil, err
|
||||
}
|
||||
|
||||
return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
// SimulateMsgMultiSendToModuleAccount sends coins to Module Accounts
|
||||
func SimulateMsgMultiSendToModuleAccount(ak types.AccountKeeper, bk keeper.Keeper, moduleAccCount int) simtypes.Operation {
|
||||
return func(
|
||||
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
accs []simtypes.Account, chainID string,
|
||||
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
||||
|
||||
inputs := make([]types.Input, 2)
|
||||
outputs := make([]types.Output, moduleAccCount)
|
||||
// collect signer privKeys
|
||||
privs := make([]cryptotypes.PrivKey, len(inputs))
|
||||
|
||||
var totalSentCoins sdk.Coins
|
||||
for i := range inputs {
|
||||
sender := accs[i]
|
||||
privs[i] = sender.PrivKey
|
||||
spendable := bk.SpendableCoins(ctx, sender.Address)
|
||||
coins := simtypes.RandSubsetCoins(r, spendable)
|
||||
inputs[i] = types.NewInput(sender.Address, coins)
|
||||
totalSentCoins = totalSentCoins.Add(coins...)
|
||||
}
|
||||
|
||||
if err := bk.IsSendEnabledCoins(ctx, totalSentCoins...); err != nil {
|
||||
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgMultiSend, err.Error()), nil, nil
|
||||
}
|
||||
|
||||
moduleAccounts := getModuleAccounts(ak, ctx, moduleAccCount)
|
||||
for i := range outputs {
|
||||
var outCoins sdk.Coins
|
||||
// split total sent coins into random subsets for output
|
||||
if i == len(outputs)-1 {
|
||||
outCoins = totalSentCoins
|
||||
} else {
|
||||
// take random subset of remaining coins for output
|
||||
// and update remaining coins
|
||||
outCoins = simtypes.RandSubsetCoins(r, totalSentCoins)
|
||||
totalSentCoins = totalSentCoins.Sub(outCoins)
|
||||
}
|
||||
|
||||
outputs[i] = types.NewOutput(moduleAccounts[i].Address, outCoins)
|
||||
}
|
||||
|
||||
// remove any output that has no coins
|
||||
|
||||
for i := 0; i < len(outputs); {
|
||||
if outputs[i].Coins.Empty() {
|
||||
outputs[i] = outputs[len(outputs)-1]
|
||||
outputs = outputs[:len(outputs)-1]
|
||||
} else {
|
||||
// continue onto next coin
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
msg := &types.MsgMultiSend{
|
||||
Inputs: inputs,
|
||||
Outputs: outputs,
|
||||
}
|
||||
err := sendMsgMultiSend(r, app, bk, ak, msg, ctx, chainID, privs)
|
||||
if err != nil {
|
||||
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "invalid transfers"), nil, err
|
||||
|
@ -291,25 +388,44 @@ func randomSendFields(
|
|||
r *rand.Rand, ctx sdk.Context, accs []simtypes.Account, bk keeper.Keeper, ak types.AccountKeeper,
|
||||
) (simtypes.Account, simtypes.Account, sdk.Coins, bool) {
|
||||
|
||||
simAccount, _ := simtypes.RandomAcc(r, accs)
|
||||
toSimAcc, _ := simtypes.RandomAcc(r, accs)
|
||||
from, _ := simtypes.RandomAcc(r, accs)
|
||||
to, _ := simtypes.RandomAcc(r, accs)
|
||||
|
||||
// disallow sending money to yourself
|
||||
for simAccount.PubKey.Equals(toSimAcc.PubKey) {
|
||||
toSimAcc, _ = simtypes.RandomAcc(r, accs)
|
||||
for from.PubKey.Equals(to.PubKey) {
|
||||
to, _ = simtypes.RandomAcc(r, accs)
|
||||
}
|
||||
|
||||
acc := ak.GetAccount(ctx, simAccount.Address)
|
||||
acc := ak.GetAccount(ctx, from.Address)
|
||||
if acc == nil {
|
||||
return simAccount, toSimAcc, nil, true
|
||||
return from, to, nil, true
|
||||
}
|
||||
|
||||
spendable := bk.SpendableCoins(ctx, acc.GetAddress())
|
||||
|
||||
sendCoins := simtypes.RandSubsetCoins(r, spendable)
|
||||
if sendCoins.Empty() {
|
||||
return simAccount, toSimAcc, nil, true
|
||||
return from, to, nil, true
|
||||
}
|
||||
|
||||
return simAccount, toSimAcc, sendCoins, false
|
||||
return from, to, sendCoins, false
|
||||
}
|
||||
|
||||
func getModuleAccounts(ak types.AccountKeeper, ctx sdk.Context, moduleAccCount int) []simtypes.Account {
|
||||
|
||||
moduleAccounts := make([]simtypes.Account, moduleAccCount)
|
||||
|
||||
for i := 0; i < moduleAccCount; i++ {
|
||||
addr := ak.GetModuleAddress(distributiontypes.ModuleName)
|
||||
acc := ak.GetAccount(ctx, addr)
|
||||
mAcc := simtypes.Account{
|
||||
Address: acc.GetAddress(),
|
||||
PrivKey: nil,
|
||||
ConsKey: nil,
|
||||
PubKey: acc.GetPubKey(),
|
||||
}
|
||||
moduleAccounts[i] = mAcc
|
||||
}
|
||||
|
||||
return moduleAccounts
|
||||
}
|
||||
|
|
|
@ -104,18 +104,80 @@ func (suite *SimTestSuite) TestSimulateMsgMultiSend() {
|
|||
// execute operation
|
||||
op := simulation.SimulateMsgMultiSend(suite.app.AccountKeeper, suite.app.BankKeeper)
|
||||
operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "")
|
||||
suite.Require().NoError(err)
|
||||
require := suite.Require()
|
||||
require.NoError(err)
|
||||
|
||||
var msg types.MsgMultiSend
|
||||
types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)
|
||||
|
||||
suite.Require().True(operationMsg.OK)
|
||||
suite.Require().Len(msg.Inputs, 3)
|
||||
suite.Require().Equal("cosmos1p8wcgrjr4pjju90xg6u9cgq55dxwq8j7u4x9a0", msg.Inputs[1].Address)
|
||||
suite.Require().Equal("185121068stake", msg.Inputs[1].Coins.String())
|
||||
suite.Require().Len(msg.Outputs, 2)
|
||||
suite.Require().Equal("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r", msg.Outputs[1].Address)
|
||||
suite.Require().Equal("260469617stake", msg.Outputs[1].Coins.String())
|
||||
require.True(operationMsg.OK)
|
||||
require.Len(msg.Inputs, 3)
|
||||
require.Equal("cosmos1p8wcgrjr4pjju90xg6u9cgq55dxwq8j7u4x9a0", msg.Inputs[1].Address)
|
||||
require.Equal("185121068stake", msg.Inputs[1].Coins.String())
|
||||
require.Len(msg.Outputs, 2)
|
||||
require.Equal("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r", msg.Outputs[1].Address)
|
||||
require.Equal("260469617stake", msg.Outputs[1].Coins.String())
|
||||
require.Equal(types.TypeMsgMultiSend, msg.Type())
|
||||
require.Equal(types.ModuleName, msg.Route())
|
||||
require.Len(futureOperations, 0)
|
||||
}
|
||||
|
||||
func (suite *SimTestSuite) TestSimulateModuleAccountMsgSend() {
|
||||
const (
|
||||
accCount = 1
|
||||
moduleAccCount = 1
|
||||
)
|
||||
|
||||
s := rand.NewSource(1)
|
||||
r := rand.New(s)
|
||||
accounts := suite.getTestingAccounts(r, accCount)
|
||||
|
||||
// begin a new block
|
||||
suite.app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: suite.app.LastBlockHeight() + 1, AppHash: suite.app.LastCommitID().Hash}})
|
||||
|
||||
// execute operation
|
||||
op := simulation.SimulateMsgSendToModuleAccount(suite.app.AccountKeeper, suite.app.BankKeeper, moduleAccCount)
|
||||
|
||||
s = rand.NewSource(1)
|
||||
r = rand.New(s)
|
||||
|
||||
operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "")
|
||||
suite.Require().Error(err)
|
||||
|
||||
var msg types.MsgSend
|
||||
types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)
|
||||
|
||||
suite.Require().False(operationMsg.OK)
|
||||
suite.Require().Equal(operationMsg.Comment, "invalid transfers")
|
||||
suite.Require().Equal(types.TypeMsgSend, msg.Type())
|
||||
suite.Require().Equal(types.ModuleName, msg.Route())
|
||||
suite.Require().Len(futureOperations, 0)
|
||||
}
|
||||
|
||||
func (suite *SimTestSuite) TestSimulateMsgMultiSendToModuleAccount() {
|
||||
const (
|
||||
accCount = 2
|
||||
mAccCount = 2
|
||||
)
|
||||
|
||||
s := rand.NewSource(1)
|
||||
r := rand.New(s)
|
||||
accounts := suite.getTestingAccounts(r, accCount)
|
||||
|
||||
// begin a new block
|
||||
suite.app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: suite.app.LastBlockHeight() + 1, AppHash: suite.app.LastCommitID().Hash}})
|
||||
|
||||
// execute operation
|
||||
op := simulation.SimulateMsgMultiSendToModuleAccount(suite.app.AccountKeeper, suite.app.BankKeeper, mAccCount)
|
||||
|
||||
operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "")
|
||||
suite.Require().Error(err)
|
||||
|
||||
var msg types.MsgMultiSend
|
||||
types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)
|
||||
|
||||
suite.Require().False(operationMsg.OK) // sending tokens to a module account should fail
|
||||
suite.Require().Equal(operationMsg.Comment, "invalid transfers")
|
||||
suite.Require().Equal(types.TypeMsgMultiSend, msg.Type())
|
||||
suite.Require().Equal(types.ModuleName, msg.Route())
|
||||
suite.Require().Len(futureOperations, 0)
|
||||
|
|
Loading…
Reference in New Issue