feat: Move CommunityPool to its own module (#17657)
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
package simulation
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
|
||||
"cosmossdk.io/x/protocolpool/keeper"
|
||||
"cosmossdk.io/x/protocolpool/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||
"github.com/cosmos/cosmos-sdk/x/simulation"
|
||||
)
|
||||
|
||||
// Simulation operation weights constants
|
||||
const (
|
||||
OpWeightMsgFundCommunityPool = "op_weight_msg_fund_community_pool"
|
||||
|
||||
DefaultWeightMsgFundCommunityPool int = 50
|
||||
)
|
||||
|
||||
// WeightedOperations returns all the operations from the module with their respective weights
|
||||
func WeightedOperations(
|
||||
appParams simtypes.AppParams,
|
||||
cdc codec.JSONCodec,
|
||||
txConfig client.TxConfig,
|
||||
ak types.AccountKeeper,
|
||||
bk types.BankKeeper,
|
||||
k keeper.Keeper,
|
||||
) simulation.WeightedOperations {
|
||||
var weightMsgFundCommunityPool int
|
||||
appParams.GetOrGenerate(OpWeightMsgFundCommunityPool, &weightMsgFundCommunityPool, nil, func(_ *rand.Rand) {
|
||||
weightMsgFundCommunityPool = DefaultWeightMsgFundCommunityPool
|
||||
})
|
||||
|
||||
return simulation.WeightedOperations{
|
||||
simulation.NewWeightedOperation(
|
||||
weightMsgFundCommunityPool,
|
||||
SimulateMsgFundCommunityPool(txConfig, ak, bk, k),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// SimulateMsgFundCommunityPool simulates MsgFundCommunityPool execution where
|
||||
// a random account sends a random amount of its funds to the community pool.
|
||||
func SimulateMsgFundCommunityPool(txConfig client.TxConfig, ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation {
|
||||
return func(
|
||||
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
|
||||
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
||||
funder, _ := simtypes.RandomAcc(r, accs)
|
||||
|
||||
account := ak.GetAccount(ctx, funder.Address)
|
||||
spendable := bk.SpendableCoins(ctx, account.GetAddress())
|
||||
|
||||
fundAmount := simtypes.RandSubsetCoins(r, spendable)
|
||||
if fundAmount.Empty() {
|
||||
return simtypes.NoOpMsg(types.ModuleName, sdk.MsgTypeURL(&types.MsgFundCommunityPool{}), "fund amount is empty"), nil, nil
|
||||
}
|
||||
|
||||
var (
|
||||
fees sdk.Coins
|
||||
err error
|
||||
)
|
||||
|
||||
coins, hasNeg := spendable.SafeSub(fundAmount...)
|
||||
if !hasNeg {
|
||||
fees, err = simtypes.RandomFees(r, coins)
|
||||
if err != nil {
|
||||
return simtypes.NoOpMsg(types.ModuleName, sdk.MsgTypeURL(&types.MsgFundCommunityPool{}), "unable to generate fees"), nil, err
|
||||
}
|
||||
}
|
||||
|
||||
msg := types.NewMsgFundCommunityPool(fundAmount, funder.Address.String())
|
||||
|
||||
txCtx := simulation.OperationInput{
|
||||
R: r,
|
||||
App: app,
|
||||
TxGen: txConfig,
|
||||
Cdc: nil,
|
||||
Msg: msg,
|
||||
Context: ctx,
|
||||
SimAccount: funder,
|
||||
AccountKeeper: ak,
|
||||
ModuleName: types.ModuleName,
|
||||
}
|
||||
|
||||
return simulation.GenAndDeliverTx(txCtx, fees)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
package simulation_test
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
abci "github.com/cometbft/cometbft/abci/types"
|
||||
"github.com/cosmos/gogoproto/proto"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"cosmossdk.io/depinject"
|
||||
"cosmossdk.io/log"
|
||||
"cosmossdk.io/x/protocolpool/keeper"
|
||||
"cosmossdk.io/x/protocolpool/simulation"
|
||||
pooltestutil "cosmossdk.io/x/protocolpool/testutil"
|
||||
"cosmossdk.io/x/protocolpool/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/runtime"
|
||||
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
||||
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
|
||||
banktestutil "github.com/cosmos/cosmos-sdk/x/bank/testutil"
|
||||
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
|
||||
)
|
||||
|
||||
type suite struct {
|
||||
Ctx sdk.Context
|
||||
App *runtime.App
|
||||
|
||||
TxConfig client.TxConfig
|
||||
Cdc codec.Codec
|
||||
AccountKeeper authkeeper.AccountKeeper
|
||||
BankKeeper bankkeeper.Keeper
|
||||
StakingKeeper *stakingkeeper.Keeper
|
||||
PoolKeeper keeper.Keeper
|
||||
}
|
||||
|
||||
func setUpTest(t *testing.T) suite {
|
||||
t.Helper()
|
||||
res := suite{}
|
||||
|
||||
var (
|
||||
appBuilder *runtime.AppBuilder
|
||||
err error
|
||||
)
|
||||
|
||||
app, err := simtestutil.Setup(
|
||||
depinject.Configs(
|
||||
pooltestutil.AppConfig,
|
||||
depinject.Supply(log.NewNopLogger()),
|
||||
),
|
||||
&res.AccountKeeper,
|
||||
&res.BankKeeper,
|
||||
&res.Cdc,
|
||||
&appBuilder,
|
||||
&res.StakingKeeper,
|
||||
&res.PoolKeeper,
|
||||
&res.TxConfig,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
res.App = app
|
||||
res.Ctx = app.BaseApp.NewContext(false)
|
||||
return res
|
||||
}
|
||||
|
||||
// TestWeightedOperations tests the weights of the operations.
|
||||
func TestWeightedOperations(t *testing.T) {
|
||||
suite := setUpTest(t)
|
||||
|
||||
appParams := make(simtypes.AppParams)
|
||||
|
||||
weightedOps := simulation.WeightedOperations(appParams, suite.Cdc, suite.TxConfig, suite.AccountKeeper,
|
||||
suite.BankKeeper, suite.PoolKeeper)
|
||||
|
||||
// setup 3 accounts
|
||||
s := rand.NewSource(1)
|
||||
r := rand.New(s)
|
||||
accs := getTestingAccounts(t, r, suite.AccountKeeper, suite.BankKeeper, suite.StakingKeeper, suite.Ctx, 3)
|
||||
|
||||
expected := []struct {
|
||||
weight int
|
||||
opMsgRoute string
|
||||
opMsgName string
|
||||
}{
|
||||
{simulation.DefaultWeightMsgFundCommunityPool, types.ModuleName, sdk.MsgTypeURL(&types.MsgFundCommunityPool{})},
|
||||
}
|
||||
|
||||
for i, w := range weightedOps {
|
||||
operationMsg, _, err := w.Op()(r, suite.App.BaseApp, suite.Ctx, accs, "")
|
||||
require.NoError(t, 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
|
||||
require.Equal(t, expected[i].weight, w.Weight(), "weight should be the same")
|
||||
require.Equal(t, expected[i].opMsgRoute, operationMsg.Route, "route should be the same")
|
||||
require.Equal(t, expected[i].opMsgName, operationMsg.Name, "operation Msg name should be the same")
|
||||
}
|
||||
}
|
||||
|
||||
// TestSimulateMsgFundCommunityPool tests the normal scenario of a valid message of type TypeMsgFundCommunityPool.
|
||||
// Abonormal scenarios, where the message is created by an errors, are not tested here.
|
||||
func TestSimulateMsgFundCommunityPool(t *testing.T) {
|
||||
suite := setUpTest(t)
|
||||
|
||||
// setup 3 accounts
|
||||
s := rand.NewSource(1)
|
||||
r := rand.New(s)
|
||||
accounts := getTestingAccounts(t, r, suite.AccountKeeper, suite.BankKeeper, suite.StakingKeeper, suite.Ctx, 3)
|
||||
|
||||
_, err := suite.App.FinalizeBlock(&abci.RequestFinalizeBlock{
|
||||
Height: suite.App.LastBlockHeight() + 1,
|
||||
Hash: suite.App.LastCommitID().Hash,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// execute operation
|
||||
op := simulation.SimulateMsgFundCommunityPool(suite.TxConfig, suite.AccountKeeper, suite.BankKeeper, suite.PoolKeeper)
|
||||
operationMsg, futureOperations, err := op(r, suite.App.BaseApp, suite.Ctx, accounts, "")
|
||||
require.NoError(t, err)
|
||||
|
||||
var msg types.MsgFundCommunityPool
|
||||
err = proto.Unmarshal(operationMsg.Msg, &msg)
|
||||
require.NoError(t, err)
|
||||
require.True(t, operationMsg.OK)
|
||||
require.Equal(t, "4896096stake", msg.Amount.String())
|
||||
require.Equal(t, "cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r", msg.Depositor)
|
||||
require.Equal(t, sdk.MsgTypeURL(&types.MsgFundCommunityPool{}), sdk.MsgTypeURL(&msg))
|
||||
require.Len(t, futureOperations, 0)
|
||||
}
|
||||
|
||||
func getTestingAccounts(
|
||||
t *testing.T, r *rand.Rand,
|
||||
accountKeeper authkeeper.AccountKeeper, bankKeeper bankkeeper.Keeper,
|
||||
stakingKeeper *stakingkeeper.Keeper, ctx sdk.Context, n int,
|
||||
) []simtypes.Account {
|
||||
t.Helper()
|
||||
accounts := simtypes.RandomAccounts(r, n)
|
||||
|
||||
initAmt := stakingKeeper.TokensFromConsensusPower(ctx, 200)
|
||||
initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt))
|
||||
|
||||
// add coins to the accounts
|
||||
for _, account := range accounts {
|
||||
acc := accountKeeper.NewAccountWithAddress(ctx, account.Address)
|
||||
accountKeeper.SetAccount(ctx, acc)
|
||||
require.NoError(t, banktestutil.FundAccount(ctx, bankKeeper, account.Address, initCoins))
|
||||
}
|
||||
|
||||
return accounts
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package simulation
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
|
||||
pooltypes "cosmossdk.io/x/protocolpool/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/address"
|
||||
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||
"github.com/cosmos/cosmos-sdk/x/simulation"
|
||||
)
|
||||
|
||||
const (
|
||||
OpWeightMsgCommunityPoolSpend = "op_weight_msg_community_pool_spend"
|
||||
|
||||
DefaultWeightMsgCommunityPoolSpend int = 50
|
||||
)
|
||||
|
||||
func ProposalMsgs() []simtypes.WeightedProposalMsg {
|
||||
return []simtypes.WeightedProposalMsg{
|
||||
simulation.NewWeightedProposalMsg(
|
||||
OpWeightMsgCommunityPoolSpend,
|
||||
DefaultWeightMsgCommunityPoolSpend,
|
||||
SimulateMsgCommunityPoolSpend,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func SimulateMsgCommunityPoolSpend(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) sdk.Msg {
|
||||
// use the default gov module account address as authority
|
||||
var authority sdk.AccAddress = address.Module("gov")
|
||||
|
||||
accs := simtypes.RandomAccounts(r, 5)
|
||||
acc, _ := simtypes.RandomAcc(r, accs)
|
||||
|
||||
coins, err := sdk.ParseCoinsNormalized("100stake,2testtoken")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return &pooltypes.MsgCommunityPoolSpend{
|
||||
Authority: authority.String(),
|
||||
Recipient: acc.Address.String(),
|
||||
Amount: coins,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package simulation_test
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
|
||||
"cosmossdk.io/x/protocolpool/simulation"
|
||||
pooltypes "cosmossdk.io/x/protocolpool/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/address"
|
||||
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||
)
|
||||
|
||||
func TestProposalMsgs(t *testing.T) {
|
||||
// initialize parameters
|
||||
s := rand.NewSource(1)
|
||||
r := rand.New(s)
|
||||
|
||||
ctx := sdk.NewContext(nil, true, nil)
|
||||
accounts := simtypes.RandomAccounts(r, 3)
|
||||
|
||||
// execute ProposalMsgs function
|
||||
weightedProposalMsgs := simulation.ProposalMsgs()
|
||||
assert.Assert(t, len(weightedProposalMsgs) == 1)
|
||||
|
||||
w0 := weightedProposalMsgs[0]
|
||||
|
||||
// tests w0 interface:
|
||||
assert.Equal(t, simulation.OpWeightMsgCommunityPoolSpend, w0.AppParamsKey())
|
||||
assert.Equal(t, simulation.DefaultWeightMsgCommunityPoolSpend, w0.DefaultWeight())
|
||||
|
||||
msg := w0.MsgSimulatorFn()(r, ctx, accounts)
|
||||
msgCommunityPoolSpend, ok := msg.(*pooltypes.MsgCommunityPoolSpend)
|
||||
assert.Assert(t, ok)
|
||||
|
||||
coins, err := sdk.ParseCoinsNormalized("100stake,2testtoken")
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Equal(t, sdk.AccAddress(address.Module("gov")).String(), msgCommunityPoolSpend.Authority)
|
||||
assert.Assert(t, msgCommunityPoolSpend.Amount.Equal(coins))
|
||||
}
|
||||
Reference in New Issue
Block a user