github.com/Finschia/finschia-sdk@v0.48.1/x/gov/simulation/operations_test.go (about)

     1  package simulation_test
     2  
     3  import (
     4  	"fmt"
     5  	"math/rand"
     6  	"testing"
     7  	"time"
     8  
     9  	ocabci "github.com/Finschia/ostracon/abci/types"
    10  	"github.com/stretchr/testify/require"
    11  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
    12  
    13  	"github.com/Finschia/finschia-sdk/simapp"
    14  	simappparams "github.com/Finschia/finschia-sdk/simapp/params"
    15  	sdk "github.com/Finschia/finschia-sdk/types"
    16  	simtypes "github.com/Finschia/finschia-sdk/types/simulation"
    17  	govcodec "github.com/Finschia/finschia-sdk/x/gov/codec"
    18  	"github.com/Finschia/finschia-sdk/x/gov/simulation"
    19  	"github.com/Finschia/finschia-sdk/x/gov/types"
    20  	minttypes "github.com/Finschia/finschia-sdk/x/mint/types"
    21  )
    22  
    23  type MockWeightedProposalContent struct {
    24  	n int
    25  }
    26  
    27  func (m MockWeightedProposalContent) AppParamsKey() string {
    28  	return fmt.Sprintf("AppParamsKey-%d", m.n)
    29  }
    30  
    31  func (m MockWeightedProposalContent) DefaultWeight() int {
    32  	return m.n
    33  }
    34  
    35  func (m MockWeightedProposalContent) ContentSimulatorFn() simtypes.ContentSimulatorFn {
    36  	return func(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) simtypes.Content {
    37  		return types.NewTextProposal(
    38  			fmt.Sprintf("title-%d: %s", m.n, simtypes.RandStringOfLength(r, 100)),
    39  			fmt.Sprintf("description-%d: %s", m.n, simtypes.RandStringOfLength(r, 4000)),
    40  		)
    41  	}
    42  }
    43  
    44  // make sure the MockWeightedProposalContent satisfied the WeightedProposalContent interface
    45  var _ simtypes.WeightedProposalContent = MockWeightedProposalContent{}
    46  
    47  func mockWeightedProposalContent(n int) []simtypes.WeightedProposalContent {
    48  	wpc := make([]simtypes.WeightedProposalContent, n)
    49  	for i := 0; i < n; i++ {
    50  		wpc[i] = MockWeightedProposalContent{i}
    51  	}
    52  	return wpc
    53  }
    54  
    55  // TestWeightedOperations tests the weights of the operations.
    56  func TestWeightedOperations(t *testing.T) {
    57  	app, ctx := createTestApp(false)
    58  	ctx.WithChainID("test-chain")
    59  
    60  	cdc := app.AppCodec()
    61  	appParams := make(simtypes.AppParams)
    62  
    63  	weightesOps := simulation.WeightedOperations(appParams, cdc, app.AccountKeeper,
    64  		app.BankKeeper, app.GovKeeper, mockWeightedProposalContent(3),
    65  	)
    66  
    67  	// setup 3 accounts
    68  	s := rand.NewSource(1)
    69  	r := rand.New(s)
    70  	accs := getTestingAccounts(t, r, app, ctx, 3)
    71  
    72  	expected := []struct {
    73  		weight     int
    74  		opMsgRoute string
    75  		opMsgName  string
    76  	}{
    77  		{0, types.ModuleName, "submit_proposal"},
    78  		{1, types.ModuleName, "submit_proposal"},
    79  		{2, types.ModuleName, "submit_proposal"},
    80  		{simappparams.DefaultWeightMsgDeposit, types.ModuleName, types.TypeMsgDeposit},
    81  		{simappparams.DefaultWeightMsgVote, types.ModuleName, types.TypeMsgVote},
    82  		{simappparams.DefaultWeightMsgVoteWeighted, types.ModuleName, types.TypeMsgVoteWeighted},
    83  	}
    84  
    85  	for i, w := range weightesOps {
    86  		operationMsg, _, _ := w.Op()(r, app.BaseApp, ctx, accs, ctx.ChainID())
    87  		// the following checks are very much dependent from the ordering of the output given
    88  		// by WeightedOperations. if the ordering in WeightedOperations changes some tests
    89  		// will fail
    90  		require.Equal(t, expected[i].weight, w.Weight(), "weight should be the same")
    91  		require.Equal(t, expected[i].opMsgRoute, operationMsg.Route, "route should be the same")
    92  		require.Equal(t, expected[i].opMsgName, operationMsg.Name, "operation Msg name should be the same")
    93  	}
    94  }
    95  
    96  // TestSimulateMsgSubmitProposal tests the normal scenario of a valid message of type TypeMsgSubmitProposal.
    97  // Abonormal scenarios, where the message is created by an errors are not tested here.
    98  func TestSimulateMsgSubmitProposal(t *testing.T) {
    99  	app, ctx := createTestApp(false)
   100  
   101  	// setup 3 accounts
   102  	s := rand.NewSource(1)
   103  	r := rand.New(s)
   104  	accounts := getTestingAccounts(t, r, app, ctx, 3)
   105  
   106  	// begin a new block
   107  	app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash}})
   108  
   109  	// execute operation
   110  	op := simulation.SimulateMsgSubmitProposal(app.AccountKeeper, app.BankKeeper, app.GovKeeper, MockWeightedProposalContent{3}.ContentSimulatorFn())
   111  	operationMsg, _, err := op(r, app.BaseApp, ctx, accounts, "")
   112  	require.NoError(t, err)
   113  
   114  	var msg types.MsgSubmitProposal
   115  	err = govcodec.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)
   116  	require.NoError(t, err)
   117  
   118  	require.True(t, operationMsg.OK)
   119  	require.Equal(t, "link1p8wcgrjr4pjju90xg6u9cgq55dxwq8j7fmx8x8", msg.Proposer)
   120  	require.Equal(t, "2686011stake", msg.InitialDeposit.String())
   121  	require.Equal(t, "title-3: ZBSpYuLyYggwexjxusrBqDOTtGTOWeLrQKjLxzIivHSlcxgdXhhuTSkuxKGLwQvuyNhYFmBZHeAerqyNEUzXPFGkqEGqiQWIXnku", msg.GetContent().GetTitle())
   122  	require.Equal(t, "description-3: NJWzHdBNpAXKJPHWQdrGYcAHSctgVlqwqHoLfHsXUdStwfefwzqLuKEhmMyYLdbZrcPgYqjNHxPexsruwEGStAneKbWkQDDIlCWBLSiAASNhZqNFlPtfqPJoxKsgMdzjWqLWdqKQuJqWPMvwPQWZUtVMOTMYKJbfdlZsjdsomuScvDmbDkgRualsxDvRJuCAmPOXitIbcyWsKGSdrEunFAOdmXnsuyFVgJqEjbklvmwrUlsxjRSfKZxGcpayDdgoFcnVSutxjRgOSFzPwidAjubMncNweqpbxhXGchpZUxuFDOtpnhNUycJICRYqsPhPSCjPTWZFLkstHWJxvdPEAyEIxXgLwbNOjrgzmaujiBABBIXvcXpLrbcEWNNQsbjvgJFgJkflpRohHUutvnaUqoopuKjTDaemDeSdqbnOzcfJpcTuAQtZoiLZOoAIlboFDAeGmSNwkvObPRvRWQgWkGkxwtPauYgdkmypLjbqhlHJIQTntgWjXwZdOyYEdQRRLfMSdnxqppqUofqLbLQDUjwKVKfZJUJQPsWIPwIVaSTrmKskoAhvmZyJgeRpkaTfGgrJzAigcxtfshmiDCFkuiluqtMOkidknnTBtumyJYlIsWLnCQclqdVmikUoMOPdPWwYbJxXyqUVicNxFxyqJTenNblyyKSdlCbiXxUiYUiMwXZASYfvMDPFgxniSjWaZTjHkqlJvtBsXqwPpyVxnJVGFWhfSxgOcduoxkiopJvFjMmFabrGYeVtTXLhxVUEiGwYUvndjFGzDVntUvibiyZhfMQdMhgsiuysLMiePBNXifRLMsSmXPkwlPloUbJveCvUlaalhZHuvdkCnkSHbMbmOnrfEGPwQiACiPlnihiaOdbjPqPiTXaHDoJXjSlZmltGqNHHNrcKdlFSCdmVOuvDcBLdSklyGJmcLTbSFtALdGlPkqqecJrpLCXNPWefoTJNgEJlyMEPneVaxxduAAEqQpHWZodWyRkDAxzyMnFMcjSVqeRXLqsNyNtQBbuRvunZflWSbbvXXdkyLikYqutQhLPONXbvhcQZJPSWnOulqQaXmbfFxAkqfYeseSHOQidHwbcsOaMnSrrmGjjRmEMQNuknupMxJiIeVjmgZvbmjPIQTEhQFULQLBMPrxcFPvBinaOPYWGvYGRKxLZdwamfRQQFngcdSlvwjfaPbURasIsGJVHtcEAxnIIrhSriiXLOlbEBLXFElXJFGxHJczRBIxAuPKtBisjKBwfzZFagdNmjdwIRvwzLkFKWRTDPxJCmpzHUcrPiiXXHnOIlqNVoGSXZewdnCRhuxeYGPVTfrNTQNOxZmxInOazUYNTNDgzsxlgiVEHPKMfbesvPHUqpNkUqbzeuzfdrsuLDpKHMUbBMKczKKWOdYoIXoPYtEjfOnlQLoGnbQUCuERdEFaptwnsHzTJDsuZkKtzMpFaZobynZdzNydEeJJHDYaQcwUxcqvwfWwNUsCiLvkZQiSfzAHftYgAmVsXgtmcYgTqJIawstRYJrZdSxlfRiqTufgEQVambeZZmaAyRQbcmdjVUZZCgqDrSeltJGXPMgZnGDZqISrGDOClxXCxMjmKqEPwKHoOfOeyGmqWqihqjINXLqnyTesZePQRqaWDQNqpLgNrAUKulklmckTijUltQKuWQDwpLmDyxLppPVMwsmBIpOwQttYFMjgJQZLYFPmxWFLIeZihkRNnkzoypBICIxgEuYsVWGIGRbbxqVasYnstWomJnHwmtOhAFSpttRYYzBmyEtZXiCthvKvWszTXDbiJbGXMcrYpKAgvUVFtdKUfvdMfhAryctklUCEdjetjuGNfJjajZtvzdYaqInKtFPPLYmRaXPdQzxdSQfmZDEVHlHGEGNSPRFJuIfKLLfUmnHxHnRjmzQPNlqrXgifUdzAGKVabYqvcDeYoTYgPsBUqehrBhmQUgTvDnsdpuhUoxskDdppTsYMcnDIPSwKIqhXDCIxOuXrywahvVavvHkPuaenjLmEbMgrkrQLHEAwrhHkPRNvonNQKqprqOFVZKAtpRSpvQUxMoXCMZLSSbnLEFsjVfANdQNQVwTmGxqVjVqRuxREAhuaDrFgEZpYKhwWPEKBevBfsOIcaZKyykQafzmGPLRAKDtTcJxJVgiiuUkmyMYuDUNEUhBEdoBLJnamtLmMJQgmLiUELIhLpiEvpOXOvXCPUeldLFqkKOwfacqIaRcnnZvERKRMCKUkMABbDHytQqQblrvoxOZkwzosQfDKGtIdfcXRJNqlBNwOCWoQBcEWyqrMlYZIAXYJmLfnjoJepgSFvrgajaBAIksoyeHqgqbGvpAstMIGmIhRYGGNPRIfOQKsGoKgxtsidhTaAePRCBFqZgPDWCIkqOJezGVkjfYUCZTlInbxBXwUAVRsxHTQtJFnnpmMvXDYCVlEmnZBKhmmxQOIQzxFWpJQkQoSAYzTEiDWEOsVLNrbfzeHFRyeYATakQQWmFDLPbVMCJcWjFGJjfqCoVzlbNNEsqxdSmNPjTjHYOkuEMFLkXYGaoJlraLqayMeCsTjWNRDPBywBJLAPVkGQqTwApVVwYAetlwSbzsdHWsTwSIcctkyKDuRWYDQikRqsKTMJchrliONJeaZIzwPQrNbTwxsGdwuduvibtYndRwpdsvyCktRHFalvUuEKMqXbItfGcNGWsGzubdPMYayOUOINjpcFBeESdwpdlTYmrPsLsVDhpTzoMegKrytNVZkfJRPuDCUXxSlSthOohmsuxmIZUedzxKmowKOdXTMcEtdpHaPWgIsIjrViKrQOCONlSuazmLuCUjLltOGXeNgJKedTVrrVCpWYWHyVrdXpKgNaMJVjbXxnVMSChdWKuZdqpisvrkBJPoURDYxWOtpjzZoOpWzyUuYNhCzRoHsMjmmWDcXzQiHIyjwdhPNwiPqFxeUfMVFQGImhykFgMIlQEoZCaRoqSBXTSWAeDumdbsOGtATwEdZlLfoBKiTvodQBGOEcuATWXfiinSjPmJKcWgQrTVYVrwlyMWhxqNbCMpIQNoSMGTiWfPTCezUjYcdWppnsYJihLQCqbNLRGgqrwHuIvsazapTpoPZIyZyeeSueJuTIhpHMEJfJpScshJubJGfkusuVBgfTWQoywSSliQQSfbvaHKiLnyjdSbpMkdBgXepoSsHnCQaYuHQqZsoEOmJCiuQUpJkmfyfbIShzlZpHFmLCsbknEAkKXKfRTRnuwdBeuOGgFbJLbDksHVapaRayWzwoYBEpmrlAxrUxYMUekKbpjPNfjUCjhbdMAnJmYQVZBQZkFVweHDAlaqJjRqoQPoOMLhyvYCzqEuQsAFoxWrzRnTVjStPadhsESlERnKhpEPsfDxNvxqcOyIulaCkmPdambLHvGhTZzysvqFauEgkFRItPfvisehFmoBhQqmkfbHVsgfHXDPJVyhwPllQpuYLRYvGodxKjkarnSNgsXoKEMlaSKxKdcVgvOkuLcfLFfdtXGTclqfPOfeoVLbqcjcXCUEBgAGplrkgsmIEhWRZLlGPGCwKWRaCKMkBHTAcypUrYjWwCLtOPVygMwMANGoQwFnCqFrUGMCRZUGJKTZIGPyldsifauoMnJPLTcDHmilcmahlqOELaAUYDBuzsVywnDQfwRLGIWozYaOAilMBcObErwgTDNGWnwQMUgFFSKtPDMEoEQCTKVREqrXZSGLqwTMcxHfWotDllNkIJPMbXzjDVjPOOjCFuIvTyhXKLyhUScOXvYthRXpPfKwMhptXaxIxgqBoUqzrWbaoLTVpQoottZyPFfNOoMioXHRuFwMRYUiKvcWPkrayyTLOCFJlAyslDameIuqVAuxErqFPEWIScKpBORIuZqoXlZuTvAjEdlEWDODFRregDTqGNoFBIHxvimmIZwLfFyKUfEWAnNBdtdzDmTPXtpHRGdIbuucfTjOygZsTxPjfweXhSUkMhPjMaxKlMIJMOXcnQfyzeOcbWwNbeH", msg.GetContent().GetDescription())
   123  	require.Equal(t, "gov", msg.Route())
   124  	require.Equal(t, types.TypeMsgSubmitProposal, msg.Type())
   125  }
   126  
   127  // TestSimulateMsgDeposit tests the normal scenario of a valid message of type TypeMsgDeposit.
   128  // Abonormal scenarios, where the message is created by an errors are not tested here.
   129  func TestSimulateMsgDeposit(t *testing.T) {
   130  	app, ctx := createTestApp(false)
   131  	blockTime := time.Now().UTC()
   132  	ctx = ctx.WithBlockTime(blockTime)
   133  
   134  	// setup 3 accounts
   135  	s := rand.NewSource(1)
   136  	r := rand.New(s)
   137  	accounts := getTestingAccounts(t, r, app, ctx, 3)
   138  
   139  	// setup a proposal
   140  	content := types.NewTextProposal("Test", "description")
   141  
   142  	submitTime := ctx.BlockHeader().Time
   143  	depositPeriod := app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod
   144  
   145  	proposal, err := types.NewProposal(content, 1, submitTime, submitTime.Add(depositPeriod))
   146  	require.NoError(t, err)
   147  
   148  	app.GovKeeper.SetProposal(ctx, proposal)
   149  
   150  	// begin a new block
   151  	app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash, Time: blockTime}})
   152  
   153  	// execute operation
   154  	op := simulation.SimulateMsgDeposit(app.AccountKeeper, app.BankKeeper, app.GovKeeper)
   155  	operationMsg, _, err := op(r, app.BaseApp, ctx, accounts, "")
   156  	require.NoError(t, err)
   157  
   158  	var msg types.MsgDeposit
   159  	err = govcodec.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)
   160  	require.NoError(t, err)
   161  
   162  	require.True(t, operationMsg.OK)
   163  	require.Equal(t, uint64(1), msg.ProposalId)
   164  	require.Equal(t, "link1ghekyjucln7y67ntx7cf27m9dpuxxemnqk82wt", msg.Depositor)
   165  	require.Equal(t, "560969stake", msg.Amount.String())
   166  	require.Equal(t, "gov", msg.Route())
   167  	require.Equal(t, types.TypeMsgDeposit, msg.Type())
   168  }
   169  
   170  // TestSimulateMsgVote tests the normal scenario of a valid message of type TypeMsgVote.
   171  // Abonormal scenarios, where the message is created by an errors are not tested here.
   172  func TestSimulateMsgVote(t *testing.T) {
   173  	app, ctx := createTestApp(false)
   174  	blockTime := time.Now().UTC()
   175  	ctx = ctx.WithBlockTime(blockTime)
   176  
   177  	// setup 3 accounts
   178  	s := rand.NewSource(1)
   179  	r := rand.New(s)
   180  	accounts := getTestingAccounts(t, r, app, ctx, 3)
   181  
   182  	// setup a proposal
   183  	content := types.NewTextProposal("Test", "description")
   184  
   185  	submitTime := ctx.BlockHeader().Time
   186  	depositPeriod := app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod
   187  
   188  	proposal, err := types.NewProposal(content, 1, submitTime, submitTime.Add(depositPeriod))
   189  	require.NoError(t, err)
   190  
   191  	app.GovKeeper.ActivateVotingPeriod(ctx, proposal)
   192  
   193  	// begin a new block
   194  	app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash, Time: blockTime}})
   195  
   196  	// execute operation
   197  	op := simulation.SimulateMsgVote(app.AccountKeeper, app.BankKeeper, app.GovKeeper)
   198  	operationMsg, _, err := op(r, app.BaseApp, ctx, accounts, "")
   199  	require.NoError(t, err)
   200  
   201  	var msg types.MsgVote
   202  	err = govcodec.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)
   203  	require.NoError(t, err)
   204  
   205  	require.True(t, operationMsg.OK)
   206  	require.Equal(t, uint64(1), msg.ProposalId)
   207  	require.Equal(t, "link1ghekyjucln7y67ntx7cf27m9dpuxxemnqk82wt", msg.Voter)
   208  	require.Equal(t, types.OptionYes, msg.Option)
   209  	require.Equal(t, "gov", msg.Route())
   210  	require.Equal(t, types.TypeMsgVote, msg.Type())
   211  }
   212  
   213  // TestSimulateMsgVoteWeighted tests the normal scenario of a valid message of type TypeMsgVoteWeighted.
   214  // Abonormal scenarios, where the message is created by an errors are not tested here.
   215  func TestSimulateMsgVoteWeighted(t *testing.T) {
   216  	app, ctx := createTestApp(false)
   217  	blockTime := time.Now().UTC()
   218  	ctx = ctx.WithBlockTime(blockTime)
   219  
   220  	// setup 3 accounts
   221  	s := rand.NewSource(1)
   222  	r := rand.New(s)
   223  	accounts := getTestingAccounts(t, r, app, ctx, 3)
   224  
   225  	// setup a proposal
   226  	content := types.NewTextProposal("Test", "description")
   227  
   228  	submitTime := ctx.BlockHeader().Time
   229  	depositPeriod := app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod
   230  
   231  	proposal, err := types.NewProposal(content, 1, submitTime, submitTime.Add(depositPeriod))
   232  	require.NoError(t, err)
   233  
   234  	app.GovKeeper.ActivateVotingPeriod(ctx, proposal)
   235  
   236  	// begin a new block
   237  	app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash, Time: blockTime}})
   238  
   239  	// execute operation
   240  	op := simulation.SimulateMsgVoteWeighted(app.AccountKeeper, app.BankKeeper, app.GovKeeper)
   241  	operationMsg, _, err := op(r, app.BaseApp, ctx, accounts, "")
   242  	require.NoError(t, err)
   243  
   244  	var msg types.MsgVoteWeighted
   245  	err = govcodec.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)
   246  	require.NoError(t, err)
   247  
   248  	require.True(t, operationMsg.OK)
   249  	require.Equal(t, uint64(1), msg.ProposalId)
   250  	require.Equal(t, "link1ghekyjucln7y67ntx7cf27m9dpuxxemnqk82wt", msg.Voter)
   251  	require.True(t, len(msg.Options) >= 1)
   252  	require.Equal(t, "gov", msg.Route())
   253  	require.Equal(t, types.TypeMsgVoteWeighted, msg.Type())
   254  }
   255  
   256  // returns context and an app with updated mint keeper
   257  func createTestApp(isCheckTx bool) (*simapp.SimApp, sdk.Context) {
   258  	app := simapp.Setup(isCheckTx)
   259  
   260  	ctx := app.BaseApp.NewContext(isCheckTx, tmproto.Header{})
   261  	app.MintKeeper.SetParams(ctx, minttypes.DefaultParams())
   262  	app.MintKeeper.SetMinter(ctx, minttypes.DefaultInitialMinter())
   263  
   264  	return app, ctx
   265  }
   266  
   267  func getTestingAccounts(t *testing.T, r *rand.Rand, app *simapp.SimApp, ctx sdk.Context, n int) []simtypes.Account {
   268  	accounts := simtypes.RandomAccounts(r, n)
   269  
   270  	initAmt := app.StakingKeeper.TokensFromConsensusPower(ctx, 200)
   271  	initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt))
   272  
   273  	// add coins to the accounts
   274  	for _, account := range accounts {
   275  		acc := app.AccountKeeper.NewAccountWithAddress(ctx, account.Address)
   276  		app.AccountKeeper.SetAccount(ctx, acc)
   277  		require.NoError(t, simapp.FundAccount(app, ctx, account.Address, initCoins))
   278  	}
   279  
   280  	return accounts
   281  }