github.com/cosmos/cosmos-sdk@v0.50.10/x/gov/keeper/common_test.go (about)

     1  package keeper_test
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
     8  	cmttime "github.com/cometbft/cometbft/types/time"
     9  	"github.com/golang/mock/gomock"
    10  	"github.com/stretchr/testify/require"
    11  
    12  	"cosmossdk.io/math"
    13  	storetypes "cosmossdk.io/store/types"
    14  
    15  	"github.com/cosmos/cosmos-sdk/baseapp"
    16  	"github.com/cosmos/cosmos-sdk/codec/address"
    17  	"github.com/cosmos/cosmos-sdk/runtime"
    18  	"github.com/cosmos/cosmos-sdk/testutil"
    19  	"github.com/cosmos/cosmos-sdk/testutil/testdata"
    20  	sdk "github.com/cosmos/cosmos-sdk/types"
    21  	moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
    22  	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
    23  	banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
    24  	disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
    25  	"github.com/cosmos/cosmos-sdk/x/gov/keeper"
    26  	govtestutil "github.com/cosmos/cosmos-sdk/x/gov/testutil"
    27  	"github.com/cosmos/cosmos-sdk/x/gov/types"
    28  	v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
    29  	"github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
    30  	minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
    31  )
    32  
    33  var (
    34  	_, _, addr   = testdata.KeyTestPubAddr()
    35  	govAcct      = authtypes.NewModuleAddress(types.ModuleName)
    36  	distAcct     = authtypes.NewModuleAddress(disttypes.ModuleName)
    37  	TestProposal = getTestProposal()
    38  )
    39  
    40  // getTestProposal creates and returns a test proposal message.
    41  func getTestProposal() []sdk.Msg {
    42  	legacyProposalMsg, err := v1.NewLegacyContent(v1beta1.NewTextProposal("Title", "description"), authtypes.NewModuleAddress(types.ModuleName).String())
    43  	if err != nil {
    44  		panic(err)
    45  	}
    46  
    47  	return []sdk.Msg{
    48  		banktypes.NewMsgSend(govAcct, addr, sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(1000)))),
    49  		legacyProposalMsg,
    50  	}
    51  }
    52  
    53  // setupGovKeeper creates a govKeeper as well as all its dependencies.
    54  func setupGovKeeper(t *testing.T) (
    55  	*keeper.Keeper,
    56  	*govtestutil.MockAccountKeeper,
    57  	*govtestutil.MockBankKeeper,
    58  	*govtestutil.MockStakingKeeper,
    59  	*govtestutil.MockDistributionKeeper,
    60  	moduletestutil.TestEncodingConfig,
    61  	sdk.Context,
    62  ) {
    63  	key := storetypes.NewKVStoreKey(types.StoreKey)
    64  	storeService := runtime.NewKVStoreService(key)
    65  	testCtx := testutil.DefaultContextWithDB(t, key, storetypes.NewTransientStoreKey("transient_test"))
    66  	ctx := testCtx.Ctx.WithBlockHeader(cmtproto.Header{Time: cmttime.Now()})
    67  	encCfg := moduletestutil.MakeTestEncodingConfig()
    68  	v1.RegisterInterfaces(encCfg.InterfaceRegistry)
    69  	v1beta1.RegisterInterfaces(encCfg.InterfaceRegistry)
    70  	banktypes.RegisterInterfaces(encCfg.InterfaceRegistry)
    71  
    72  	// Create MsgServiceRouter, but don't populate it before creating the gov
    73  	// keeper.
    74  	msr := baseapp.NewMsgServiceRouter()
    75  
    76  	// gomock initializations
    77  	ctrl := gomock.NewController(t)
    78  	acctKeeper := govtestutil.NewMockAccountKeeper(ctrl)
    79  	bankKeeper := govtestutil.NewMockBankKeeper(ctrl)
    80  	stakingKeeper := govtestutil.NewMockStakingKeeper(ctrl)
    81  	distributionKeeper := govtestutil.NewMockDistributionKeeper(ctrl)
    82  
    83  	acctKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(govAcct).AnyTimes()
    84  	acctKeeper.EXPECT().GetModuleAddress(disttypes.ModuleName).Return(distAcct).AnyTimes()
    85  	acctKeeper.EXPECT().GetModuleAccount(gomock.Any(), types.ModuleName).Return(authtypes.NewEmptyModuleAccount(types.ModuleName)).AnyTimes()
    86  	acctKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec("cosmos")).AnyTimes()
    87  
    88  	trackMockBalances(bankKeeper, distributionKeeper)
    89  	stakingKeeper.EXPECT().TokensFromConsensusPower(ctx, gomock.Any()).DoAndReturn(func(ctx sdk.Context, power int64) math.Int {
    90  		return sdk.TokensFromConsensusPower(power, math.NewIntFromUint64(1000000))
    91  	}).AnyTimes()
    92  
    93  	stakingKeeper.EXPECT().BondDenom(ctx).Return("stake", nil).AnyTimes()
    94  	stakingKeeper.EXPECT().IterateBondedValidatorsByPower(gomock.Any(), gomock.Any()).AnyTimes()
    95  	stakingKeeper.EXPECT().IterateDelegations(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
    96  	stakingKeeper.EXPECT().TotalBondedTokens(gomock.Any()).Return(math.NewInt(10000000), nil).AnyTimes()
    97  	distributionKeeper.EXPECT().FundCommunityPool(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
    98  
    99  	// Gov keeper initializations
   100  
   101  	govKeeper := keeper.NewKeeper(encCfg.Codec, storeService, acctKeeper, bankKeeper, stakingKeeper, distributionKeeper, msr, types.DefaultConfig(), govAcct.String())
   102  	require.NoError(t, govKeeper.ProposalID.Set(ctx, 1))
   103  	govRouter := v1beta1.NewRouter() // Also register legacy gov handlers to test them too.
   104  	govRouter.AddRoute(types.RouterKey, v1beta1.ProposalHandler)
   105  	govKeeper.SetLegacyRouter(govRouter)
   106  	err := govKeeper.Params.Set(ctx, v1.DefaultParams())
   107  	require.NoError(t, err)
   108  	err = govKeeper.Constitution.Set(ctx, "constitution")
   109  	require.NoError(t, err)
   110  
   111  	// Register all handlers for the MegServiceRouter.
   112  	msr.SetInterfaceRegistry(encCfg.InterfaceRegistry)
   113  	v1.RegisterMsgServer(msr, keeper.NewMsgServerImpl(govKeeper))
   114  	banktypes.RegisterMsgServer(msr, nil) // Nil is fine here as long as we never execute the proposal's Msgs.
   115  
   116  	return govKeeper, acctKeeper, bankKeeper, stakingKeeper, distributionKeeper, encCfg, ctx
   117  }
   118  
   119  // trackMockBalances sets up expected calls on the Mock BankKeeper, and also
   120  // locally tracks accounts balances (not modules balances).
   121  func trackMockBalances(bankKeeper *govtestutil.MockBankKeeper, distributionKeeper *govtestutil.MockDistributionKeeper) {
   122  	balances := make(map[string]sdk.Coins)
   123  	balances[distAcct.String()] = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(0)))
   124  
   125  	// We don't track module account balances.
   126  	bankKeeper.EXPECT().MintCoins(gomock.Any(), minttypes.ModuleName, gomock.Any()).AnyTimes()
   127  	bankKeeper.EXPECT().BurnCoins(gomock.Any(), types.ModuleName, gomock.Any()).AnyTimes()
   128  	bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), minttypes.ModuleName, types.ModuleName, gomock.Any()).AnyTimes()
   129  
   130  	// But we do track normal account balances.
   131  	bankKeeper.EXPECT().SendCoinsFromAccountToModule(gomock.Any(), gomock.Any(), types.ModuleName, gomock.Any()).DoAndReturn(func(_ sdk.Context, sender sdk.AccAddress, _ string, coins sdk.Coins) error {
   132  		newBalance, negative := balances[sender.String()].SafeSub(coins...)
   133  		if negative {
   134  			return fmt.Errorf("not enough balance")
   135  		}
   136  		balances[sender.String()] = newBalance
   137  		return nil
   138  	}).AnyTimes()
   139  	bankKeeper.EXPECT().SendCoinsFromModuleToAccount(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(_ sdk.Context, module string, rcpt sdk.AccAddress, coins sdk.Coins) error {
   140  		balances[rcpt.String()] = balances[rcpt.String()].Add(coins...)
   141  		return nil
   142  	}).AnyTimes()
   143  	bankKeeper.EXPECT().GetAllBalances(gomock.Any(), gomock.Any()).DoAndReturn(func(_ sdk.Context, addr sdk.AccAddress) sdk.Coins {
   144  		return balances[addr.String()]
   145  	}).AnyTimes()
   146  	bankKeeper.EXPECT().GetBalance(gomock.Any(), gomock.Any(), sdk.DefaultBondDenom).DoAndReturn(func(_ sdk.Context, addr sdk.AccAddress, _ string) sdk.Coin {
   147  		balances := balances[addr.String()]
   148  		for _, balance := range balances {
   149  			if balance.Denom == sdk.DefaultBondDenom {
   150  				return balance
   151  			}
   152  		}
   153  		return sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(0))
   154  	}).AnyTimes()
   155  
   156  	distributionKeeper.EXPECT().FundCommunityPool(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(_ sdk.Context, coins sdk.Coins, sender sdk.AccAddress) error {
   157  		// sender balance
   158  		newBalance, negative := balances[sender.String()].SafeSub(coins...)
   159  		if negative {
   160  			return fmt.Errorf("not enough balance")
   161  		}
   162  		balances[sender.String()] = newBalance
   163  		// receiver balance
   164  		balances[distAcct.String()] = balances[distAcct.String()].Add(coins...)
   165  		return nil
   166  	}).AnyTimes()
   167  }