diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7583d4fa41..6deb05cbe8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -44,22 +44,22 @@ jobs: name: "${{ steps.def-vars.outputs.file-prefix }}-pkgs.txt" path: ./pkgs.txt - name: Split pkgs into parts - # The x/marker/simulation test-race takes around 6ish minutes and is by far the longest running one. - # The next longest running is x/metadata/client/cli at 2.5ish minutes. - # So take x/marker/simulation out of the list, split the list into 3 parts and create a 4th part - # with just the x/marker/simulation test. - # Temporarily, several tests are known to still fail, so we make them all part 3, and split the rest among 0-2. - # TODO[1760]: Re-analyze how long tests tests take and change the splitting back to be based on speed. + # With a standard split, test-race (03) takes the longest of all these at around 6m35s. + # and test-race (00) is the shortest (of the race tests) at around 4m00s. + # The x/sanction/simulation test-race is one of the longer ones (at almost 2 minutes), and ends up in part 03. + # By forcing that one into 00, it ends up reducing the overall run-time of this whole workflow by about a minute. + # The x/marker/client/cli tests take around 30s (35s for race), and would be in 01. + # Moving it to 00 ends up leveling out the times a bit more. run: | grep -vF \ - -e 'github.com/provenance-io/provenance/x/ibcratelimit/simulation' \ - -e 'github.com/provenance-io/provenance/x/oracle/simulation' \ + -e 'github.com/provenance-io/provenance/x/sanction/simulation' \ + -e 'github.com/provenance-io/provenance/x/marker/client/cli' \ pkgs.txt > pkgs.txt.tmp - split -d -n l/3 pkgs.txt.tmp pkgs.txt.part. + split -d -n l/4 pkgs.txt.tmp pkgs.txt.part. printf '%s\n' \ - 'github.com/provenance-io/provenance/x/ibcratelimit/simulation' \ - 'github.com/provenance-io/provenance/x/oracle/simulation' \ - > pkgs.txt.part.03 + 'github.com/provenance-io/provenance/x/sanction/simulation' \ + 'github.com/provenance-io/provenance/x/marker/client/cli' \ + >> pkgs.txt.part.00 - uses: actions/upload-artifact@v4 with: name: "${{ steps.def-vars.outputs.file-prefix }}-pkgs.txt.part.00" diff --git a/CHANGELOG.md b/CHANGELOG.md index 38ae90cf16..74ca0cf658 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -96,6 +96,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * `marker` add `UpdateParams` endpoint and cli [#1991](https://github.com/provenance-io/provenance/pull/1991). * `name` add `UpdateParams` endpoint and cli [#2004](https://github.com/provenance-io/provenance/pull/2004). * Update the exchange `commitment-settlement-fee-calc` cli query to utilize the keyring [#2001](https://github.com/provenance-io/provenance/pull/2001). +* Implement the ProposalMsgs module interface for the internal/provwasm, ibcratelimit, oracle, and sanction modules [#1993](https://github.com/provenance-io/provenance/pull/1993.) ### Client Breaking diff --git a/app/app.go b/app/app.go index 886e75b974..004e6f9a47 100644 --- a/app/app.go +++ b/app/app.go @@ -770,7 +770,7 @@ func New( // IBC ibc.NewAppModule(app.IBCKeeper), - ibcratelimitmodule.NewAppModule(appCodec, *app.RateLimitingKeeper, app.AccountKeeper, app.BankKeeper), + ibcratelimitmodule.NewAppModule(appCodec, *app.RateLimitingKeeper), ibchooks.NewAppModule(app.AccountKeeper, *app.IBCHooksKeeper), ibctransfer.NewAppModule(*app.TransferKeeper), icqModule, @@ -1015,7 +1015,7 @@ func New( // IBC ibc.NewAppModule(app.IBCKeeper), - ibcratelimitmodule.NewAppModule(appCodec, *app.RateLimitingKeeper, app.AccountKeeper, app.BankKeeper), + ibcratelimitmodule.NewAppModule(appCodec, *app.RateLimitingKeeper), ibchooks.NewAppModule(app.AccountKeeper, *app.IBCHooksKeeper), ibctransfer.NewAppModule(*app.TransferKeeper), icaModule, diff --git a/app/params/weights.go b/app/params/weights.go index 732ddc2581..8381e348b8 100644 --- a/app/params/weights.go +++ b/app/params/weights.go @@ -14,13 +14,6 @@ const ( DefaultWeightMsgDeleteDistinctAttribute int = 5 DefaultWeightMsgSetAccountData int = 10 // Marker - DefaultWeightSupplyIncreaseProposalContent int = 5 - DefaultWeightSupplyDecreaseProposalContent int = 5 - DefaultWeightSetAdministratorProposalContent int = 5 - DefaultWeightRemoveAdministratorProposalContent int = 5 - DefaultWeightChangeStatusProposalContent int = 5 - DefaultWeightSetDenomMetadataProposalContent int = 5 - // Adjusted marker operations to a cumulative weight of 100 DefaultWeightMsgAddMarker int = 30 DefaultWeightMsgChangeStatus int = 10 DefaultWeightMsgFinalize int = 10 @@ -28,12 +21,6 @@ const ( DefaultWeightMsgAddFinalizeActivateMarker int = 10 DefaultWeightMsgAddMarkerProposal int = 40 DefaultWeightMsgUpdateDenySendList int = 10 - // MsgFees - DefaultWeightAddMsgFeeProposalContent int = 75 - DefaultWeightRemoveMsgFeeProposalContent int = 25 - // Rewards - DefaultWeightSubmitCreateRewards int = 95 - DefaultWeightSubmitEndRewards int = 5 // Trigger DefaultWeightSubmitCreateTrigger int = 95 DefaultWeightSubmitDestroyTrigger int = 5 @@ -41,5 +28,5 @@ const ( DefaultWeightUpdateOracle int = 25 DefaultWeightSendOracleQuery int = 75 // Ibc Rate Limiter - DefaultWeightUpdateParams int = 100 + DefaultWeightIBCRLUpdateParams int = 100 ) diff --git a/internal/helpers/rand.go b/internal/helpers/rand.go new file mode 100644 index 0000000000..4b02030477 --- /dev/null +++ b/internal/helpers/rand.go @@ -0,0 +1,43 @@ +package helpers + +import ( + "fmt" + "math/rand" + + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" +) + +// RandIntBetween generates a random number between min and max inclusive. +func RandIntBetween(r *rand.Rand, min, max int) int { + return r.Intn(max-min+1) + min +} + +// SelectRandomEntries selects count entries from the ones provided. +// The entriesType string is used in the error message to describe the entries slice. +func SelectRandomEntries[E any](r *rand.Rand, entries []E, count int, entriesType string) ([]E, error) { + if count == 0 { + return nil, nil + } + if len(entries) < count { + return nil, fmt.Errorf("cannot choose %d %s because there are only %d", count, entriesType, len(entries)) + } + if count == 1 { + if len(entries) == 1 { + return entries, nil + } + pivot := r.Intn(len(entries)) + return entries[pivot : pivot+1], nil + } + + randomized := make([]E, 0, len(entries)) + randomized = append(randomized, entries...) + r.Shuffle(len(randomized), func(i, j int) { + randomized[i], randomized[j] = randomized[j], randomized[i] + }) + return randomized[:count], nil +} + +// SelectRandomAccounts selects count accounts from the ones provided. +func SelectRandomAccounts(r *rand.Rand, accs []simtypes.Account, count int) ([]simtypes.Account, error) { + return SelectRandomEntries(r, accs, count, "accounts") +} diff --git a/internal/helpers/rand_test.go b/internal/helpers/rand_test.go new file mode 100644 index 0000000000..fd619caba5 --- /dev/null +++ b/internal/helpers/rand_test.go @@ -0,0 +1,283 @@ +package helpers + +import ( + "fmt" + "math/rand" + "slices" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/provenance-io/provenance/testutil/assertions" +) + +func TestRandIntBetween(t *testing.T) { + tests := []struct { + min int + max int + expPanic bool + }{ + {min: 0, max: 0}, + {min: 0, max: 10}, + {min: 1, max: 1}, + {min: -1, max: -1}, + {min: 1, max: 0, expPanic: true}, + {min: 0, max: -1, expPanic: true}, + {min: 1, max: -1, expPanic: true}, + {min: 10, max: -20, expPanic: true}, + {min: 10, max: -11, expPanic: true}, + {min: 10, max: -10, expPanic: true}, + {min: 10, max: -9, expPanic: true}, + {min: 10, max: 9, expPanic: true}, + {min: 10, max: 10}, + {min: 10, max: 11}, + {min: 10, max: 20}, + {min: -10, max: -11, expPanic: true}, + {min: -10, max: -10}, + {min: -10, max: -9}, + {min: -10, max: 9}, + {min: -10, max: 10}, + {min: -10, max: 11}, + {min: -20, max: -1}, + {min: -20, max: 0}, + {min: -20, max: 1}, + {min: 1001, max: 1100}, + {min: -1778, max: -1670}, + } + + for _, tc := range tests { + name := fmt.Sprintf("RandIntBetween(%d, %d)", tc.min, tc.max) + if tc.expPanic { + name += " panics" + } + + t.Run(name, func(t *testing.T) { + r := rand.New(rand.NewSource(1)) + // Check for panic for the first try. + seen := make(map[int]bool) + testFunc := func() { + val := RandIntBetween(r, tc.min, tc.max) + seen[val] = true + } + if tc.expPanic { + require.PanicsWithValue(t, "invalid argument to Intn", testFunc) + return + } + require.NotPanics(t, testFunc) + + count := tc.max - tc.min + 1 + expected := make([]int, 0, count) + for i := tc.min; i <= tc.max; i++ { + expected = append(expected, i) + } + + // Run it a bunch of times, trying to get it to return all possible values. + // I chose count*100 to essentially give each value 100 chances to be chosen, but be + // low enough to still finish pretty quickly if one or more values never gets returned. + for i := 0; i < count*100 && len(seen) < count; i++ { + testFunc() + } + // Make sure both the min and max were returned at some point. + assert.True(t, seen[tc.min], "minimum value %d in seen map", tc.min) + assert.True(t, seen[tc.max], "maximum value %d in seen map", tc.max) + + seenVals := Keys(seen) + slices.Sort(seenVals) + // Make sure the smallest and largest are as expected. + assert.Equal(t, tc.min, seenVals[0], "smallest number generated") + assert.Equal(t, tc.max, seenVals[len(seenVals)-1], "largest number generated") + // Make sure all values were generated. This check technically covers the previous ones, + // but I've got them split out like this for friendlier test failure messages. + assert.Equal(t, expected, seenVals, "values generated") + }) + } +} + +func TestSelectRandomEntries(t *testing.T) { + entries := make([]string, 3) + for i := range entries { + entries[i] = fmt.Sprintf("entry_%02d", i) + } + + // Seeds are chosen through trial and error for some tests so that the results are what I want for that test case. + tests := []struct { + name string + seed int64 // Defaults to 1 if not defined. + entries []string + count int + entriesType string + expected []string + expErr string + }{ + { + name: "nil entries, count 0", + entries: nil, + count: 0, + expected: nil, + }, + { + name: "nil entries, count 1", + entries: nil, + count: 1, + entriesType: "entries", + expErr: "cannot choose 1 entries because there are only 0", + }, + { + name: "nil entries, count 2", + entries: nil, + count: 2, + entriesType: "bananas", + expErr: "cannot choose 2 bananas because there are only 0", + }, + { + name: "nil entries, count 3", + entries: nil, + count: 3, + entriesType: "cars", + expErr: "cannot choose 3 cars because there are only 0", + }, + { + name: "empty entries, count 0", + entries: []string{}, + count: 0, + expected: nil, + }, + { + name: "empty entries, count 1", + entries: []string{}, + count: 1, + entriesType: "thingies", + expErr: "cannot choose 1 thingies because there are only 0", + }, + { + name: "empty entries, count 2", + entries: []string{}, + count: 2, + entriesType: "red pandas", + expErr: "cannot choose 2 red pandas because there are only 0", + }, + { + name: "empty entries, count 3", + entries: []string{}, + count: 3, + entriesType: "legos", + expErr: "cannot choose 3 legos because there are only 0", + }, + { + name: "one entry, count 0", + entries: entries[:1], + count: 0, + expected: nil, + }, + { + name: "one entry, count 1", + entries: entries[1:2], + count: 1, + expected: entries[1:2], + }, + { + name: "one entry, count 2", + entries: entries[2:3], + count: 2, + entriesType: "mice", + expErr: "cannot choose 2 mice because there are only 1", + }, + { + name: "one entry, count 3", + entries: entries[:1], + count: 3, + entriesType: "remotes", + expErr: "cannot choose 3 remotes because there are only 1", + }, + { + name: "two entries, count 0", + seed: 2, + entries: entries[:2], + count: 0, + expected: nil, + }, + { + name: "two entries, count 1, seed 1", + seed: 1, + entries: entries[:2], + count: 1, + expected: []string{entries[1]}, + }, + { + name: "two entries, count 1, seed 2", + seed: 2, + entries: entries[:2], + count: 1, + expected: []string{entries[0]}, + }, + { + name: "two entries, count 2", + seed: 2, + entries: entries[:2], + count: 2, + expected: []string{entries[1], entries[0]}, + }, + { + name: "two entries, count 3", + entries: entries[:2], + count: 3, + entriesType: "shoelaces", + expErr: "cannot choose 3 shoelaces because there are only 2", + }, + { + name: "three entries, count 0", + entries: entries[:3], + count: 0, + expected: nil, + }, + { + name: "three entries, count 1", + seed: 2, + entries: entries[:3], + count: 1, + expected: []string{entries[1]}, + }, + { + name: "three entries, count 2", + seed: 10, + entries: entries[:3], + count: 2, + expected: []string{entries[2], entries[0]}, + }, + { + name: "three entries, count 3, seed 10", + seed: 10, + entries: entries[:3], + count: 3, + expected: []string{entries[2], entries[0], entries[1]}, + }, + { + name: "three entries, count 3, seed 20", + seed: 20, + entries: entries[:3], + count: 3, + expected: []string{entries[1], entries[2], entries[0]}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + if tc.seed == 0 { + tc.seed = 1 + } + if len(tc.entriesType) == 0 { + tc.entriesType = "strings" + } + r := rand.New(rand.NewSource(tc.seed)) + var actual []string + var err error + testFunc := func() { + actual, err = SelectRandomEntries(r, tc.entries, tc.count, tc.entriesType) + } + require.NotPanics(t, testFunc, "SelectRandomEntries") + assertions.AssertErrorValue(t, err, tc.expErr, "SelectRandomEntries error") + assert.Equal(t, tc.expected, actual, "SelectRandomEntries result") + }) + } +} diff --git a/internal/provwasm/simulation.go b/internal/provwasm/simulation.go index 85f5a6cb68..27d86bbecf 100644 --- a/internal/provwasm/simulation.go +++ b/internal/provwasm/simulation.go @@ -32,6 +32,11 @@ import ( nametypes "github.com/provenance-io/provenance/x/name/types" ) +var ( + _ module.AppModuleSimulation = (*Wrapper)(nil) + _ module.HasProposalMsgs = (*Wrapper)(nil) +) + const ( denom = "coinfortestingsmartc" // must be a string of length 20 namePrefix = "scsnameprefix" // must be a string of length 13 @@ -84,8 +89,8 @@ func (pw Wrapper) GenerateGenesisState(input *module.SimulationState) { input.GenState[types.ModuleName] = input.Cdc.MustMarshalJSON(&wasmGenesis) } -// ProposalContents doesn't return any content functions for governance proposals. -func (pw Wrapper) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalMsg { +// ProposalMsgs returns the wasm weighted proposal messages. +func (pw Wrapper) ProposalMsgs(_ module.SimulationState) []simtypes.WeightedProposalMsg { return wasmsimulation.ProposalMsgs(pw.bk, pw.wk) } diff --git a/testutil/keyring.go b/testutil/keyring.go new file mode 100644 index 0000000000..c24cd1a6a1 --- /dev/null +++ b/testutil/keyring.go @@ -0,0 +1,79 @@ +package testutil + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// TestKeyringEntry is a keyring.Record plus some extra fields that might be needed for unit tests. +type TestKeyringEntry struct { + keyring.Record + AccAddress sdk.AccAddress + Mnemonic string +} + +// GenerateTestKeyring creates an in-memory keyring and adds count entries to it. +// The names of the entries will be incrementing, starting at "test_key_01". +func GenerateTestKeyring(t *testing.T, count int, codec codec.Codec) ([]TestKeyringEntry, keyring.Keyring) { + kr := NewTestKeyring(t, codec) + accounts := GenerateTestAccountsInKeyring(t, kr, count) + return accounts, kr +} + +// NewTestKeyring creates a new in-memory keyring for use in tests. +// Use GenerateTestAccountsInKeyring to add entries to the keyring. +func NewTestKeyring(t *testing.T, codec codec.Codec) keyring.Keyring { + kr, krErr := keyring.New(t.Name(), keyring.BackendMemory, "", nil, codec) + require.NoError(t, krErr, "keyring.New(...)") + return kr +} + +// GenerateTestAccountsInKeyring adds count entries to the keyring. +// The names of the entries will be like "test_key_01". +// +// Counting starts at 1 + the number of entries already in the keyring. +// E.g. If there aren't any yet, the first one will be "test_key_01". +// E.g. If there are five already in there, the first one added here will be "test_key_06". +// +// Only newly created entries are returned. +func GenerateTestAccountsInKeyring(t *testing.T, kr keyring.Keyring, count int) []TestKeyringEntry { + curRecs, curErr := kr.List() + require.NoError(t, curErr, "listing keyring entries") + i0 := len(curRecs) + 1 + + path := hd.CreateHDPath(118, 0, 0).String() + accounts := make([]TestKeyringEntry, count) + for i := range accounts { + name := fmt.Sprintf("test_key_%02d", i+i0) + info, mnemonic, err := kr.NewMnemonic(name, keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(t, err, "[%d] kr.NewMnemonic(%q, ...)", i, name) + addr, err := info.GetAddress() + require.NoError(t, err, "[%d] getting keyring address for %q", i, name) + accounts[i] = TestKeyringEntry{ + Record: *info, + AccAddress: addr, + Mnemonic: mnemonic, + } + } + + return accounts +} + +// GetKeyringEntryAddresses gets the AccAddress of each entry. +func GetKeyringEntryAddresses(entries []TestKeyringEntry) []sdk.AccAddress { + if len(entries) == 0 { + return nil + } + rv := make([]sdk.AccAddress, len(entries)) + for i, entry := range entries { + rv[i] = entry.AccAddress + } + return rv +} diff --git a/testutil/network.go b/testutil/network.go index 4ec19fd015..ef08127aca 100644 --- a/testutil/network.go +++ b/testutil/network.go @@ -55,7 +55,7 @@ func DefaultTestNetworkConfig() testnet.Config { log.NewNopLogger(), dbm.NewMemDB(), nil, true, make(map[int64]bool), tempDir, 0, simtestutil.NewAppOptionsWithFlagHome(tempDir), ) - encCfg := provenanceapp.MakeTestEncodingConfig(nil) + encCfg := tempApp.GetEncodingConfig() return testnet.Config{ Codec: encCfg.Marshaler, @@ -94,8 +94,6 @@ func Cleanup(n *testnet.Network, t *testing.T) { } t.Log("Cleanup: Cleaning up testnet.") n.Cleanup() - // Give things a chance to finish closing up. Hopefully will prevent things like address collisions. 100ms chosen randomly. - time.Sleep(100 * time.Millisecond) t.Log("Cleanup: Done.") } diff --git a/testutil/sims.go b/testutil/sims.go new file mode 100644 index 0000000000..06a99538ba --- /dev/null +++ b/testutil/sims.go @@ -0,0 +1,361 @@ +package testutil + +import ( + "bytes" + "fmt" + "math/rand" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/bank/testutil" + "github.com/cosmos/cosmos-sdk/x/simulation" + + "github.com/provenance-io/provenance/app" + "github.com/provenance-io/provenance/testutil/assertions" +) + +// LogOperationMsg outputs an OperationMsg to test logs. The provided msg and args are included first in the output. +func LogOperationMsg(t *testing.T, operationMsg simtypes.OperationMsg, msg string, args ...interface{}) { + msgFmt := "%q" + if len(bytes.TrimSpace(operationMsg.Msg)) == 0 { + msgFmt = " %q" + } + fmtLines := []string{ + fmt.Sprintf(msg, args...), + "operationMsg.Route: %q", + "operationMsg.Name: %q", + "operationMsg.Comment: %q", + "operationMsg.OK: %t", + "operationMsg.Msg: " + msgFmt, + } + t.Logf(strings.Join(fmtLines, "\n"), + operationMsg.Route, operationMsg.Name, operationMsg.Comment, operationMsg.OK, string(operationMsg.Msg), + ) +} + +func GenerateTestingAccounts(t *testing.T, ctx sdk.Context, app *app.App, r *rand.Rand, n int) []simtypes.Account { + return GenerateTestingAccountsWithPower(t, ctx, app, r, n, 1_000_000) +} + +// GenerateTestingAccountsWithPower generates n new accounts, creates them (in state) and gives each the provided power worth of bond tokens. +func GenerateTestingAccountsWithPower(t *testing.T, ctx sdk.Context, app *app.App, r *rand.Rand, n int, power int64) []simtypes.Account { + if n <= 0 { + return nil + } + t.Helper() + + initAmt := sdk.TokensFromConsensusPower(power, sdk.DefaultPowerReduction) + initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) + + accs := simtypes.RandomAccounts(r, n) + // add coins to the accounts + for i, account := range accs { + acc := app.AccountKeeper.NewAccountWithAddress(ctx, account.Address) + app.AccountKeeper.SetAccount(ctx, acc) + err := testutil.FundAccount(ctx, app.BankKeeper, account.Address, initCoins) + require.NoError(t, err, "[%d]: FundAccount", i) + } + + return accs +} + +// SimTestHelper contains various things needed to check most of the simulation-related stuff. +type SimTestHelper struct { + // T is the testing.T to use for the tests. + T *testing.T + // Ctx is the context to provide to the various simulation-related functions. + Ctx sdk.Context + // R is the randomizer to provide to the various simulation-related functions. + R *rand.Rand + // App is the app object used in some of the simulation-related functions, and also used to create test accounts. + App *app.App + // Accs are the accounts to provide to the various simulation-related funtions. + Accs []simtypes.Account +} + +// NewSimTestHelper creates a new SimTestHelper with the provided aspects. +// You'll probably want to call either WithAccs or WithTestingAccounts on the result to finish setting it up. +func NewSimTestHelper(t *testing.T, ctx sdk.Context, r *rand.Rand, app *app.App) *SimTestHelper { + return &SimTestHelper{ + T: t, + Ctx: ctx, + R: r, + App: app, + } +} + +// WithT returns a copy of this SimTestHelper, but with a different T. +func (a SimTestHelper) WithT(t *testing.T) *SimTestHelper { + a.T = t + return &a +} + +// WithR returns a copy of this SimTestHelper, but with a different R. +func (a SimTestHelper) WithR(r *rand.Rand) *SimTestHelper { + a.R = r + return &a +} + +// WithCtx returns a copy of this SimTestHelper, but with a different Ctx. +func (a SimTestHelper) WithCtx(ctx sdk.Context) *SimTestHelper { + a.Ctx = ctx + return &a +} + +// WithApp returns a copy of this SimTestHelper, but with a different App. +func (a SimTestHelper) WithApp(app *app.App) *SimTestHelper { + a.App = app + return &a +} + +// WithAccs returns a copy of this SimTestHelper, but with the provided Accs. +func (a SimTestHelper) WithAccs(accs []simtypes.Account) *SimTestHelper { + a.Accs = accs + return &a +} + +// WithTestingAccounts returns a copy of this SimTestHelper, but with n randomized Accs. +func (a SimTestHelper) WithTestingAccounts(n int) *SimTestHelper { + a.Accs = GenerateTestingAccounts(a.T, a.Ctx, a.App, a.R, n) + return &a +} + +// WithTestingAccountsWithPower returns a copy of this SimTestHelper, but with n randomized Accs having the provided power. +func (a SimTestHelper) WithTestingAccountsWithPower(n int, power int64) *SimTestHelper { + a.Accs = GenerateTestingAccountsWithPower(a.T, a.Ctx, a.App, a.R, n, power) + return &a +} + +// GenerateTestingAccounts generates n new accounts, creates them (in state) and gives each 1 million power worth of bond tokens. +// ExpectedWeightedOp is the various aspects of a simulation.WeightedOperation to check. +type ExpectedWeightedOp struct { + // Weight is the expected WeightedOperation.Weight. + Weight int + // Route is the expected WeightedOperation.Route. + Route string + // MsgType is a Msg with the same type that is expected to be returned by the WeightedOperation.Op() function. + // No assertion is made that the returned Msg equals this message, only that they both have the same result from sdk.MsgTypeURL. + MsgType sdk.Msg +} + +// AssertWeightedOperations tests that the results of a WeightedOperations function are as expected. +// The returned bool is true iff everything is as expected. +func (a SimTestHelper) AssertWeightedOperations(expected []ExpectedWeightedOp, wOpsFn func() simulation.WeightedOperations) bool { + a.T.Helper() + var wOps simulation.WeightedOperations + testWOpsFn := func() { + wOps = wOpsFn() + } + if !assert.NotPanics(a.T, testWOpsFn, "Executing the provided WeightedOperations function.") { + return false + } + + expNames := make([]string, len(expected)) + for i, exp := range expected { + expNames[i] = sdk.MsgTypeURL(exp.MsgType) + } + + // Run all the ops and get the operation messages and their names. + opMsgs := make([]simtypes.OperationMsg, len(wOps)) + actNames := make([]string, len(wOps)) + for i, w := range wOps { + testFunc := func() { + opMsgs[i], _, _ = w.Op()(a.R, a.App.BaseApp, a.Ctx, a.Accs, "") + } + if !assert.NotPanics(a.T, testFunc, "executing OperationMsg[%d]", i) { + return false + } + actNames[i] = opMsgs[i].Name + } + + // First, make sure the op names are as expected since a failure there probably means the rest will fail. + // And it's probably easier to address when you've got a nice list comparison of names and their orderings. + if !assert.Equal(a.T, expNames, actNames, "operation message names") { + return false + } + + // Now assert that each entry was as expected. + ok := true + for i := range expected { + a.T.Run(fmt.Sprintf("%d: %s", i, expNames[i]), func(t *testing.T) { + LogOperationMsg(t, opMsgs[i], "WeightedOperation [%d]", i) + ok = assert.Equal(t, expected[i].Weight, wOps[i].Weight(), "weightedOps[%d].Weight", i) && ok + ok = assert.Equal(t, expected[i].Route, opMsgs[i].Route, "weightedOps[%d] operationMsg.Route", i) && ok + ok = assert.Equal(t, expNames[i], opMsgs[i].Name, "weightedOps[%d] operationMsg.Name", i) && ok + }) + } + + return ok +} + +// ExpectedProposalMsg is the various aspects of a simulation.WeightedProposalMsg to check. +type ExpectedProposalMsg struct { + // Key is the expected WeightedProposalMsg.AppParamsKey() + Key string + // Weight is the expected WeightedProposalMsg.DefaultWeight() + Weight int + // MsgType is a Msg with the same type that is expected to be returned by the WeightedProposalMsg.MsgSimulatorFn(). + // No assertion is made that the returned Msg equals this message, only that they both have the same result from sdk.MsgTypeURL. + MsgType sdk.Msg +} + +// AssertProposalMsgs tests that the results of a ProposalMsgs function are as expected. +// The returned bool is true iff everything is as expected. +func (a SimTestHelper) AssertProposalMsgs(expected []ExpectedProposalMsg, proposalMsgsFn func() []simtypes.WeightedProposalMsg) bool { + a.T.Helper() + var wOps []simtypes.WeightedProposalMsg + testWOps := func() { + wOps = proposalMsgsFn() + } + if !assert.NotPanics(a.T, testWOps, "Executing the provided ProposalMsgs function.") { + return false + } + + expNames := make([]string, len(expected)) + for i, exp := range expected { + expNames[i] = sdk.MsgTypeURL(exp.MsgType) + } + actNames := make([]string, len(wOps)) + propMsgs := make([]sdk.Msg, len(wOps)) + ok := true + for i, act := range wOps { + testFunc := func() { + propMsgs[i] = act.MsgSimulatorFn()(a.R, a.Ctx, a.Accs) + } + if !assert.NotPanics(a.T, testFunc, "executing MsgSimulatorFn [%d]", i) { + ok = false + actNames[i] = "" + } else { + actNames[i] = sdk.MsgTypeURL(propMsgs[i]) + } + } + + // First, make sure the op names are as expected since a failure there probably means the rest will fail. + // And it's probably easier to address when you've got a nice list comparison of names and their orderings. + if !assert.Equal(a.T, expNames, actNames, "operation message names") { + return false + } + + // Now assert that each entry was as expected. + for i, exp := range expected { + a.T.Run(fmt.Sprintf("%d: %s", i, exp.Key), func(t *testing.T) { + ok = assert.Equal(t, exp.Key, wOps[i].AppParamsKey(), "AppParamsKey()") && ok + ok = assert.Equal(t, exp.Weight, wOps[i].DefaultWeight(), "DefaultWeight()") && ok + ok = assert.NotNil(t, propMsgs[i], "MsgSimulatorFn result") && ok + }) + } + + return ok +} + +// ExpectedOp is the various aspects of a simulation.Operation to check. +type ExpectedOp struct { + // FutureOpCount is the exected length of the []FutureOperation returned by the Operation. + FutureOpCount int + // Err is the error expected from the Operation. + Err string + + // Route is the expected OperationMsg.Route value (usually the module name). + Route string + // EmptyMsg serves two purposes: + // 1. The OperationMsg.Name is expected to be the sdk.MsgTypeURL of this field. + // 2. The OperationMsg.Msg will be unmarshalled into this field if possible. + EmptyMsg sdk.Msg + // Comment is the expected OperationMsg.Comment value. + Comment string + // OK is the expected OperationMsg.OK value. + OK bool +} + +// AssertSimOp tests that a simulation Operation is as expected. +// The returned bool is true iff everything is as expected. +// The msg and future ops are returned even if things aren't as expected. +func (a SimTestHelper) AssertSimOp(expected ExpectedOp, opMaker func() simtypes.Operation, opDesc string) (sdk.Msg, []simtypes.FutureOperation, bool) { + a.T.Helper() + var op simtypes.Operation + testOp := func() { + op = opMaker() + } + if !assert.NotPanics(a.T, testOp, "Running the Operation Maker.") { + return nil, nil, false + } + if !assert.NotNil(a.T, op, "The Operation") { + return nil, nil, false + } + + // Run the op, and log it. + var opMsg simtypes.OperationMsg + var fOps []simtypes.FutureOperation + var opErr error + testFunc := func() { + opMsg, fOps, opErr = op(a.R, a.App.BaseApp, a.Ctx, a.Accs, "") + } + if !assert.NotPanics(a.T, testFunc, "executing the simtypes.Operation(...)") { + return nil, fOps, false + } + LogOperationMsg(a.T, opMsg, opDesc) + + // Check the error and number of future ops. + ok := true + ok = assertions.AssertErrorValue(a.T, opErr, expected.Err, "error returned from the simtypes.Operation(...)") && ok + ok = assert.Len(a.T, fOps, expected.FutureOpCount, "future ops returned from the simtypes.Operation(...)") && ok + + // Attempt to unmarshal the msg now, so it can be available even if we end up returning early. + // We check the error after the short-circuit because of the case when we're expecting an error, + // but don't get one. When that happens, the error assertion above will fail, so ok will be false, + // and we don't really care whether the Msg is the type expected. Checking this error before the + // short-circuit is likely to just pollute the test output with a failure that isn't helpful. + // The content of the Msg was logged, so it's available for reference if needed for troubleshooting. + // + // Further, there are some cases (e.g. a no-op) where the Msg is expected to be empty. + // We want to allow for this, so we only make this conversion attempt if it's not empty. + var msgErr error + if len(opMsg.Msg) > 0 { + msgErr = a.App.AppCodec().Unmarshal(opMsg.Msg, expected.EmptyMsg) + } + + // If the Operation returned an error, or we were expecting one, the rest of the checks are meaningless. + if opErr != nil || len(expected.Err) > 0 { + return expected.EmptyMsg, fOps, ok + } + + // Check the opMsg results. + ok = assert.NoError(a.T, msgErr, "Unmarshal(opMsg.Msg) error") && ok + ok = assert.Equal(a.T, expected.OK, opMsg.OK, "opMsg.OK") && ok + ok = assert.Equal(a.T, sdk.MsgTypeURL(expected.EmptyMsg), opMsg.Name, "opMsg.Name") && ok + ok = assert.Equal(a.T, expected.Route, opMsg.Route, "opMsg.Route") && ok + ok = assert.Equal(a.T, expected.Comment, opMsg.Comment, "opMsg.Comment") && ok + + return expected.EmptyMsg, fOps, ok +} + +// AssertMsgSimulatorFn tests that a MsgSimulatorFn generates the expected Msg. +// The returned bool is true iff everything is as expected. +// The returned Msg might be nil regardless of the returned bool value. +func (a SimTestHelper) AssertMsgSimulatorFn(expected sdk.Msg, simFnMaker func() simtypes.MsgSimulatorFn) (sdk.Msg, bool) { + a.T.Helper() + var msgSimFn simtypes.MsgSimulatorFn + testMaker := func() { + msgSimFn = simFnMaker() + } + if !assert.NotPanics(a.T, testMaker, "The provided MsgSimulatorFn maker.") { + return nil, false + } + if !assert.NotNil(a.T, msgSimFn, "The MsgSimulatorFn returned by the provided maker.") { + return nil, false + } + + var actual sdk.Msg + testMsgSimFn := func() { + actual = msgSimFn(a.R, a.Ctx, a.Accs) + } + if !assert.NotPanics(a.T, testMsgSimFn, "Executing the MsgSimulatorFn") { + return actual, false + } + return actual, assert.Equal(a.T, expected, actual) +} diff --git a/x/attribute/client/cli/cli_test.go b/x/attribute/client/cli/cli_test.go index aea8157743..5c9b694701 100644 --- a/x/attribute/client/cli/cli_test.go +++ b/x/attribute/client/cli/cli_test.go @@ -16,7 +16,6 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" testnet "github.com/cosmos/cosmos-sdk/testutil/network" @@ -39,11 +38,11 @@ import ( type IntegrationTestSuite struct { suite.Suite - cfg testnet.Config - testnet *testnet.Network - keyring keyring.Keyring - keyringDir string + cfg testnet.Config + testnet *testnet.Network + keyring keyring.Keyring + keyringEntries []testutil.TestKeyringEntry accountAddresses []sdk.AccAddress account1Addr sdk.AccAddress @@ -77,21 +76,8 @@ func TestIntegrationTestSuite(t *testing.T) { // Generate a number of accounts with keyring entries. // To use these, do .WithKeyring(s.keyring) when getting the client context. func (s *IntegrationTestSuite) generateKeyringAndAccounts(number int) { - path := hd.CreateHDPath(118, 0, 0).String() - s.keyringDir = s.T().TempDir() - var err error - s.keyring, err = keyring.New(s.T().Name(), "test", s.keyringDir, nil, s.cfg.Codec) - s.Require().NoError(err, "creating keyring") - - s.accountAddresses = make([]sdk.AccAddress, number) - for i := range s.accountAddresses { - keyID := fmt.Sprintf("test_key%v", i+1) - info, _, err := s.keyring.NewMnemonic(keyID, keyring.English, path, "", hd.Secp256k1) - s.Require().NoError(err, "NewMnemonic(%q)", keyID) - addr, err := info.GetAddress() - s.Require().NoError(err, "getting keyring address") - s.accountAddresses[i] = addr - } + s.keyringEntries, s.keyring = testutil.GenerateTestKeyring(s.T(), number, s.cfg.Codec) + s.accountAddresses = testutil.GetKeyringEntryAddresses(s.keyringEntries) } func (s *IntegrationTestSuite) SetupSuite() { diff --git a/x/attribute/simulation/operations_test.go b/x/attribute/simulation/operations_test.go index d180a4e57f..bf5a07c492 100644 --- a/x/attribute/simulation/operations_test.go +++ b/x/attribute/simulation/operations_test.go @@ -13,10 +13,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/x/bank/testutil" "github.com/provenance-io/provenance/app" simappparams "github.com/provenance-io/provenance/app/params" + "github.com/provenance-io/provenance/testutil" "github.com/provenance-io/provenance/x/attribute/simulation" "github.com/provenance-io/provenance/x/attribute/types" ) @@ -267,20 +267,7 @@ func (s *SimTestSuite) TestSimulateMsgSetAccountData() { } func (s *SimTestSuite) getTestingAccounts(r *rand.Rand, n int) []simtypes.Account { - accounts := simtypes.RandomAccounts(r, n) - - initAmt := sdk.TokensFromConsensusPower(200, sdk.DefaultPowerReduction) - initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) - - // add coins to the accounts - for i, account := range accounts { - acc := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, account.Address) - s.app.AccountKeeper.SetAccount(s.ctx, acc) - err := testutil.FundAccount(s.ctx, s.app.BankKeeper, account.Address, initCoins) - s.Require().NoError(err, "[%d]: FundAccount", i) - } - - return accounts + return testutil.GenerateTestingAccountsWithPower(s.T(), s.ctx, s.app, r, n, 200) } func GenerateRandomTime(minHours int) time.Time { diff --git a/x/exchange/client/cli/cli_test.go b/x/exchange/client/cli/cli_test.go index 19febb9ae1..c29295a201 100644 --- a/x/exchange/client/cli/cli_test.go +++ b/x/exchange/client/cli/cli_test.go @@ -50,12 +50,13 @@ import ( type CmdTestSuite struct { suite.Suite - cfg testnet.Config - testnet *testnet.Network - keyring keyring.Keyring - keyringDir string - accountAddrs []sdk.AccAddress - feeDenom string + cfg testnet.Config + testnet *testnet.Network + feeDenom string + + keyring keyring.Keyring + keyringEntries []testutil.TestKeyringEntry + accountAddrs []sdk.AccAddress addr0 sdk.AccAddress addr1 sdk.AccAddress @@ -361,7 +362,7 @@ func (s *CmdTestSuite) SetupSuite() { s.testnet, err = testnet.New(s.T(), s.T().TempDir(), s.cfg) s.Require().NoError(err, "testnet.New(...)") - s.testnet.Validators[0].ClientCtx = s.testnet.Validators[0].ClientCtx.WithKeyringDir(s.keyringDir).WithKeyring(s.keyring) + s.testnet.Validators[0].ClientCtx = s.testnet.Validators[0].ClientCtx.WithKeyring(s.keyring) _, err = testutil.WaitForHeight(s.testnet, 1) s.Require().NoError(err, "s.testnet.WaitForHeight(1)") @@ -375,21 +376,8 @@ func (s *CmdTestSuite) TearDownSuite() { // The s.keyringDir, s.keyring, and s.accountAddrs are all set in here. // The getClientCtx function returns a context that knows about this keyring. func (s *CmdTestSuite) generateAccountsWithKeyring(number int) { - path := hd.CreateHDPath(118, 0, 0).String() - s.keyringDir = s.T().TempDir() - var err error - s.keyring, err = keyring.New(s.T().Name(), "test", s.keyringDir, nil, s.cfg.Codec) - s.Require().NoError(err, "keyring.New(...)") - - s.accountAddrs = make([]sdk.AccAddress, number) - for i := range s.accountAddrs { - keyId := fmt.Sprintf("test_key_%v", i) - var info *keyring.Record - info, _, err = s.keyring.NewMnemonic(keyId, keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1) - s.Require().NoError(err, "[%d] s.keyring.NewMnemonic(...)", i) - s.accountAddrs[i], err = info.GetAddress() - s.Require().NoError(err, "[%d] getting keyring address", i) - } + s.keyringEntries, s.keyring = testutil.GenerateTestKeyring(s.T(), number, s.cfg.Codec) + s.accountAddrs = testutil.GetKeyringEntryAddresses(s.keyringEntries) } // makeInitialOrder makes an order using the order id for various aspects. diff --git a/x/ibcratelimit/client/cli/cli_test.go b/x/ibcratelimit/client/cli/cli_test.go index 7bda2d08e7..82bbaaa910 100644 --- a/x/ibcratelimit/client/cli/cli_test.go +++ b/x/ibcratelimit/client/cli/cli_test.go @@ -11,7 +11,6 @@ import ( sdkmath "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" @@ -32,10 +31,11 @@ import ( type TestSuite struct { suite.Suite - cfg network.Config - network *network.Network - keyring keyring.Keyring - keyringDir string + cfg network.Config + network *network.Network + + keyring keyring.Keyring + keyringEntries []testutil.TestKeyringEntry accountAddr sdk.AccAddress accountKey *secp256k1.PrivKey @@ -102,7 +102,7 @@ func (s *TestSuite) SetupSuite() { s.network, err = network.New(s.T(), s.T().TempDir(), s.cfg) s.Require().NoError(err, "network.New") - s.network.Validators[0].ClientCtx = s.network.Validators[0].ClientCtx.WithKeyringDir(s.keyringDir).WithKeyring(s.keyring) + s.network.Validators[0].ClientCtx = s.network.Validators[0].ClientCtx.WithKeyring(s.keyring) _, err = testutil.WaitForHeight(s.network, 6) s.Require().NoError(err, "WaitForHeight") } @@ -112,21 +112,8 @@ func (s *TestSuite) TearDownSuite() { } func (s *TestSuite) GenerateAccountsWithKeyrings(number int) { - path := hd.CreateHDPath(118, 0, 0).String() - s.keyringDir = s.T().TempDir() - kr, err := keyring.New(s.T().Name(), "test", s.keyringDir, nil, s.cfg.Codec) - s.Require().NoError(err, "Keyring.New") - s.keyring = kr - for i := 0; i < number; i++ { - keyId := fmt.Sprintf("test_key%v", i) - info, _, err := kr.NewMnemonic(keyId, keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1) - s.Require().NoError(err, "Keyring.NewMneomonic") - addr, err := info.GetAddress() - if err != nil { - panic(err) - } - s.accountAddresses = append(s.accountAddresses, addr) - } + s.keyringEntries, s.keyring = testutil.GenerateTestKeyring(s.T(), number, s.cfg.Codec) + s.accountAddresses = testutil.GetKeyringEntryAddresses(s.keyringEntries) } func (s *TestSuite) TestGetParams() { diff --git a/x/ibcratelimit/keeper/keeper.go b/x/ibcratelimit/keeper/keeper.go index 3235d4a2b9..d0cd726270 100644 --- a/x/ibcratelimit/keeper/keeper.go +++ b/x/ibcratelimit/keeper/keeper.go @@ -74,6 +74,11 @@ func (k Keeper) IsContractConfigured(ctx sdk.Context) bool { return params.ContractAddress != "" } +// GetAuthority gets the authority account address. +func (k Keeper) GetAuthority() string { + return k.authority +} + // ValidateAuthority returns an error if the provided address is not the authority. func (k Keeper) ValidateAuthority(addr string) error { if k.authority != addr { diff --git a/x/ibcratelimit/module/module.go b/x/ibcratelimit/module/module.go index 52e7e9ab61..cdea447fca 100644 --- a/x/ibcratelimit/module/module.go +++ b/x/ibcratelimit/module/module.go @@ -20,9 +20,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" 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" - "github.com/provenance-io/provenance/x/ibcratelimit" ibcratelimitcli "github.com/provenance-io/provenance/x/ibcratelimit/client/cli" "github.com/provenance-io/provenance/x/ibcratelimit/keeper" @@ -32,6 +29,7 @@ import ( var ( _ module.AppModuleBasic = (*AppModule)(nil) _ module.AppModuleSimulation = (*AppModule)(nil) + _ module.HasProposalMsgs = (*AppModule)(nil) _ appmodule.AppModule = (*AppModule)(nil) ) @@ -93,18 +91,14 @@ func (b AppModuleBasic) GetTxCmd() *cobra.Command { // AppModule implements the sdk.AppModule interface type AppModule struct { AppModuleBasic - keeper keeper.Keeper - accountKeeper authkeeper.AccountKeeper - bankKeeper bankkeeper.Keeper + keeper keeper.Keeper } // NewAppModule creates a new AppModule object -func NewAppModule(cdc codec.Codec, keeper keeper.Keeper, accountKeeper authkeeper.AccountKeeper, bankKeeper bankkeeper.Keeper) AppModule { +func NewAppModule(cdc codec.Codec, keeper keeper.Keeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{cdc: cdc}, keeper: keeper, - accountKeeper: accountKeeper, - bankKeeper: bankKeeper, } } @@ -130,8 +124,13 @@ func (am AppModule) RegisterStoreDecoder(sdr simtypes.StoreDecoderRegistry) { } // WeightedOperations returns simulation operations (i.e msgs) with their respective weight -func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { - return simulation.WeightedOperations(simState, am.keeper, am.accountKeeper, am.bankKeeper) +func (am AppModule) WeightedOperations(_ module.SimulationState) []simtypes.WeightedOperation { + return nil +} + +// ProposalMsgs returns all the msgs to execute as governance proposals. +func (am AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg { + return simulation.ProposalMsgs(simState, &am.keeper) } // Name returns the ibcratelimit module's name. diff --git a/x/ibcratelimit/simulation/genesis.go b/x/ibcratelimit/simulation/genesis.go index 7097bcc919..aebc9f4e25 100644 --- a/x/ibcratelimit/simulation/genesis.go +++ b/x/ibcratelimit/simulation/genesis.go @@ -8,6 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/provenance-io/provenance/internal/helpers" "github.com/provenance-io/provenance/x/ibcratelimit" ) @@ -16,9 +17,9 @@ const ( Contract = "contract" ) -// ContractFn randomized conntract address +// ContractFn randomized contract address func ContractFn(r *rand.Rand, accs []simtypes.Account) string { - randomAccount, _ := RandomAccs(r, accs, 1) + randomAccount, _ := helpers.SelectRandomAccounts(r, accs, 1) if r.Intn(2) > 0 || len(randomAccount) == 0 { return "" } diff --git a/x/ibcratelimit/simulation/genesis_test.go b/x/ibcratelimit/simulation/genesis_test.go index af9707ebc7..575ce1fadd 100644 --- a/x/ibcratelimit/simulation/genesis_test.go +++ b/x/ibcratelimit/simulation/genesis_test.go @@ -5,13 +5,15 @@ import ( "math/rand" "testing" + "github.com/stretchr/testify/assert" + "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/provenance-io/provenance/x/ibcratelimit" "github.com/provenance-io/provenance/x/ibcratelimit/simulation" - "github.com/stretchr/testify/assert" ) func TestContractFn(t *testing.T) { @@ -25,13 +27,13 @@ func TestContractFn(t *testing.T) { }{ { name: "success - returns an empty account", - seed: 0, + seed: 3, accounts: accs, expected: "", }, { name: "success - returns a random account", - seed: 3, + seed: 0, accounts: accs, expected: "cosmos1tp4es44j4vv8m59za3z0tm64dkmlnm8wg2frhc", }, diff --git a/x/ibcratelimit/simulation/operations.go b/x/ibcratelimit/simulation/operations.go index e91f2f9bf7..4961f29487 100644 --- a/x/ibcratelimit/simulation/operations.go +++ b/x/ibcratelimit/simulation/operations.go @@ -1,23 +1,13 @@ package simulation import ( - "fmt" "math/rand" - sdkmath "cosmossdk.io/math" - - "github.com/cosmos/cosmos-sdk/baseapp" - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" 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" - "github.com/cosmos/cosmos-sdk/x/bank/testutil" "github.com/cosmos/cosmos-sdk/x/simulation" - simappparams "github.com/provenance-io/provenance/app/params" - "github.com/provenance-io/provenance/internal/pioconfig" "github.com/provenance-io/provenance/x/ibcratelimit" "github.com/provenance-io/provenance/x/ibcratelimit/keeper" ) @@ -28,107 +18,22 @@ const ( OpWeightMsgUpdateParams = "op_weight_msg_update_params" ) -// WeightedOperations returns all the operations from the module with their respective weights -func WeightedOperations( - simState module.SimulationState, k keeper.Keeper, ak authkeeper.AccountKeeperI, bk bankkeeper.Keeper, -) simulation.WeightedOperations { - var ( - wMsgUpdateParams int - ) +// ProposalMsgs returns all the governance proposal messages. +func ProposalMsgs(simState module.SimulationState, k *keeper.Keeper) []simtypes.WeightedProposalMsg { + var wMsgUpdateParams int simState.AppParams.GetOrGenerate(OpWeightMsgUpdateParams, &wMsgUpdateParams, nil, - func(_ *rand.Rand) { wMsgUpdateParams = simappparams.DefaultWeightUpdateParams }) - - return simulation.WeightedOperations{ - simulation.NewWeightedOperation(wMsgUpdateParams, SimulateMsgUpdateParams(simState, k, ak, bk)), - } -} - -// SimulateMsgUpdateParams sends a MsgUpdateParams. -func SimulateMsgUpdateParams(simState module.SimulationState, _ keeper.Keeper, ak authkeeper.AccountKeeperI, bk bankkeeper.Keeper) simtypes.Operation { - return func( - r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, - ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { - raccs, err := RandomAccs(r, accs, uint64(len(accs))) - if err != nil { - return simtypes.NoOpMsg(ibcratelimit.ModuleName, sdk.MsgTypeURL(&ibcratelimit.MsgUpdateParamsRequest{}), err.Error()), nil, nil - } - - // 50% chance to be from the module's authority - from := raccs[0] - to := raccs[1] - - msg := ibcratelimit.NewMsgUpdateParamsRequest(from.Address.String(), to.Address.String()) - - // TODO[1760]: Refactor this to submit it as a gov prop and return futures for votes. - return Dispatch(r, app, ctx, simState, from, chainID, msg, ak, bk, nil) - } -} - -// Dispatch sends an operation to the chain using a given account/funds on account for fees. Failures on the server side -// are handled as no-op msg operations with the error string as the status/response. -func Dispatch( - r *rand.Rand, - app *baseapp.BaseApp, - ctx sdk.Context, - simState module.SimulationState, - from simtypes.Account, - chainID string, - msg sdk.Msg, - ak authkeeper.AccountKeeperI, - bk bankkeeper.Keeper, - futures []simtypes.FutureOperation, -) ( - simtypes.OperationMsg, - []simtypes.FutureOperation, - error, -) { - account := ak.GetAccount(ctx, from.Address) - spendable := bk.SpendableCoins(ctx, account.GetAddress()) + func(_ *rand.Rand) { wMsgUpdateParams = simappparams.DefaultWeightIBCRLUpdateParams }) - fees, err := simtypes.RandomFees(r, ctx, spendable) - if err != nil { - return simtypes.NoOpMsg(ibcratelimit.ModuleName, sdk.MsgTypeURL(msg), "unable to generate fees"), nil, err + return []simtypes.WeightedProposalMsg{ + simulation.NewWeightedProposalMsg(OpWeightMsgUpdateParams, wMsgUpdateParams, SimulatePropMsgUpdateParams(k)), } - err = testutil.FundAccount(ctx, bk, account.GetAddress(), sdk.NewCoins(sdk.Coin{ - Denom: pioconfig.GetProvenanceConfig().BondDenom, - Amount: sdkmath.NewInt(1_000_000_000_000_000), - })) - if err != nil { - return simtypes.NoOpMsg(ibcratelimit.ModuleName, sdk.MsgTypeURL(msg), "unable to fund account"), nil, err - } - - tx, err := simtestutil.GenSignedMockTx( - r, - simState.TxConfig, - []sdk.Msg{msg}, - fees, - simtestutil.DefaultGenTxGas, - chainID, - []uint64{account.GetAccountNumber()}, - []uint64{account.GetSequence()}, - from.PrivKey, - ) - if err != nil { - return simtypes.NoOpMsg(ibcratelimit.ModuleName, sdk.MsgTypeURL(msg), "unable to generate mock tx"), nil, err - } - - _, _, err = app.SimDeliver(simState.TxConfig.TxEncoder(), tx) - if err != nil { - return simtypes.NoOpMsg(ibcratelimit.ModuleName, sdk.MsgTypeURL(msg), err.Error()), nil, nil - } - - return simtypes.NewOperationMsg(msg, true, ""), futures, nil } -func RandomAccs(r *rand.Rand, accs []simtypes.Account, count uint64) ([]simtypes.Account, error) { - if uint64(len(accs)) < count { - return nil, fmt.Errorf("cannot choose %d accounts because there are only %d", count, len(accs)) +func SimulatePropMsgUpdateParams(k *keeper.Keeper) simtypes.MsgSimulatorFn { + return func(r *rand.Rand, ctx sdk.Context, accs []simtypes.Account) sdk.Msg { + // change it to a new random account. + raccs := simtypes.RandomAccounts(r, 1) + return ibcratelimit.NewMsgUpdateParamsRequest(k.GetAuthority(), raccs[0].Address.String()) } - raccs := make([]simtypes.Account, 0, len(accs)) - raccs = append(raccs, accs...) - r.Shuffle(len(raccs), func(i, j int) { - raccs[i], raccs[j] = raccs[j], raccs[i] - }) - return raccs[:count], nil } diff --git a/x/ibcratelimit/simulation/operations_test.go b/x/ibcratelimit/simulation/operations_test.go index d9a39c2d58..d16896f197 100644 --- a/x/ibcratelimit/simulation/operations_test.go +++ b/x/ibcratelimit/simulation/operations_test.go @@ -1,10 +1,7 @@ package simulation_test import ( - "bytes" - "fmt" "math/rand" - "strings" "testing" "github.com/stretchr/testify/suite" @@ -12,12 +9,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/x/bank/testutil" "github.com/provenance-io/provenance/app" simappparams "github.com/provenance-io/provenance/app/params" + "github.com/provenance-io/provenance/testutil" "github.com/provenance-io/provenance/x/ibcratelimit" - "github.com/provenance-io/provenance/x/ibcratelimit/simulation" + + . "github.com/provenance-io/provenance/x/ibcratelimit/simulation" ) type SimTestSuite struct { @@ -36,25 +34,6 @@ func (s *SimTestSuite) SetupTest() { s.ctx = s.app.BaseApp.NewContext(false) } -// LogOperationMsg logs all fields of the provided operationMsg. -func (s *SimTestSuite) LogOperationMsg(operationMsg simtypes.OperationMsg, msg string, args ...interface{}) { - msgFmt := "%s" - if len(bytes.TrimSpace(operationMsg.Msg)) == 0 { - msgFmt = " %q" - } - fmtLines := []string{ - fmt.Sprintf(msg, args...), - "operationMsg.Route: %q", - "operationMsg.Name: %q", - "operationMsg.Comment: %q", - "operationMsg.OK: %t", - "operationMsg.Msg: " + msgFmt, - } - s.T().Logf(strings.Join(fmtLines, "\n"), - operationMsg.Route, operationMsg.Name, operationMsg.Comment, operationMsg.OK, string(operationMsg.Msg), - ) -} - // MakeTestSimState creates a new module.SimulationState struct with the fields needed by the functions being tested. func (s *SimTestSuite) MakeTestSimState() module.SimulationState { return module.SimulationState{ @@ -64,141 +43,37 @@ func (s *SimTestSuite) MakeTestSimState() module.SimulationState { } } -func (s *SimTestSuite) TestWeightedOperations() { - weightedOps := simulation.WeightedOperations(s.MakeTestSimState(), *s.app.RateLimitingKeeper, - s.app.AccountKeeper, s.app.BankKeeper, - ) - - // setup 3 accounts - source := rand.NewSource(1) - r := rand.New(source) - accs := s.getTestingAccounts(r, 3) - - expected := []struct { - weight int - opMsgRoute string - opMsgName string - }{ - {simappparams.DefaultWeightUpdateParams, ibcratelimit.ModuleName, sdk.MsgTypeURL(&ibcratelimit.MsgUpdateParamsRequest{})}, - } - - expNames := make([]string, len(expected)) - for i, exp := range expected { - expNames[i] = exp.opMsgName - } - - // Run all the ops and get the operation messages and their names. - opMsgs := make([]simtypes.OperationMsg, len(weightedOps)) - actualNames := make([]string, len(weightedOps)) - for i, w := range weightedOps { - opMsgs[i], _, _ = w.Op()(r, s.app.BaseApp, s.ctx, accs, "") - actualNames[i] = opMsgs[i].Name - } - - // First, make sure the op names are as expected since a failure there probably means the rest will fail. - // And it's probably easier to address when you've got a nice list comparison of names and their orderings. - s.Require().Equal(expNames, actualNames, "operation message names") - - // Now assert that each entry was as expected. - for i := range expected { - s.Assert().Equal(expected[i].weight, weightedOps[i].Weight(), "weightedOps[%d].Weight", i) - s.Assert().Equal(expected[i].opMsgRoute, opMsgs[i].Route, "weightedOps[%d] operationMsg.Route", i) - s.Assert().Equal(expected[i].opMsgName, opMsgs[i].Name, "weightedOps[%d] operationMsg.Name", i) - } +func (s *SimTestSuite) NewSimTestHelper(accCount int) *testutil.SimTestHelper { + return testutil.NewSimTestHelper(s.T(), s.ctx, rand.New(rand.NewSource(1)), s.app). + WithTestingAccounts(accCount) } -func (s *SimTestSuite) TestSimulateMsgUpdateParams() { - // setup 3 accounts - source := rand.NewSource(1) - r := rand.New(source) - accounts := s.getTestingAccounts(r, 3) - - // execute operation - op := simulation.SimulateMsgUpdateParams(s.MakeTestSimState(), *s.app.RateLimitingKeeper, s.app.AccountKeeper, s.app.BankKeeper) - operationMsg, futureOperations, err := op(r, s.app.BaseApp, s.ctx, accounts, "") - s.Require().NoError(err, "SimulateMsgUpdateParams op(...) error") - s.LogOperationMsg(operationMsg, "good") - - var msg ibcratelimit.MsgUpdateParamsRequest - s.Require().NoError(s.app.AppCodec().Unmarshal(operationMsg.Msg, &msg), "UnmarshalJSON(operationMsg.Msg)") - - s.Assert().True(operationMsg.OK, "operationMsg.OK") - s.Assert().Equal(sdk.MsgTypeURL(&msg), operationMsg.Name, "operationMsg.Name") - s.Assert().Equal(ibcratelimit.ModuleName, operationMsg.Route, "operationMsg.Route") - s.Assert().Len(futureOperations, 0, "futureOperations") -} - -func (s *SimTestSuite) TestRandomAccs() { - source := rand.NewSource(1) - r := rand.New(source) - accounts := s.getTestingAccounts(r, 3) - - tests := []struct { - name string - accs []simtypes.Account - expected []simtypes.Account - count uint64 - err string - }{ - { - name: "valid - return nothing when count is 0", - accs: []simtypes.Account{}, - expected: []simtypes.Account{}, - count: 0, - }, - { - name: "valid - return 1 when count is 1", - accs: []simtypes.Account{accounts[0]}, - expected: []simtypes.Account{accounts[0]}, - count: 1, - }, +func (s *SimTestSuite) TestProposalMsgs() { + expected := []testutil.ExpectedProposalMsg{ { - name: "valid - return multiple when count greater than 1", - accs: []simtypes.Account{accounts[0], accounts[1]}, - expected: []simtypes.Account{accounts[1], accounts[0]}, - count: 2, - }, - { - name: "valid - return is limited by count", - accs: []simtypes.Account{accounts[0], accounts[1], accounts[2]}, - expected: []simtypes.Account{accounts[1]}, - count: 1, - }, - { - name: "invalid - return error when count is greater than length", - accs: []simtypes.Account{accounts[0], accounts[1]}, - expected: []simtypes.Account{}, - count: 3, - err: "cannot choose 3 accounts because there are only 2", + Key: OpWeightMsgUpdateParams, + Weight: simappparams.DefaultWeightIBCRLUpdateParams, + MsgType: &ibcratelimit.MsgUpdateParamsRequest{}, }, } - for _, tc := range tests { - s.Run(tc.name, func() { - raccs, err := simulation.RandomAccs(r, tc.accs, tc.count) - if len(tc.err) == 0 { - s.Require().NoError(err, "should have no error for successful RandomAccs") - s.Require().Equal(tc.expected, raccs, "should have correct output for successful RandomAccs") - } else { - s.Require().EqualError(err, tc.err, "should have correct error message for RandomAccs") - } - }) + simState := s.MakeTestSimState() + proposalMsgsFn := func() []simtypes.WeightedProposalMsg { + return ProposalMsgs(simState, s.app.RateLimitingKeeper) } + s.NewSimTestHelper(10).AssertProposalMsgs(expected, proposalMsgsFn) } -func (s *SimTestSuite) getTestingAccounts(r *rand.Rand, n int) []simtypes.Account { - accounts := simtypes.RandomAccounts(r, n) - - initAmt := sdk.TokensFromConsensusPower(1000000, sdk.DefaultPowerReduction) - initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) - - // add coins to the accounts - for _, account := range accounts { - acc := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, account.Address) - s.app.AccountKeeper.SetAccount(s.ctx, acc) - err := testutil.FundAccount(s.ctx, s.app.BankKeeper, account.Address, initCoins) - s.Require().NoError(err) +func (s *SimTestSuite) TestSimulatePropMsgUpdateOracle() { + expMsg := &ibcratelimit.MsgUpdateParamsRequest{ + Authority: s.app.OracleKeeper.GetAuthority(), + Params: ibcratelimit.Params{ + ContractAddress: "cosmos1tnh2q55v8wyygtt9srz5safamzdengsnqeycj3", + }, } - return accounts + simFnMaker := func() simtypes.MsgSimulatorFn { + return SimulatePropMsgUpdateParams(s.app.RateLimitingKeeper) + } + s.NewSimTestHelper(0).AssertMsgSimulatorFn(expMsg, simFnMaker) } diff --git a/x/marker/client/cli/cli_test.go b/x/marker/client/cli/cli_test.go index 34db04c7ee..d557c3bdf7 100644 --- a/x/marker/client/cli/cli_test.go +++ b/x/marker/client/cli/cli_test.go @@ -20,7 +20,6 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" sdktypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" testnet "github.com/cosmos/cosmos-sdk/testutil/network" @@ -54,10 +53,11 @@ const ( type IntegrationTestSuite struct { suite.Suite - cfg testnet.Config - testnet *testnet.Network + cfg testnet.Config + testnet *testnet.Network + keyring keyring.Keyring - keyringDir string + keyringEntries []testutil.TestKeyringEntry accountAddresses []sdk.AccAddress holderDenom string @@ -66,19 +66,8 @@ type IntegrationTestSuite struct { } func (s *IntegrationTestSuite) GenerateAccountsWithKeyrings(number int) { - path := hd.CreateHDPath(118, 0, 0).String() - s.keyringDir = s.T().TempDir() - kr, err := keyring.New(s.T().Name(), "test", s.keyringDir, nil, s.cfg.Codec) - s.Require().NoError(err) - s.keyring = kr - for i := 0; i < number; i++ { - keyId := fmt.Sprintf("test_key%v", i) - info, _, err := kr.NewMnemonic(keyId, keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1) - s.Require().NoError(err) - addr, err := info.GetAddress() - s.Require().NoError(err, "getting keyring address") - s.accountAddresses = append(s.accountAddresses, addr) - } + s.keyringEntries, s.keyring = testutil.GenerateTestKeyring(s.T(), number, s.cfg.Codec) + s.accountAddresses = testutil.GetKeyringEntryAddresses(s.keyringEntries) } func TestIntegrationTestSuite(t *testing.T) { @@ -1098,7 +1087,7 @@ func (s *IntegrationTestSuite) TestMarkerAuthzTxCommands() { defer func() { s.testnet.Validators[0].ClientCtx = curClientCtx }() - s.testnet.Validators[0].ClientCtx = s.testnet.Validators[0].ClientCtx.WithKeyringDir(s.keyringDir).WithKeyring(s.keyring) + s.testnet.Validators[0].ClientCtx = s.testnet.Validators[0].ClientCtx.WithKeyring(s.keyring) testCases := []struct { name string diff --git a/x/marker/simulation/operations_test.go b/x/marker/simulation/operations_test.go index 89f274dd9c..2f6367e602 100644 --- a/x/marker/simulation/operations_test.go +++ b/x/marker/simulation/operations_test.go @@ -15,11 +15,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/x/bank/testutil" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1" "github.com/provenance-io/provenance/app" simappparams "github.com/provenance-io/provenance/app/params" + "github.com/provenance-io/provenance/testutil" "github.com/provenance-io/provenance/testutil/assertions" "github.com/provenance-io/provenance/x/marker/keeper" "github.com/provenance-io/provenance/x/marker/simulation" @@ -220,18 +220,13 @@ func (s *SimTestSuite) TestSimulateMsgAddMarkerProposal() { govMinDep := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 3)) depositPeriod := 1 * time.Second - resetParams := func(t *testing.T, ctx sdk.Context) { - // TODO[1760]: gov: Figure out how to set just the deposit params and uncomment this. - _, _ = govMinDep, depositPeriod - /* - require.NotPanics(s.T(), func() { - s.app.GovKeeper.SetDepositParams(s.ctx, govtypes.DepositParams{ - MinDeposit: govMinDep, - MaxDepositPeriod: &depositPeriod, - }) - }, "gov SetDepositParams") - - */ + resetParams := func() { + params := govtypes.DefaultParams() + params.MinDeposit = govMinDep + params.MaxDepositPeriod = &depositPeriod + assertions.RequireNotPanicsNoError(s.T(), func() error { + return s.app.GovKeeper.Params.Set(s.ctx, params) + }, "reset gov params") } access := types.AccessGrant{ @@ -319,7 +314,7 @@ func (s *SimTestSuite) TestSimulateMsgAddMarkerProposal() { } for _, tc := range tests { - resetParams(s.T(), s.ctx) + resetParams() s.Run(tc.name, func() { args := &simulation.SendGovMsgArgs{ WeightedOpsArgs: *s.getWeightedOpsArgs(), @@ -463,20 +458,7 @@ func (s *SimTestSuite) TestSimulateMsgUpdateSendDenyList() { } func (s *SimTestSuite) getTestingAccounts(r *rand.Rand, n int) []simtypes.Account { - accounts := simtypes.RandomAccounts(r, n) - - initAmt := sdk.TokensFromConsensusPower(1000000, sdk.DefaultPowerReduction) - initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) - - // add coins to the accounts - for _, account := range accounts { - acc := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, account.Address) - s.app.AccountKeeper.SetAccount(s.ctx, acc) - err := testutil.FundAccount(s.ctx, s.app.BankKeeper, account.Address, initCoins) - s.Require().NoError(err) - } - - return accounts + return testutil.GenerateTestingAccounts(s.T(), s.ctx, s.app, r, n) } // getWeightedOpsArgs creates a standard WeightedOpsArgs. @@ -512,17 +494,5 @@ func (s *SimTestSuite) freshCtx() { // createTestingAccountsWithPower creates new accounts with the specified power (coins amount). func (s *SimTestSuite) createTestingAccountsWithPower(r *rand.Rand, count int, power int64) []simtypes.Account { - accounts := simtypes.RandomAccounts(r, count) - - initAmt := sdk.TokensFromConsensusPower(power, sdk.DefaultPowerReduction) - initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) - - // add coins to the accounts - for _, account := range accounts { - acc := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, account.Address) - s.app.AccountKeeper.SetAccount(s.ctx, acc) - s.Require().NoError(testutil.FundAccount(s.ctx, s.app.BankKeeper, account.Address, initCoins)) - } - - return accounts + return testutil.GenerateTestingAccountsWithPower(s.T(), s.ctx, s.app, r, count, power) } diff --git a/x/marker/types/key.go b/x/marker/types/key.go index 370ea0cac3..aba3b35cf8 100644 --- a/x/marker/types/key.go +++ b/x/marker/types/key.go @@ -21,9 +21,6 @@ const ( // CoinPoolName to be used for coin pool associated with mint/burn activities. CoinPoolName = ModuleName - - // DefaultParamspace is the name used for the parameter subspace for this module. - DefaultParamspace = ModuleName ) var ( diff --git a/x/metadata/client/cli/cli_test.go b/x/metadata/client/cli/cli_test.go index 9a9b14d7dc..19fc2b51a2 100644 --- a/x/metadata/client/cli/cli_test.go +++ b/x/metadata/client/cli/cli_test.go @@ -16,7 +16,6 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" @@ -43,11 +42,11 @@ import ( type IntegrationCLITestSuite struct { suite.Suite - cfg testnet.Config - testnet *testnet.Network + cfg testnet.Config + testnet *testnet.Network + keyring keyring.Keyring - keyringDir string - keyringAccounts []keyring.Record + keyringAccounts []testutil.TestKeyringEntry asJson string asText string @@ -497,7 +496,7 @@ owner: %s`, s.testnet, err = testnet.New(s.T(), s.T().TempDir(), s.cfg) s.Require().NoError(err, "creating testnet") - s.testnet.Validators[0].ClientCtx = s.testnet.Validators[0].ClientCtx.WithKeyringDir(s.keyringDir).WithKeyring(s.keyring) + s.testnet.Validators[0].ClientCtx = s.testnet.Validators[0].ClientCtx.WithKeyring(s.keyring) _, err = testutil.WaitForHeight(s.testnet, 1) s.Require().NoError(err, "waiting for height 1") @@ -508,17 +507,7 @@ func (s *IntegrationCLITestSuite) TearDownSuite() { } func (s *IntegrationCLITestSuite) generateAccountsWithKeyrings(number int) { - path := hd.CreateHDPath(118, 0, 0).String() - s.keyringDir = s.T().TempDir() - kr, err := keyring.New(s.T().Name(), "test", s.keyringDir, nil, s.cfg.Codec) - s.Require().NoError(err, "keyring creation") - s.keyring = kr - for i := 0; i < number; i++ { - keyId := fmt.Sprintf("test_key%v", i) - info, _, err := kr.NewMnemonic(keyId, keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1) - s.Require().NoError(err, "key creation") - s.keyringAccounts = append(s.keyringAccounts, *info) - } + s.keyringAccounts, s.keyring = testutil.GenerateTestKeyring(s.T(), number, s.cfg.Codec) } func ownerPartyList(addresses ...string) []metadatatypes.Party { diff --git a/x/msgfees/client/cli/cli_test.go b/x/msgfees/client/cli/cli_test.go index 0291343132..5e5867810f 100644 --- a/x/msgfees/client/cli/cli_test.go +++ b/x/msgfees/client/cli/cli_test.go @@ -12,7 +12,6 @@ import ( cmtcli "github.com/cometbft/cometbft/libs/cli" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" testnet "github.com/cosmos/cosmos-sdk/testutil/network" @@ -34,17 +33,16 @@ type IntegrationTestSuite struct { cfg testnet.Config testnet *testnet.Network + keyring keyring.Keyring + keyringEntries []testutil.TestKeyringEntry + accountAddresses []sdk.AccAddress + accountAddr sdk.AccAddress accountKey *secp256k1.PrivKey account2Addr sdk.AccAddress account2Key *secp256k1.PrivKey acc2NameCount int - - accountAddresses []sdk.AccAddress - - keyring keyring.Keyring - keyringDir string } func TestIntegrationTestSuite(t *testing.T) { @@ -107,25 +105,14 @@ func (s *IntegrationTestSuite) SetupSuite() { s.testnet, err = testnet.New(s.T(), s.T().TempDir(), s.cfg) s.Require().NoError(err, "creating testnet") - s.testnet.Validators[0].ClientCtx = s.testnet.Validators[0].ClientCtx.WithKeyringDir(s.keyringDir).WithKeyring(s.keyring) + s.testnet.Validators[0].ClientCtx = s.testnet.Validators[0].ClientCtx.WithKeyring(s.keyring) _, err = testutil.WaitForHeight(s.testnet, 1) s.Require().NoError(err, "waiting for height 1") } func (s *IntegrationTestSuite) GenerateAccountsWithKeyrings(number int) { - path := hd.CreateHDPath(118, 0, 0).String() - s.keyringDir = s.T().TempDir() - kr, err := keyring.New(s.T().Name(), "test", s.keyringDir, nil, s.cfg.Codec) - s.Require().NoError(err, "Keyring.New") - s.keyring = kr - for i := 0; i < number; i++ { - keyId := fmt.Sprintf("test_key%v", i) - info, _, err := kr.NewMnemonic(keyId, keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1) - s.Require().NoError(err, "Keyring.NewMnemonic") - addr, err := info.GetAddress() - s.Require().NoError(err, "GetAddress") - s.accountAddresses = append(s.accountAddresses, addr) - } + s.keyringEntries, s.keyring = testutil.GenerateTestKeyring(s.T(), number, s.cfg.Codec) + s.accountAddresses = testutil.GetKeyringEntryAddresses(s.keyringEntries) } func (s *IntegrationTestSuite) TearDownSuite() { diff --git a/x/name/simulation/operations.go b/x/name/simulation/operations.go index fd39039d60..6dbcd82281 100644 --- a/x/name/simulation/operations.go +++ b/x/name/simulation/operations.go @@ -14,6 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/simulation" simappparams "github.com/provenance-io/provenance/app/params" + "github.com/provenance-io/provenance/internal/helpers" "github.com/provenance-io/provenance/x/name/keeper" "github.com/provenance-io/provenance/x/name/types" ) @@ -66,7 +67,7 @@ func SimulateMsgBindName(simState module.SimulationState, k keeper.Keeper, ak au return simtypes.NoOpMsg(types.ModuleName, sdk.MsgTypeURL(&types.MsgBindNameRequest{}), "no name records available to create under"), nil, nil } - nameLen := randIntBetween(r, int(params.GetMinSegmentLength()), int(params.GetMaxSegmentLength())) + nameLen := helpers.RandIntBetween(r, int(params.GetMinSegmentLength()), int(params.GetMaxSegmentLength())) newRecordName := simtypes.RandStringOfLength(r, nameLen) newRecordOwner := parentOwner if !parentRecord.Restricted { @@ -200,8 +201,3 @@ func getRandomRecord(r *rand.Rand, ctx sdk.Context, k keeper.Keeper, accs []simt return types.NameRecord{}, simtypes.Account{}, false, nil } - -// randIntBetween generates a random number between min and max inclusive. -func randIntBetween(r *rand.Rand, min, max int) int { - return r.Intn(max-min+1) + min -} diff --git a/x/name/simulation/operations_test.go b/x/name/simulation/operations_test.go index 46993252ba..8f4560e994 100644 --- a/x/name/simulation/operations_test.go +++ b/x/name/simulation/operations_test.go @@ -12,10 +12,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/x/bank/testutil" "github.com/provenance-io/provenance/app" simappparams "github.com/provenance-io/provenance/app/params" + "github.com/provenance-io/provenance/testutil" "github.com/provenance-io/provenance/x/name/simulation" "github.com/provenance-io/provenance/x/name/types" ) @@ -208,18 +208,5 @@ func (s *SimTestSuite) TestSimulateMsgModifyName() { } func (s *SimTestSuite) getTestingAccounts(r *rand.Rand, n int) []simtypes.Account { - accounts := simtypes.RandomAccounts(r, n) - - initAmt := sdk.TokensFromConsensusPower(200, sdk.DefaultPowerReduction) - initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) - - // add coins to the accounts - for i, account := range accounts { - acc := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, account.Address) - s.app.AccountKeeper.SetAccount(s.ctx, acc) - err := testutil.FundAccount(s.ctx, s.app.BankKeeper, account.Address, initCoins) - s.Require().NoError(err, "[%d]: FundAccount", i) - } - - return accounts + return testutil.GenerateTestingAccountsWithPower(s.T(), s.ctx, s.app, r, n, 200) } diff --git a/x/oracle/client/cli/cli_test.go b/x/oracle/client/cli/cli_test.go index f03d562609..cb28768b1d 100644 --- a/x/oracle/client/cli/cli_test.go +++ b/x/oracle/client/cli/cli_test.go @@ -11,7 +11,6 @@ import ( sdkmath "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" @@ -33,15 +32,16 @@ import ( type IntegrationTestSuite struct { suite.Suite - cfg network.Config - network *network.Network - keyring keyring.Keyring - keyringDir string + cfg network.Config + network *network.Network - accountAddr sdk.AccAddress - accountKey *secp256k1.PrivKey + keyring keyring.Keyring + keyringEntries []testutil.TestKeyringEntry accountAddresses []sdk.AccAddress + accountAddr sdk.AccAddress + accountKey *secp256k1.PrivKey + port string oracle string } @@ -98,7 +98,7 @@ func (s *IntegrationTestSuite) SetupSuite() { s.network, err = network.New(s.T(), s.T().TempDir(), s.cfg) s.Require().NoError(err, "network.New") - s.network.Validators[0].ClientCtx = s.network.Validators[0].ClientCtx.WithKeyringDir(s.keyringDir).WithKeyring(s.keyring) + s.network.Validators[0].ClientCtx = s.network.Validators[0].ClientCtx.WithKeyring(s.keyring) _, err = testutil.WaitForHeight(s.network, 6) s.Require().NoError(err, "WaitForHeight") @@ -109,21 +109,8 @@ func (s *IntegrationTestSuite) TearDownSuite() { } func (s *IntegrationTestSuite) GenerateAccountsWithKeyrings(number int) { - path := hd.CreateHDPath(118, 0, 0).String() - s.keyringDir = s.T().TempDir() - kr, err := keyring.New(s.T().Name(), "test", s.keyringDir, nil, s.cfg.Codec) - s.Require().NoError(err, "Keyring.New") - s.keyring = kr - for i := 0; i < number; i++ { - keyId := fmt.Sprintf("test_key%v", i) - info, _, err := kr.NewMnemonic(keyId, keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1) - s.Require().NoError(err, "Keyring.NewMneomonic") - addr, err := info.GetAddress() - if err != nil { - panic(err) - } - s.accountAddresses = append(s.accountAddresses, addr) - } + s.keyringEntries, s.keyring = testutil.GenerateTestKeyring(s.T(), number, s.cfg.Codec) + s.accountAddresses = testutil.GetKeyringEntryAddresses(s.keyringEntries) } func (s *IntegrationTestSuite) TestQueryOracleAddress() { diff --git a/x/oracle/module/module.go b/x/oracle/module/module.go index d5882534e9..55db9c89a5 100644 --- a/x/oracle/module/module.go +++ b/x/oracle/module/module.go @@ -33,6 +33,7 @@ import ( var ( _ module.AppModuleBasic = (*AppModule)(nil) _ module.AppModuleSimulation = (*AppModule)(nil) + _ module.HasProposalMsgs = (*AppModule)(nil) _ appmodule.AppModule = (*AppModule)(nil) ) @@ -140,6 +141,11 @@ func (am AppModule) WeightedOperations(simState module.SimulationState) []simtyp return simulation.WeightedOperations(simState, am.keeper, am.accountKeeper, am.bankKeeper, am.channelKeeper) } +// ProposalMsgs returns all the msgs to execute as governance proposals. +func (am AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg { + return simulation.ProposalMsgs(simState, am.keeper) +} + // Name returns the oracle module's name. func (AppModule) Name() string { return types.ModuleName diff --git a/x/oracle/simulation/genesis.go b/x/oracle/simulation/genesis.go index 4c7f553408..1c90f83e6d 100644 --- a/x/oracle/simulation/genesis.go +++ b/x/oracle/simulation/genesis.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/provenance-io/provenance/internal/helpers" "github.com/provenance-io/provenance/x/oracle/types" ) @@ -21,14 +22,14 @@ func PortFn(r *rand.Rand) string { if r.Intn(2) > 0 { return "oracle" } - length := uint64(randIntBetween(r, 6, 10)) + length := uint64(helpers.RandIntBetween(r, 6, 10)) return strings.ToLower(simtypes.RandStringOfLength(r, int(length))) } // OracleFn randomized oracle address func OracleFn(r *rand.Rand, accs []simtypes.Account) string { - randomAccount, _ := RandomAccs(r, accs, 1) - if r.Intn(2) > 0 { + randomAccount, _ := helpers.SelectRandomAccounts(r, accs, 1) + if r.Intn(2) > 0 || len(randomAccount) == 0 { return "" } return randomAccount[0].Address.String() @@ -58,11 +59,6 @@ func RandomizedGenState(simState *module.SimulationState) { fmt.Printf("Selected randomly generated oracle parameters:\n%s\n", bz) } -// randIntBetween generates a random number between min and max inclusive. -func randIntBetween(r *rand.Rand, min, max int) int { - return r.Intn(max-min+1) + min -} - // RandomChannel returns a random channel func RandomChannel(r *rand.Rand) string { channelNumber := r.Intn(1000) diff --git a/x/oracle/simulation/genesis_test.go b/x/oracle/simulation/genesis_test.go index 7486b29f82..e038c4beee 100644 --- a/x/oracle/simulation/genesis_test.go +++ b/x/oracle/simulation/genesis_test.go @@ -5,13 +5,15 @@ import ( "math/rand" "testing" + "github.com/stretchr/testify/assert" + "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/provenance-io/provenance/x/oracle/simulation" "github.com/provenance-io/provenance/x/oracle/types" - "github.com/stretchr/testify/assert" ) func TestPortFn(t *testing.T) { @@ -51,13 +53,13 @@ func TestOracleFn(t *testing.T) { }{ { name: "success - returns an empty account", - seed: 0, + seed: 3, accounts: accs, expected: "", }, { name: "success - returns a random account", - seed: 3, + seed: 0, accounts: accs, expected: "cosmos1tp4es44j4vv8m59za3z0tm64dkmlnm8wg2frhc", }, diff --git a/x/oracle/simulation/operations.go b/x/oracle/simulation/operations.go index 6705d77760..ef6ad7692b 100644 --- a/x/oracle/simulation/operations.go +++ b/x/oracle/simulation/operations.go @@ -18,6 +18,7 @@ import ( channelkeeper "github.com/cosmos/ibc-go/v8/modules/core/04-channel/keeper" simappparams "github.com/provenance-io/provenance/app/params" + "github.com/provenance-io/provenance/internal/helpers" "github.com/provenance-io/provenance/internal/pioconfig" "github.com/provenance-io/provenance/x/oracle/keeper" "github.com/provenance-io/provenance/x/oracle/types" @@ -35,40 +36,33 @@ const ( func WeightedOperations( simState module.SimulationState, k keeper.Keeper, ak authkeeper.AccountKeeperI, bk bankkeeper.Keeper, ck channelkeeper.Keeper, ) simulation.WeightedOperations { - var ( - wMsgUpdateOracle int - wMsgSendOracleQuery int - ) + var wMsgSendOracleQuery int - simState.AppParams.GetOrGenerate(OpWeightMsgUpdateOracle, &wMsgUpdateOracle, nil, - func(_ *rand.Rand) { wMsgUpdateOracle = simappparams.DefaultWeightUpdateOracle }) simState.AppParams.GetOrGenerate(OpWeightMsgSendOracleQuery, &wMsgSendOracleQuery, nil, func(_ *rand.Rand) { wMsgSendOracleQuery = simappparams.DefaultWeightSendOracleQuery }) return simulation.WeightedOperations{ - simulation.NewWeightedOperation(wMsgUpdateOracle, SimulateMsgUpdateOracle(simState, k, ak, bk)), simulation.NewWeightedOperation(wMsgSendOracleQuery, SimulateMsgSendQueryOracle(simState, k, ak, bk, ck)), } } -// SimulateMsgUpdateOracle sends a MsgUpdateOracle. -func SimulateMsgUpdateOracle(simState module.SimulationState, _ keeper.Keeper, ak authkeeper.AccountKeeperI, bk bankkeeper.Keeper) simtypes.Operation { - return func( - r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, - ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { - raccs, err := RandomAccs(r, accs, uint64(len(accs))) - if err != nil { - return simtypes.NoOpMsg(types.ModuleName, sdk.MsgTypeURL(&types.MsgUpdateOracleRequest{}), err.Error()), nil, nil - } +// ProposalMsgs returns all the governance proposal messages. +func ProposalMsgs(simState module.SimulationState, k keeper.Keeper) []simtypes.WeightedProposalMsg { + var wMsgUpdateOracle int - // 50% chance to be from the module's authority - from := raccs[0] - to := raccs[1] + simState.AppParams.GetOrGenerate(OpWeightMsgUpdateOracle, &wMsgUpdateOracle, nil, + func(_ *rand.Rand) { wMsgUpdateOracle = simappparams.DefaultWeightUpdateOracle }) - // TODO[1760]: Submit this as a gov prop and also return futures for the votes. - msg := types.NewMsgUpdateOracle(from.Address.String(), to.Address.String()) + return []simtypes.WeightedProposalMsg{ + simulation.NewWeightedProposalMsg(OpWeightMsgUpdateOracle, wMsgUpdateOracle, SimulatePropMsgUpdateOracle(k)), + } +} - return Dispatch(r, app, ctx, simState, from, chainID, msg, ak, bk, nil) +func SimulatePropMsgUpdateOracle(k keeper.Keeper) simtypes.MsgSimulatorFn { + return func(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) sdk.Msg { + // change it to a new random account. + raccs := simtypes.RandomAccounts(r, 1) + return types.NewMsgUpdateOracle(k.GetAuthority(), raccs[0].Address.String()) } } @@ -77,7 +71,7 @@ func SimulateMsgSendQueryOracle(simState module.SimulationState, _ keeper.Keeper return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { - raccs, err := RandomAccs(r, accs, 1) + raccs, err := helpers.SelectRandomAccounts(r, accs, 1) if err != nil { return simtypes.NoOpMsg(types.ModuleName, sdk.MsgTypeURL(&types.MsgSendQueryOracleRequest{}), err.Error()), nil, nil @@ -151,18 +145,6 @@ func Dispatch( return simtypes.NewOperationMsg(msg, true, ""), futures, nil } -func RandomAccs(r *rand.Rand, accs []simtypes.Account, count uint64) ([]simtypes.Account, error) { - if uint64(len(accs)) < count { - return nil, fmt.Errorf("cannot choose %d accounts because there are only %d", count, len(accs)) - } - raccs := make([]simtypes.Account, 0, len(accs)) - raccs = append(raccs, accs...) - r.Shuffle(len(raccs), func(i, j int) { - raccs[i], raccs[j] = raccs[j], raccs[i] - }) - return raccs[:count], nil -} - func randomChannel(r *rand.Rand, ctx sdk.Context, ck channelkeeper.Keeper) (string, error) { channels := ck.GetAllChannels(ctx) if len(channels) == 0 { @@ -173,7 +155,7 @@ func randomChannel(r *rand.Rand, ctx sdk.Context, ck channelkeeper.Keeper) (stri } func randomQuery(r *rand.Rand) []byte { - queryType := randIntBetween(r, 0, 3) + queryType := helpers.RandIntBetween(r, 0, 3) var query string switch queryType { case 0: diff --git a/x/oracle/simulation/operations_test.go b/x/oracle/simulation/operations_test.go index 8c44c19e5d..ac37e0e65b 100644 --- a/x/oracle/simulation/operations_test.go +++ b/x/oracle/simulation/operations_test.go @@ -1,10 +1,7 @@ package simulation_test import ( - "bytes" - "fmt" "math/rand" - "strings" "testing" "github.com/stretchr/testify/suite" @@ -12,12 +9,14 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/x/bank/testutil" + "github.com/cosmos/cosmos-sdk/x/simulation" "github.com/provenance-io/provenance/app" simappparams "github.com/provenance-io/provenance/app/params" - "github.com/provenance-io/provenance/x/oracle/simulation" + "github.com/provenance-io/provenance/testutil" "github.com/provenance-io/provenance/x/oracle/types" + + . "github.com/provenance-io/provenance/x/oracle/simulation" ) type SimTestSuite struct { @@ -36,23 +35,8 @@ func (s *SimTestSuite) SetupTest() { s.ctx = s.app.BaseApp.NewContext(false) } -// LogOperationMsg logs all fields of the provided operationMsg. -func (s *SimTestSuite) LogOperationMsg(operationMsg simtypes.OperationMsg, msg string, args ...interface{}) { - msgFmt := "%s" - if len(bytes.TrimSpace(operationMsg.Msg)) == 0 { - msgFmt = " %q" - } - fmtLines := []string{ - fmt.Sprintf(msg, args...), - "operationMsg.Route: %q", - "operationMsg.Name: %q", - "operationMsg.Comment: %q", - "operationMsg.OK: %t", - "operationMsg.Msg: " + msgFmt, - } - s.T().Logf(strings.Join(fmtLines, "\n"), - operationMsg.Route, operationMsg.Name, operationMsg.Comment, operationMsg.OK, string(operationMsg.Msg), - ) +func (s *SimTestSuite) getTestingAccounts(r *rand.Rand, n int) []simtypes.Account { + return testutil.GenerateTestingAccounts(s.T(), s.ctx, s.app, r, n) } // MakeTestSimState creates a new module.SimulationState struct with the fields needed by the functions being tested. @@ -64,163 +48,61 @@ func (s *SimTestSuite) MakeTestSimState() module.SimulationState { } } +func (s *SimTestSuite) NewSimTestHelper(accCount int) *testutil.SimTestHelper { + return testutil.NewSimTestHelper(s.T(), s.ctx, rand.New(rand.NewSource(1)), s.app). + WithTestingAccounts(accCount) +} + func (s *SimTestSuite) TestWeightedOperations() { - weightedOps := simulation.WeightedOperations(s.MakeTestSimState(), s.app.OracleKeeper, - s.app.AccountKeeper, s.app.BankKeeper, s.app.IBCKeeper.ChannelKeeper, - ) - - // setup 3 accounts - source := rand.NewSource(1) - r := rand.New(source) - accs := s.getTestingAccounts(r, 3) - - expected := []struct { - weight int - opMsgRoute string - opMsgName string - }{ - {weight: simappparams.DefaultWeightUpdateOracle, opMsgRoute: types.ModuleName, opMsgName: sdk.MsgTypeURL(&types.MsgUpdateOracleRequest{})}, - {weight: simappparams.DefaultWeightSendOracleQuery, opMsgRoute: types.ModuleName, opMsgName: sdk.MsgTypeURL(&types.MsgSendQueryOracleRequest{})}, + expected := []testutil.ExpectedWeightedOp{ + {Weight: simappparams.DefaultWeightSendOracleQuery, Route: types.ModuleName, MsgType: &types.MsgSendQueryOracleRequest{}}, } - expNames := make([]string, len(expected)) - for i, exp := range expected { - expNames[i] = exp.opMsgName + simState := s.MakeTestSimState() + wOpsFn := func() simulation.WeightedOperations { + return WeightedOperations(simState, s.app.OracleKeeper, + s.app.AccountKeeper, s.app.BankKeeper, s.app.IBCKeeper.ChannelKeeper) } + s.NewSimTestHelper(3).AssertWeightedOperations(expected, wOpsFn) +} - // Run all the ops and get the operation messages and their names. - opMsgs := make([]simtypes.OperationMsg, len(weightedOps)) - actualNames := make([]string, len(weightedOps)) - for i, w := range weightedOps { - opMsgs[i], _, _ = w.Op()(r, s.app.BaseApp, s.ctx, accs, "") - actualNames[i] = opMsgs[i].Name +func (s *SimTestSuite) TestProposalMsgs() { + expected := []testutil.ExpectedProposalMsg{ + {Key: OpWeightMsgUpdateOracle, Weight: simappparams.DefaultWeightUpdateOracle, MsgType: &types.MsgUpdateOracleRequest{}}, } - // First, make sure the op names are as expected since a failure there probably means the rest will fail. - // And it's probably easier to address when you've got a nice list comparison of names and their orderings. - s.Require().Equal(expNames, actualNames, "operation message names") - - // Now assert that each entry was as expected. - for i := range expected { - s.Assert().Equal(expected[i].weight, weightedOps[i].Weight(), "weightedOps[%d].Weight", i) - s.Assert().Equal(expected[i].opMsgRoute, opMsgs[i].Route, "weightedOps[%d] operationMsg.Route", i) - s.Assert().Equal(expected[i].opMsgName, opMsgs[i].Name, "weightedOps[%d] operationMsg.Name", i) + simState := s.MakeTestSimState() + proposalMsgsFn := func() []simtypes.WeightedProposalMsg { + return ProposalMsgs(simState, s.app.OracleKeeper) } + s.NewSimTestHelper(10).AssertProposalMsgs(expected, proposalMsgsFn) } -func (s *SimTestSuite) TestSimulateMsgUpdateOracle() { - // setup 3 accounts - source := rand.NewSource(1) - r := rand.New(source) - accounts := s.getTestingAccounts(r, 3) - - // execute operation - op := simulation.SimulateMsgUpdateOracle(s.MakeTestSimState(), s.app.OracleKeeper, s.app.AccountKeeper, s.app.BankKeeper) - operationMsg, futureOperations, err := op(r, s.app.BaseApp, s.ctx, accounts, "") - s.Require().NoError(err, "SimulateMsgUpdateOracle op(...) error") - s.LogOperationMsg(operationMsg, "good") - - var msg types.MsgUpdateOracleRequest - s.Require().NoError(s.app.AppCodec().Unmarshal(operationMsg.Msg, &msg), "UnmarshalJSON(operationMsg.Msg)") - - s.Assert().True(operationMsg.OK, "operationMsg.OK") - s.Assert().Equal(sdk.MsgTypeURL(&msg), operationMsg.Name, "operationMsg.Name") - s.Assert().Equal(types.ModuleName, operationMsg.Route, "operationMsg.Route") - s.Assert().Len(futureOperations, 0, "futureOperations") -} - -func (s *SimTestSuite) TestSimulateMsgSendQueryOracle() { - // setup 3 accounts - source := rand.NewSource(1) - r := rand.New(source) - accounts := s.getTestingAccounts(r, 3) - - // execute operation - op := simulation.SimulateMsgSendQueryOracle(s.MakeTestSimState(), s.app.OracleKeeper, s.app.AccountKeeper, s.app.BankKeeper, s.app.IBCKeeper.ChannelKeeper) - operationMsg, futureOperations, err := op(r, s.app.BaseApp, s.ctx, accounts, "") - s.Require().NoError(err, "SimulateMsgSendQueryOracle op(...) error") - s.LogOperationMsg(operationMsg, "good") - - var msg types.MsgSendQueryOracleRequest - s.Require().NoError(s.app.AppCodec().Unmarshal(operationMsg.Msg, &msg), "UnmarshalJSON(operationMsg.Msg)") - - s.Assert().True(operationMsg.OK, "operationMsg.OK") - s.Assert().Equal(sdk.MsgTypeURL(&msg), operationMsg.Name, "operationMsg.Name") - s.Assert().Equal(types.ModuleName, operationMsg.Route, "operationMsg.Route") - s.Assert().Len(futureOperations, 0, "futureOperations") -} - -func (s *SimTestSuite) TestRandomAccs() { - source := rand.NewSource(1) - r := rand.New(source) - accounts := s.getTestingAccounts(r, 3) - - tests := []struct { - name string - accs []simtypes.Account - expected []simtypes.Account - count uint64 - err string - }{ - { - name: "valid - return nothing when count is 0", - accs: []simtypes.Account{}, - expected: []simtypes.Account{}, - count: 0, - }, - { - name: "valid - return 1 when count is 1", - accs: []simtypes.Account{accounts[0]}, - expected: []simtypes.Account{accounts[0]}, - count: 1, - }, - { - name: "valid - return multiple when count greater than 1", - accs: []simtypes.Account{accounts[0], accounts[1]}, - expected: []simtypes.Account{accounts[1], accounts[0]}, - count: 2, - }, - { - name: "valid - return is limited by count", - accs: []simtypes.Account{accounts[0], accounts[1], accounts[2]}, - expected: []simtypes.Account{accounts[1]}, - count: 1, - }, - { - name: "invalid - return error when count is greater than length", - accs: []simtypes.Account{accounts[0], accounts[1]}, - expected: []simtypes.Account{}, - count: 3, - err: "cannot choose 3 accounts because there are only 2", - }, +func (s *SimTestSuite) TestSimulatePropMsgUpdateOracle() { + // This expected Address might change if use of the randomizer changes (e.g. generating more accounts). + expMsg := &types.MsgUpdateOracleRequest{ + Address: "cosmos1tnh2q55v8wyygtt9srz5safamzdengsnqeycj3", + Authority: s.app.OracleKeeper.GetAuthority(), } - for _, tc := range tests { - s.Run(tc.name, func() { - raccs, err := simulation.RandomAccs(r, tc.accs, tc.count) - if len(tc.err) == 0 { - s.Require().NoError(err, "should have no error for successful RandomAccs") - s.Require().Equal(tc.expected, raccs, "should have correct output for successful RandomAccs") - } else { - s.Require().EqualError(err, tc.err, "should have correct error message for RandomAccs") - } - }) + simFnMaker := func() simtypes.MsgSimulatorFn { + return SimulatePropMsgUpdateOracle(s.app.OracleKeeper) } + s.NewSimTestHelper(0).AssertMsgSimulatorFn(expMsg, simFnMaker) } -func (s *SimTestSuite) getTestingAccounts(r *rand.Rand, n int) []simtypes.Account { - accounts := simtypes.RandomAccounts(r, n) - - initAmt := sdk.TokensFromConsensusPower(1000000, sdk.DefaultPowerReduction) - initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) - - // add coins to the accounts - for _, account := range accounts { - acc := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, account.Address) - s.app.AccountKeeper.SetAccount(s.ctx, acc) - err := testutil.FundAccount(s.ctx, s.app.BankKeeper, account.Address, initCoins) - s.Require().NoError(err) +func (s *SimTestSuite) TestSimulateMsgSendQueryOracle() { + expected := testutil.ExpectedOp{ + Route: types.ModuleName, + EmptyMsg: &types.MsgSendQueryOracleRequest{}, + Comment: "cannot get random channel because none exist", + OK: false, } - return accounts + simState := s.MakeTestSimState() + opMaker := func() simtypes.Operation { + return SimulateMsgSendQueryOracle(simState, s.app.OracleKeeper, + s.app.AccountKeeper, s.app.BankKeeper, s.app.IBCKeeper.ChannelKeeper) + } + s.NewSimTestHelper(3).AssertSimOp(expected, opMaker, "no channel") } diff --git a/x/quarantine/simulation/operations_test.go b/x/quarantine/simulation/operations_test.go index 963a1c1a26..6fa3885509 100644 --- a/x/quarantine/simulation/operations_test.go +++ b/x/quarantine/simulation/operations_test.go @@ -10,9 +10,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/x/bank/testutil" "github.com/provenance-io/provenance/app" + "github.com/provenance-io/provenance/testutil" "github.com/provenance-io/provenance/x/quarantine" "github.com/provenance-io/provenance/x/quarantine/simulation" ) @@ -29,19 +29,7 @@ func TestSimTestSuite(t *testing.T) { } func (s *SimTestSuite) getTestingAccounts(r *rand.Rand, n int) []simtypes.Account { - accounts := simtypes.RandomAccounts(r, n) - - initAmt := sdk.TokensFromConsensusPower(200, sdk.DefaultPowerReduction) - initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) - - // add coins to the accounts - for _, account := range accounts { - acc := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, account.Address) - s.app.AccountKeeper.SetAccount(s.ctx, acc) - s.Require().NoError(testutil.FundAccount(s.ctx, s.app.BankKeeper, account.Address, initCoins)) - } - - return accounts + return testutil.GenerateTestingAccountsWithPower(s.T(), s.ctx, s.app, r, n, 200) } func (s *SimTestSuite) SetupTest() { diff --git a/x/sanction/client/testutil/cli_test.go b/x/sanction/client/testutil/cli_test.go index 2275b80df3..1c4b5cac91 100644 --- a/x/sanction/client/testutil/cli_test.go +++ b/x/sanction/client/testutil/cli_test.go @@ -12,18 +12,13 @@ import ( cmtcli "github.com/cometbft/cometbft/libs/cli" - sdkmath "cosmossdk.io/math" - "github.com/cosmos/cosmos-sdk/client/flags" codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/testutil/cli" - sdk "github.com/cosmos/cosmos-sdk/types" govcli "github.com/cosmos/cosmos-sdk/x/gov/client/cli" - gov "github.com/cosmos/cosmos-sdk/x/gov/types" govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" - "github.com/provenance-io/provenance/internal/pioconfig" "github.com/provenance-io/provenance/testutil" testcli "github.com/provenance-io/provenance/testutil/cli" "github.com/provenance-io/provenance/testutil/queries" @@ -34,60 +29,7 @@ import ( const blocksPerVotingPeriod = 8 func TestIntegrationTestSuite(t *testing.T) { - pioconfig.SetProvenanceConfig(sdk.DefaultBondDenom, 0) - govv1.DefaultMinDepositRatio = sdkmath.LegacyZeroDec() - cfg := testutil.DefaultTestNetworkConfig() - cfg.NumValidators = 5 - // cfg.TimeoutCommit = time.Millisecond * msPerBlock - - // Define some stuff in the sanction genesis state. - sanctionedAddr1 := sdk.AccAddress("1_sanctioned_address_") - sanctionedAddr2 := sdk.AccAddress("2_sanctioned_address_") - tempSanctAddr := sdk.AccAddress("temp_sanctioned_addr") - tempUnsanctAddr := sdk.AccAddress("temp_unsanctioned___") - sanctionGenBz := cfg.GenesisState[sanction.ModuleName] - var sanctionGen sanction.GenesisState - if len(sanctionGenBz) > 0 { - cfg.Codec.MustUnmarshalJSON(sanctionGenBz, &sanctionGen) - } - sanctionGen.SanctionedAddresses = append(sanctionGen.SanctionedAddresses, - sanctionedAddr1.String(), - sanctionedAddr2.String(), - ) - sanctionGen.TemporaryEntries = append(sanctionGen.TemporaryEntries, - &sanction.TemporaryEntry{ - Address: tempSanctAddr.String(), - ProposalId: 1, - Status: sanction.TEMP_STATUS_SANCTIONED, - }, - &sanction.TemporaryEntry{ - Address: tempUnsanctAddr.String(), - ProposalId: 1, - Status: sanction.TEMP_STATUS_UNSANCTIONED, - }, - ) - sanctionGen.Params = &sanction.Params{ - ImmediateSanctionMinDeposit: sdk.NewCoins(sdk.NewInt64Coin(cfg.BondDenom, 52)), - ImmediateUnsanctionMinDeposit: sdk.NewCoins(sdk.NewInt64Coin(cfg.BondDenom, 133)), - } - cfg.GenesisState[sanction.ModuleName] = cfg.Codec.MustMarshalJSON(&sanctionGen) - - // Tweak the gov params too to make testing gov props easier. - // MinDeposit: 6stake (default is 10000000stake) - // MaxDepositPeriod: 5s (default is 48h) - // VotingPeriod: 5s (default is 48h) - govGenBz := cfg.GenesisState[gov.ModuleName] - var govGen govv1.GenesisState - if len(govGenBz) > 0 { - cfg.Codec.MustUnmarshalJSON(govGenBz, &govGen) - } - govGen.Params.MinDeposit = sdk.NewCoins(sdk.NewInt64Coin(cfg.BondDenom, 6)) - votingPeriod := cfg.TimeoutCommit * blocksPerVotingPeriod - govGen.Params.MaxDepositPeriod = &votingPeriod - govGen.Params.VotingPeriod = &votingPeriod - cfg.GenesisState[gov.ModuleName] = cfg.Codec.MustMarshalJSON(&govGen) - - suite.Run(t, NewIntegrationTestSuite(cfg, &sanctionGen)) + suite.Run(t, new(IntegrationTestSuite)) } func (s *IntegrationTestSuite) TestSanctionValidatorImmediateUsingGovCmds() { diff --git a/x/sanction/client/testutil/common_test.go b/x/sanction/client/testutil/common_test.go index e0fb1eab07..cf80314c60 100644 --- a/x/sanction/client/testutil/common_test.go +++ b/x/sanction/client/testutil/common_test.go @@ -5,11 +5,16 @@ import ( "github.com/stretchr/testify/suite" + sdkmath "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/testutil/network" sdk "github.com/cosmos/cosmos-sdk/types" + gov "github.com/cosmos/cosmos-sdk/x/gov/types" + govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + "github.com/provenance-io/provenance/internal/pioconfig" "github.com/provenance-io/provenance/testutil" "github.com/provenance-io/provenance/testutil/assertions" "github.com/provenance-io/provenance/testutil/queries" @@ -25,24 +30,61 @@ type IntegrationTestSuite struct { commonArgs []string valAddr sdk.AccAddress - authority string sanctionGenesis *sanction.GenesisState } -func NewIntegrationTestSuite(cfg network.Config, sanctionGenesis *sanction.GenesisState) *IntegrationTestSuite { - return &IntegrationTestSuite{ - cfg: cfg, - sanctionGenesis: sanctionGenesis, - } -} - func (s *IntegrationTestSuite) SetupSuite() { s.T().Log("setting up integration test suite") + pioconfig.SetProvenanceConfig(sdk.DefaultBondDenom, 0) + govv1.DefaultMinDepositRatio = sdkmath.LegacyZeroDec() + s.cfg = testutil.DefaultTestNetworkConfig() + s.cfg.NumValidators = 5 // enough for voting and maybe sanctioning one. + + // Define some stuff in the santion genesis state. + testutil.MutateGenesisState(s.T(), &s.cfg, sanction.ModuleName, &sanction.GenesisState{}, func(sanctionGen *sanction.GenesisState) *sanction.GenesisState { + sanctionedAddr1 := sdk.AccAddress("1_sanctioned_address_") + sanctionedAddr2 := sdk.AccAddress("2_sanctioned_address_") + tempSanctAddr := sdk.AccAddress("temp_sanctioned_addr") + tempUnsanctAddr := sdk.AccAddress("temp_unsanctioned___") + + sanctionGen.SanctionedAddresses = append(sanctionGen.SanctionedAddresses, + sanctionedAddr1.String(), + sanctionedAddr2.String(), + ) + sanctionGen.TemporaryEntries = append(sanctionGen.TemporaryEntries, + &sanction.TemporaryEntry{ + Address: tempSanctAddr.String(), + ProposalId: 1, + Status: sanction.TEMP_STATUS_SANCTIONED, + }, + &sanction.TemporaryEntry{ + Address: tempUnsanctAddr.String(), + ProposalId: 1, + Status: sanction.TEMP_STATUS_UNSANCTIONED, + }, + ) + sanctionGen.Params = &sanction.Params{ + ImmediateSanctionMinDeposit: sdk.NewCoins(sdk.NewInt64Coin(s.cfg.BondDenom, 52)), + ImmediateUnsanctionMinDeposit: sdk.NewCoins(sdk.NewInt64Coin(s.cfg.BondDenom, 133)), + } + + s.sanctionGenesis = sanctionGen + return sanctionGen + }) + + // Tweak the gov params too to make testing gov props easier. + testutil.MutateGenesisState(s.T(), &s.cfg, gov.ModuleName, &govv1.GenesisState{}, func(govGen *govv1.GenesisState) *govv1.GenesisState { + govGen.Params.MinDeposit = sdk.NewCoins(sdk.NewInt64Coin(s.cfg.BondDenom, 6)) // default is 10000000stake + votingPeriod := s.cfg.TimeoutCommit * blocksPerVotingPeriod + govGen.Params.MaxDepositPeriod = &votingPeriod // default is 48h + govGen.Params.VotingPeriod = &votingPeriod // default is 48h + return govGen + }) var err error s.network, err = network.New(s.T(), s.T().TempDir(), s.cfg) - s.Require().NoError(err) + s.Require().NoError(err, "network.New(...)") s.waitForHeight(1) @@ -87,6 +129,7 @@ func (s *IntegrationTestSuite) getAuthority() string { return acct.GetAddress().String() } +// logHeight outputs the current height to the test log. func (s *IntegrationTestSuite) logHeight() int64 { height, err := testutil.LatestHeight(s.network) s.Require().NoError(err, "LatestHeight()") @@ -94,6 +137,7 @@ func (s *IntegrationTestSuite) logHeight() int64 { return height } +// waitForHeight waits for the requested height, logging the current height once we get there. func (s *IntegrationTestSuite) waitForHeight(height int64) int64 { rv, err := testutil.WaitForHeight(s.network, height) s.Require().NoError(err, "WaitForHeight(%d)", height) @@ -101,6 +145,7 @@ func (s *IntegrationTestSuite) waitForHeight(height int64) int64 { return rv } +// waitForNextBlock waits for the current height to be finished. func (s *IntegrationTestSuite) waitForNextBlock(msgAndArgs ...interface{}) { if len(msgAndArgs) == 0 { msgAndArgs = append(msgAndArgs, "WaitForNextBlock") diff --git a/x/sanction/module/module.go b/x/sanction/module/module.go index 30e8b532d5..113d04f6c4 100644 --- a/x/sanction/module/module.go +++ b/x/sanction/module/module.go @@ -30,6 +30,7 @@ import ( var ( _ module.AppModuleBasic = AppModuleBasic{} _ module.AppModuleSimulation = AppModule{} + _ module.HasProposalMsgs = AppModule{} _ appmodule.AppModule = AppModule{} ) @@ -162,3 +163,11 @@ func (am AppModule) WeightedOperations(simState module.SimulationState) []simtyp am.accKeeper, am.bankKeeper, am.govKeeper, am.keeper, ) } + +// ProposalMsgs returns all the msgs to execute as governance proposals. +func (am AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg { + return simulation.ProposalMsgs( + simState, codec.NewProtoCodec(am.registry), + am.accKeeper, am.bankKeeper, am.govKeeper, am.keeper, + ) +} diff --git a/x/sanction/simulation/operations.go b/x/sanction/simulation/operations.go index f76d11d8e1..75797baa8e 100644 --- a/x/sanction/simulation/operations.go +++ b/x/sanction/simulation/operations.go @@ -76,7 +76,6 @@ func WeightedOperations( wSanctionImmediate int wUnsanction int wUnsanctionImmediate int - wUpdateParams int ) simState.AppParams.GetOrGenerate(OpWeightSanction, &wSanction, nil, @@ -87,15 +86,34 @@ func WeightedOperations( func(_ *rand.Rand) { wUnsanction = DefaultWeightUnsanction }) simState.AppParams.GetOrGenerate(OpWeightUnsanctionImmediate, &wUnsanctionImmediate, nil, func(_ *rand.Rand) { wUnsanctionImmediate = DefaultWeightUnsanctionImmediate }) - simState.AppParams.GetOrGenerate(OpWeightUpdateParams, &wUpdateParams, nil, - func(_ *rand.Rand) { wUpdateParams = DefaultWeightUpdateParams }) return simulation.WeightedOperations{ simulation.NewWeightedOperation(wSanction, SimulateGovMsgSanction(args)), simulation.NewWeightedOperation(wSanctionImmediate, SimulateGovMsgSanctionImmediate(args)), simulation.NewWeightedOperation(wUnsanction, SimulateGovMsgUnsanction(args)), simulation.NewWeightedOperation(wUnsanctionImmediate, SimulateGovMsgUnsanctionImmediate(args)), - simulation.NewWeightedOperation(wUpdateParams, SimulateGovMsgUpdateParams(args)), + } +} + +func ProposalMsgs( + simState module.SimulationState, protoCodec *codec.ProtoCodec, + ak sanction.AccountKeeper, bk sanction.BankKeeper, gk govkeeper.Keeper, sk keeper.Keeper, +) []simtypes.WeightedProposalMsg { + args := &WeightedOpsArgs{ + SimState: simState, + ProtoCodec: protoCodec, + AK: ak, + BK: bk, + GK: gk, + SK: &sk, + } + + var wUpdateParams int + simState.AppParams.GetOrGenerate(OpWeightUpdateParams, &wUpdateParams, nil, + func(_ *rand.Rand) { wUpdateParams = DefaultWeightUpdateParams }) + + return []simtypes.WeightedProposalMsg{ + simulation.NewWeightedProposalMsg(OpWeightUpdateParams, wUpdateParams, SimulatePropMsgUpdateParams(args)), } } @@ -524,63 +542,11 @@ func SimulateGovMsgUnsanctionImmediate(args *WeightedOpsArgs) simtypes.Operation } } -func SimulateGovMsgUpdateParams(args *WeightedOpsArgs) simtypes.Operation { - return func( - r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, - accs []simtypes.Account, chainID string, - ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { - // Pick the random params first, so R isn't used for anything else before, - // which makes testing easier. - msg := &sanction.MsgUpdateParams{ +func SimulatePropMsgUpdateParams(args *WeightedOpsArgs) simtypes.MsgSimulatorFn { + return func(r *rand.Rand, ctx sdk.Context, accs []simtypes.Account) sdk.Msg { + return &sanction.MsgUpdateParams{ Params: RandomParams(r), Authority: args.SK.GetAuthority(), } - msgType := sdk.MsgTypeURL(msg) - - // Get the governance min deposit needed. - govParams, err := args.GK.Params.Get(ctx) - if err != nil { - return simtypes.NoOpMsg(sanction.ModuleName, msgType, "error getting gov params"), nil, err - } - govMinDep := sdk.NewCoins(govParams.MinDeposit...) - - sender, _ := simtypes.RandomAcc(r, accs) - - msgArgs := &SendGovMsgArgs{ - WeightedOpsArgs: *args, - R: r, - App: app, - Ctx: ctx, - Accs: accs, - ChainID: chainID, - Sender: sender, - Msg: msg, - Deposit: govMinDep, - Comment: "update params", - } - - skip, opMsg, err := SendGovMsg(msgArgs) - - if skip || err != nil { - return opMsg, nil, err - } - - proposalID, err := args.GK.ProposalID.Peek(ctx) - if err != nil { - return simtypes.NoOpMsg(sanction.ModuleName, sdk.MsgTypeURL(msg), "unable to get submitted proposalID"), nil, err - } - proposalID-- - - votingPeriod := govParams.VotingPeriod - fops := make([]simtypes.FutureOperation, len(accs)) - for i, acct := range accs { - whenVote := ctx.BlockHeader().Time.Add(time.Duration(r.Int63n(int64(votingPeriod.Seconds()))) * time.Second) - fops[i] = simtypes.FutureOperation{ - BlockTime: whenVote, - Op: OperationMsgVote(args, acct, proposalID, govv1.OptionYes, msgArgs.Comment), - } - } - - return opMsg, fops, nil } } diff --git a/x/sanction/simulation/operations_test.go b/x/sanction/simulation/operations_test.go index 7f2194e2d9..09ecb9f5a7 100644 --- a/x/sanction/simulation/operations_test.go +++ b/x/sanction/simulation/operations_test.go @@ -1,6 +1,7 @@ package simulation_test import ( + "fmt" "math/rand" "testing" "time" @@ -17,13 +18,14 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - bankutil "github.com/cosmos/cosmos-sdk/x/bank/testutil" govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" "github.com/provenance-io/provenance/app" + "github.com/provenance-io/provenance/testutil" "github.com/provenance-io/provenance/testutil/assertions" "github.com/provenance-io/provenance/x/sanction" - "github.com/provenance-io/provenance/x/sanction/simulation" + + . "github.com/provenance-io/provenance/x/sanction/simulation" ) type SimTestSuite struct { @@ -77,19 +79,7 @@ func (s *SimTestSuite) createTestingAccounts(r *rand.Rand, count int) []simtypes // createTestingAccountsWithPower creates new accounts with the specified power (coins amount). func (s *SimTestSuite) createTestingAccountsWithPower(r *rand.Rand, count int, power int64) []simtypes.Account { - accounts := simtypes.RandomAccounts(r, count) - - initAmt := sdk.TokensFromConsensusPower(power, sdk.DefaultPowerReduction) - initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) - - // add coins to the accounts - for _, account := range accounts { - acc := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, account.Address) - s.app.AccountKeeper.SetAccount(s.ctx, acc) - s.Require().NoError(bankutil.FundAccount(s.ctx, s.app.BankKeeper, account.Address, initCoins)) - } - - return accounts + return testutil.GenerateTestingAccountsWithPower(s.T(), s.ctx, s.app, r, count, power) } // setSanctionParamsAboveGovDeposit looks up the x/gov min deposit and sets the @@ -238,8 +228,8 @@ func (s *SimTestSuite) MakeTestSimState() module.SimulationState { } // getWeightedOpsArgs creates a standard WeightedOpsArgs. -func (s *SimTestSuite) getWeightedOpsArgs() simulation.WeightedOpsArgs { - return simulation.WeightedOpsArgs{ +func (s *SimTestSuite) getWeightedOpsArgs() WeightedOpsArgs { + return WeightedOpsArgs{ SimState: s.MakeTestSimState(), ProtoCodec: codec.NewProtoCodec(s.app.InterfaceRegistry()), AK: s.app.AccountKeeper, @@ -260,14 +250,13 @@ func (s *SimTestSuite) TestWeightedOperations() { comment string weight int }{ - {comment: "sanction", weight: simulation.DefaultWeightSanction}, - {comment: "immediate sanction", weight: simulation.DefaultWeightSanctionImmediate}, - {comment: "unsanction", weight: simulation.DefaultWeightUnsanction}, - {comment: "immediate unsanction", weight: simulation.DefaultWeightUnsanctionImmediate}, - {comment: "update params", weight: simulation.DefaultWeightUpdateParams}, + {comment: "sanction", weight: DefaultWeightSanction}, + {comment: "immediate sanction", weight: DefaultWeightSanctionImmediate}, + {comment: "unsanction", weight: DefaultWeightUnsanction}, + {comment: "immediate unsanction", weight: DefaultWeightUnsanctionImmediate}, } - weightedOps := simulation.WeightedOperations( + weightedOps := WeightedOperations( s.MakeTestSimState(), codec.NewProtoCodec(s.app.InterfaceRegistry()), s.app.AccountKeeper, s.app.BankKeeper, s.app.GovKeeper, s.app.SanctionKeeper, ) @@ -308,6 +297,48 @@ func (s *SimTestSuite) TestWeightedOperations() { } } +func (s *SimTestSuite) TestProposalMsgs() { + expected := []struct { + key string + weight int + msgType sdk.Msg + }{ + {key: OpWeightUpdateParams, weight: DefaultWeightUpdateParams, msgType: &sanction.MsgUpdateParams{}}, + } + + args := s.getWeightedOpsArgs() + + var propMsgs []simtypes.WeightedProposalMsg + testGetPropMsgs := func() { + propMsgs = ProposalMsgs(args.SimState, args.ProtoCodec, args.AK, args.BK, args.GK, *args.SK) + } + s.Require().NotPanics(testGetPropMsgs, "ProposalMsgs") + s.Require().Len(propMsgs, len(expected), "ProposalMsgs") + + r := rand.New(rand.NewSource(1)) + accs := s.createTestingAccounts(r, 10) + + for i, propMsg := range propMsgs { + exp := expected[i] + s.Run(exp.key, func() { + expMsgType := fmt.Sprintf("%T", exp.msgType) + + s.Assert().Equal(exp.key, propMsg.AppParamsKey(), "AppParamsKey()") + s.Assert().Equal(exp.weight, propMsg.DefaultWeight(), "DefaultWeight()") + s.Require().NotNil(propMsg.MsgSimulatorFn(), "MsgSimulatorFn()") + + var msg sdk.Msg + testPropMsg := func() { + msg = propMsg.MsgSimulatorFn()(r, s.ctx, accs) + } + s.Require().NotPanics(testPropMsg, "calling the propMsg.MsgSimulatorFn()") + s.Require().NotNil(msg, "msg result") + actMsgType := fmt.Sprintf("%T", msg) + s.Assert().Equal(expMsgType, actMsgType, "msg result") + }) + } +} + func (s *SimTestSuite) TestSendGovMsg() { s.requireResetGovParams() @@ -416,7 +447,7 @@ func (s *SimTestSuite) TestSendGovMsg() { for _, tc := range tests { s.Run(tc.name, func() { - args := &simulation.SendGovMsgArgs{ + args := &SendGovMsgArgs{ WeightedOpsArgs: s.getWeightedOpsArgs(), R: rand.New(rand.NewSource(1)), App: s.app.BaseApp, @@ -433,7 +464,7 @@ func (s *SimTestSuite) TestSendGovMsg() { var opMsg simtypes.OperationMsg var err error testFunc := func() { - skip, opMsg, err = simulation.SendGovMsg(args) + skip, opMsg, err = SendGovMsg(args) } s.Require().NotPanics(testFunc, "SendGovMsg") assertions.AssertErrorContents(s.T(), err, tc.expInErr, "SendGovMsg error") @@ -477,7 +508,7 @@ func (s *SimTestSuite) TestOperationMsgVote() { var opMsg simtypes.OperationMsg var err error testSendGovSanct := func() { - skip, opMsg, err = simulation.SendGovMsg(&simulation.SendGovMsgArgs{ + skip, opMsg, err = SendGovMsg(&SendGovMsgArgs{ WeightedOpsArgs: s.getWeightedOpsArgs(), R: r, App: s.app.BaseApp, @@ -494,7 +525,7 @@ func (s *SimTestSuite) TestOperationMsgVote() { }) } testSendGovUnsanct := func() { - skip, opMsg, err = simulation.SendGovMsg(&simulation.SendGovMsgArgs{ + skip, opMsg, err = SendGovMsg(&SendGovMsgArgs{ WeightedOpsArgs: s.getWeightedOpsArgs(), R: r, App: s.app.BaseApp, @@ -619,7 +650,7 @@ func (s *SimTestSuite) TestOperationMsgVote() { s.Run(tc.name, func() { var op simtypes.Operation testFunc := func() { - op = simulation.OperationMsgVote(&wopArgs, tc.voter, tc.govPropID, tc.vote, tc.comment) + op = OperationMsgVote(&wopArgs, tc.voter, tc.govPropID, tc.vote, tc.comment) } s.Require().NotPanics(testFunc, "OperationMsgVote") var fops []simtypes.FutureOperation @@ -802,7 +833,7 @@ func TestMaxCoins(t *testing.T) { t.Run(tc.name, func(t *testing.T) { var actual sdk.Coins testFunc := func() { - actual = simulation.MaxCoins(tc.a, tc.b) + actual = MaxCoins(tc.a, tc.b) } require.NotPanics(t, testFunc, "MaxCoins") assert.Equal(t, tc.exp.String(), actual.String(), "MaxCoins result") @@ -877,7 +908,7 @@ func (s *SimTestSuite) TestSimulateGovMsgSanction() { } var op simtypes.Operation testFunc := func() { - op = simulation.SimulateGovMsgSanction(&wopArgs) + op = SimulateGovMsgSanction(&wopArgs) } s.Require().NotPanics(testFunc, "SimulateGovMsgSanction") var opMsg simtypes.OperationMsg @@ -1083,7 +1114,7 @@ func (s *SimTestSuite) TestSimulateGovMsgSanctionImmediate() { } var op simtypes.Operation testFunc := func() { - op = simulation.SimulateGovMsgSanctionImmediate(&wopArgs) + op = SimulateGovMsgSanctionImmediate(&wopArgs) } s.Require().NotPanics(testFunc, "SimulateGovMsgSanctionImmediate") var opMsg simtypes.OperationMsg @@ -1291,7 +1322,7 @@ func (s *SimTestSuite) TestSimulateGovMsgUnsanction() { } var op simtypes.Operation testFunc := func() { - op = simulation.SimulateGovMsgUnsanction(&wopArgs) + op = SimulateGovMsgUnsanction(&wopArgs) } s.Require().NotPanics(testFunc, "SimulateGovMsgUnsanction") var opMsg simtypes.OperationMsg @@ -1618,7 +1649,7 @@ func (s *SimTestSuite) TestSimulateGovMsgUnsanctionImmediate() { } var op simtypes.Operation testFunc := func() { - op = simulation.SimulateGovMsgUnsanctionImmediate(&wopArgs) + op = SimulateGovMsgUnsanctionImmediate(&wopArgs) } s.Require().NotPanics(testFunc, "SimulateGovMsgUnsanctionImmediate") var opMsg simtypes.OperationMsg @@ -1705,152 +1736,25 @@ func (s *SimTestSuite) TestSimulateGovMsgUnsanctionImmediate() { } } -func (s *SimTestSuite) TestSimulateGovMsgUpdateParams() { - chainID := "test-simulate-gov-msg-update-params" - origMinDep := s.govMinDep - defer func() { - s.govMinDep = origMinDep - }() - s.govMinDep = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 2)) - s.requireResetParams() - - s.resetAccsRand() - - tests := []struct { - name string - r *rand.Rand - accs []simtypes.Account - expInErr []string - expOpMsgOK bool - expOpMsgRoute string - expOpMsgName string - expOpMsgComment string - expParams *sanction.Params - }{ - { - name: "problem sending gov msg", - r: rand.New(rand.NewSource(1)), - accs: s.createTestingAccountsWithPower(s.accsRand, 10, 0), - expOpMsgOK: false, - expOpMsgRoute: "sanction", - expOpMsgName: sdk.MsgTypeURL(&sanction.MsgUpdateParams{}), - expOpMsgComment: "sender has no spendable coins", - }, - { - name: "all good seed 1", - r: rand.New(rand.NewSource(1)), - accs: s.createTestingAccounts(s.accsRand, 10), - expOpMsgOK: true, - expOpMsgRoute: "gov", - expOpMsgName: sdk.MsgTypeURL(&govv1.MsgSubmitProposal{}), - expOpMsgComment: "update params", - expParams: &sanction.Params{ - ImmediateSanctionMinDeposit: nil, - ImmediateUnsanctionMinDeposit: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 821+1)}, - }, - }, - { - name: "all good seed 100", - r: rand.New(rand.NewSource(100)), - accs: s.createTestingAccounts(s.accsRand, 10), - expOpMsgOK: true, - expOpMsgRoute: "gov", - expOpMsgName: sdk.MsgTypeURL(&govv1.MsgSubmitProposal{}), - expOpMsgComment: "update params", - expParams: &sanction.Params{ - ImmediateSanctionMinDeposit: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 24+1)}, - ImmediateUnsanctionMinDeposit: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 39+1)}, - }, - }, +func (s *SimTestSuite) TestSimulatePropMsgUpdateParams() { + seedVal := int64(3) // 3 chosen by random roll of a d10. + wopArgs := s.getWeightedOpsArgs() + expMsg := &sanction.MsgUpdateParams{ + Params: RandomParams(rand.New(rand.NewSource(seedVal))), + Authority: wopArgs.SK.GetAuthority(), } - wopArgs := s.getWeightedOpsArgs() - voteType := sdk.MsgTypeURL(&govv1.MsgVote{}) + var simFn simtypes.MsgSimulatorFn + testGetSimFn := func() { + simFn = SimulatePropMsgUpdateParams(&wopArgs) + } + s.Require().NotPanics(testGetSimFn, "SimulatePropMsgUpdateParams") - for _, tc := range tests { - s.Run(tc.name, func() { - s.freshCtx() - var op simtypes.Operation - testFunc := func() { - op = simulation.SimulateGovMsgUpdateParams(&wopArgs) - } - s.Require().NotPanics(testFunc, "SimulateGovMsgUpdateParams") - var opMsg simtypes.OperationMsg - var fops []simtypes.FutureOperation - var err error - testOp := func() { - opMsg, fops, err = op(tc.r, s.app.BaseApp, s.ctx, tc.accs, chainID) - } - s.Require().NotPanics(testOp, "SimulateGovMsgUpdateParams op execution") - assertions.AssertErrorContents(s.T(), err, tc.expInErr, "op error") - s.Assert().Equal(tc.expOpMsgOK, opMsg.OK, "op msg ok") - s.Assert().Equal(tc.expOpMsgRoute, opMsg.Route, "op msg route") - s.Assert().Equal(tc.expOpMsgName, opMsg.Name, "op msg name") - s.Assert().Equal(tc.expOpMsgComment, opMsg.Comment, "op msg comment") - if !tc.expOpMsgOK && !opMsg.OK { - s.Assert().Empty(fops, "future ops") - } - if tc.expOpMsgOK && opMsg.OK { - s.Assert().Equal(len(tc.accs), len(fops), "number of future ops") - // If we were expecting it to be okay, and it was, run all the future ops too. - // Some of them might fail (due to being sanctioned), - // but all the ones that went through should be YES votes. - maxBlockTime := s.ctx.BlockHeader().Time.Add(s.votingPeriod) - prop := s.getLastGovProp() - s.Assert().Equal(s.govMinDep.String(), sdk.NewCoins(prop.TotalDeposit...).String(), "prop deposit") - preVotes := s.getVotes(prop.Id) - // There shouldn't be any votes yet. - if !s.Assert().Empty(preVotes, "votes before running future ops") { - for i, fop := range fops { - s.Assert().LessOrEqual(fop.BlockTime, maxBlockTime, "future op %d block time", i+1) - s.Assert().Equal(0, fop.BlockHeight, "future op %d block height", i+1) - var fopMsg simtypes.OperationMsg - var ffops []simtypes.FutureOperation - testFop := func() { - fopMsg, ffops, err = fop.Op(rand.New(rand.NewSource(1)), s.app.BaseApp, s.ctx, tc.accs, chainID) - } - if !s.Assert().NotPanics(testFop, "future op %d execution", i+1) { - continue - } - if err != nil { - s.T().Logf("future op %d returned an error, but that's kind of expected: %v", i+1, err) - continue - } - if !fopMsg.OK { - s.T().Logf("future op %d returned not okay, but that's kind of expected: %q", i+1, fopMsg.Comment) - continue - } - s.Assert().Empty(ffops, "future ops returned by future op %d", i+1) - s.Assert().Equal(voteType, fopMsg.Name, "future op %d msg name", i+1) - s.Assert().Equal(tc.expOpMsgComment, fopMsg.Comment, "future op %d msg comment", i+1) - } - // Now there should be some votes. - postVotes := s.getVotes(prop.Id) - for i, vote := range postVotes { - if s.Assert().Len(vote.Options, 1, "vote %d options count", i+1) { - s.Assert().Equal(govv1.OptionYes, vote.Options[0].Option, "vote %d option", i+1) - s.Assert().Equal("1.000000000000000000", vote.Options[1].Weight, "vote %d weight", i+1) - } - } - } - // Now, get the message and check its content. - msgs, err := prop.GetMsgs() - if s.Assert().NoError(err, "getting messages from the proposal") { - if s.Assert().Len(msgs, 1, "number of messages in the proposal") { - msg, ok := msgs[0].(*sanction.MsgUpdateParams) - if s.Assert().True(ok, "could not cast prop msg to MsgUpdateParams") { - if !s.Assert().Equal(tc.expParams, msg.Params, "params in gov prop") && tc.expParams != nil && msg.Params != nil { - s.Assert().Equal(tc.expParams.ImmediateSanctionMinDeposit.String(), - msg.Params.ImmediateSanctionMinDeposit.String(), - "ImmediateSanctionMinDeposit") - s.Assert().Equal(tc.expParams.ImmediateUnsanctionMinDeposit.String(), - msg.Params.ImmediateUnsanctionMinDeposit.String(), - "ImmediateUnsanctionMinDeposit") - } - } - } - } - } - }) + var actMsg sdk.Msg + testGetMsg := func() { + actMsg = simFn(rand.New(rand.NewSource(seedVal)), s.ctx, nil) } + s.Require().NotPanics(testGetMsg, "running the SimulatePropMsgUpdateParams result") + + s.Assert().Equal(expMsg, actMsg, "resulting MsgUpdateParams") } diff --git a/x/trigger/client/cli/cli_test.go b/x/trigger/client/cli/cli_test.go index a5357ae4cb..d396a46879 100644 --- a/x/trigger/client/cli/cli_test.go +++ b/x/trigger/client/cli/cli_test.go @@ -13,7 +13,6 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" sdktestutil "github.com/cosmos/cosmos-sdk/testutil" @@ -36,15 +35,16 @@ import ( type IntegrationTestSuite struct { suite.Suite - cfg network.Config - network *network.Network - keyring keyring.Keyring - keyringDir string + cfg network.Config + network *network.Network - accountAddr sdk.AccAddress - accountKey *secp256k1.PrivKey + keyring keyring.Keyring + keyringEntries []testutil.TestKeyringEntry accountAddresses []sdk.AccAddress + accountAddr sdk.AccAddress + accountKey *secp256k1.PrivKey + startingTriggerID triggertypes.TriggerID startingQueueIndex uint64 triggers []triggertypes.Trigger @@ -169,7 +169,7 @@ func (s *IntegrationTestSuite) SetupSuite() { s.network, err = network.New(s.T(), s.T().TempDir(), s.cfg) s.Require().NoError(err, "network.New") - s.network.Validators[0].ClientCtx = s.network.Validators[0].ClientCtx.WithKeyringDir(s.keyringDir).WithKeyring(s.keyring) + s.network.Validators[0].ClientCtx = s.network.Validators[0].ClientCtx.WithKeyring(s.keyring) _, err = testutil.WaitForHeight(s.network, 6) s.Require().NoError(err, "WaitForHeight") @@ -180,21 +180,8 @@ func (s *IntegrationTestSuite) TearDownSuite() { } func (s *IntegrationTestSuite) GenerateAccountsWithKeyrings(number int) { - path := hd.CreateHDPath(118, 0, 0).String() - s.keyringDir = s.T().TempDir() - kr, err := keyring.New(s.T().Name(), "test", s.keyringDir, nil, s.cfg.Codec) - s.Require().NoError(err, "Keyring.New") - s.keyring = kr - for i := 0; i < number; i++ { - keyId := fmt.Sprintf("test_key%v", i) - info, _, err := kr.NewMnemonic(keyId, keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1) - s.Require().NoError(err, "Keyring.NewMneomonic") - addr, err := info.GetAddress() - if err != nil { - panic(err) - } - s.accountAddresses = append(s.accountAddresses, addr) - } + s.keyringEntries, s.keyring = testutil.GenerateTestKeyring(s.T(), number, s.cfg.Codec) + s.accountAddresses = testutil.GetKeyringEntryAddresses(s.keyringEntries) } func (s *IntegrationTestSuite) CreateTrigger(id uint64, owner string, event types.TriggerEventI, action sdk.Msg) types.Trigger { diff --git a/x/trigger/simulation/genesis.go b/x/trigger/simulation/genesis.go index ebd3468c4f..779c57cb17 100644 --- a/x/trigger/simulation/genesis.go +++ b/x/trigger/simulation/genesis.go @@ -13,6 +13,7 @@ import ( sdktx "github.com/cosmos/cosmos-sdk/types/tx" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/provenance-io/provenance/internal/helpers" "github.com/provenance-io/provenance/internal/pioconfig" "github.com/provenance-io/provenance/x/trigger/types" ) @@ -30,12 +31,12 @@ const ( // TriggerIDStartFn randomized starting trigger id func TriggerIDStartFn(r *rand.Rand) uint64 { // max 5 ids for the triggers max 5 ids for the queue = min of 10 here. - return uint64(randIntBetween(r, 10, 10000000000)) + return uint64(helpers.RandIntBetween(r, 10, 10000000000)) } // QueueStartFn randomized Queue Start Index func QueueStartFn(r *rand.Rand) uint64 { - return uint64(randIntBetween(r, 1, 10000000000)) + return uint64(helpers.RandIntBetween(r, 1, 10000000000)) } // NewRandomEvent returns a random event @@ -43,16 +44,16 @@ func NewRandomEvent(r *rand.Rand, now time.Time) types.TriggerEventI { if r.Intn(2) > 0 { minimumTime := int(time.Second * 10) maximumTime := int(time.Minute * 5) - randTime := now.Add(time.Duration(randIntBetween(r, minimumTime, maximumTime))) + randTime := now.Add(time.Duration(helpers.RandIntBetween(r, minimumTime, maximumTime))) return &types.BlockTimeEvent{Time: randTime.UTC()} } - height := uint64(randIntBetween(r, 10, 150)) + height := uint64(helpers.RandIntBetween(r, 10, 150)) return &types.BlockHeightEvent{BlockHeight: height} } // NewRandomAction returns a random action func NewRandomAction(r *rand.Rand, from string, to string) sdk.Msg { - amount := int64(randIntBetween(r, 100, 1000)) + amount := int64(helpers.RandIntBetween(r, 100, 1000)) return &banktypes.MsgSend{ FromAddress: from, ToAddress: to, @@ -62,7 +63,7 @@ func NewRandomAction(r *rand.Rand, from string, to string) sdk.Msg { // NewRandomTrigger returns a random trigger func NewRandomTrigger(r *rand.Rand, simState *module.SimulationState, accs []simtypes.Account, id types.TriggerID) types.Trigger { - raccs, err := RandomAccs(r, accs, 2) + raccs, err := helpers.SelectRandomAccounts(r, accs, 2) if err != nil { panic(fmt.Errorf("NewRandomTrigger failed: %w", err)) } @@ -231,8 +232,3 @@ func RandomizedGenState(simState *module.SimulationState) { } fmt.Printf("Selected randomly generated trigger parameters:\n%s\n", bz) } - -// randIntBetween generates a random number between min and max inclusive. -func randIntBetween(r *rand.Rand, min, max int) int { - return r.Intn(max-min+1) + min -} diff --git a/x/trigger/simulation/operations.go b/x/trigger/simulation/operations.go index eeff1f7591..07299f946a 100644 --- a/x/trigger/simulation/operations.go +++ b/x/trigger/simulation/operations.go @@ -1,7 +1,6 @@ package simulation import ( - "fmt" "math/rand" sdkmath "cosmossdk.io/math" @@ -17,6 +16,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/simulation" simappparams "github.com/provenance-io/provenance/app/params" + "github.com/provenance-io/provenance/internal/helpers" "github.com/provenance-io/provenance/internal/pioconfig" "github.com/provenance-io/provenance/x/trigger/keeper" "github.com/provenance-io/provenance/x/trigger/types" @@ -56,7 +56,7 @@ func SimulateMsgCreateTrigger(simState module.SimulationState, _ keeper.Keeper, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { now := ctx.BlockTime() - raccs, err := RandomAccs(r, accs, 2) + raccs, err := helpers.SelectRandomAccounts(r, accs, 2) if err != nil { return simtypes.NoOpMsg(types.ModuleName, sdk.MsgTypeURL(&types.MsgCreateTriggerRequest{}), err.Error()), nil, nil } @@ -163,15 +163,3 @@ func randomTrigger(r *rand.Rand, ctx sdk.Context, k keeper.Keeper) *types.Trigge idx := r.Intn(len(triggers)) return &triggers[idx] } - -func RandomAccs(r *rand.Rand, accs []simtypes.Account, count uint64) ([]simtypes.Account, error) { - if uint64(len(accs)) < count { - return nil, fmt.Errorf("cannot choose %d accounts because there are only %d", count, len(accs)) - } - raccs := make([]simtypes.Account, 0, len(accs)) - raccs = append(raccs, accs...) - r.Shuffle(len(raccs), func(i, j int) { - raccs[i], raccs[j] = raccs[j], raccs[i] - }) - return raccs[:count], nil -} diff --git a/x/trigger/simulation/operations_test.go b/x/trigger/simulation/operations_test.go index 49fa6e5ddd..18b3aec0dd 100644 --- a/x/trigger/simulation/operations_test.go +++ b/x/trigger/simulation/operations_test.go @@ -14,10 +14,10 @@ import ( "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" sdktx "github.com/cosmos/cosmos-sdk/types/tx" - "github.com/cosmos/cosmos-sdk/x/bank/testutil" "github.com/provenance-io/provenance/app" simappparams "github.com/provenance-io/provenance/app/params" + "github.com/provenance-io/provenance/testutil" "github.com/provenance-io/provenance/x/trigger/simulation" "github.com/provenance-io/provenance/x/trigger/types" ) @@ -170,77 +170,6 @@ func (s *SimTestSuite) TestSimulateMsgDestroyTrigger() { s.Assert().Len(futureOperations, 0, "futureOperations") } -func (s *SimTestSuite) TestRandomAccs() { - source := rand.NewSource(1) - r := rand.New(source) - accounts := s.getTestingAccounts(r, 3) - - tests := []struct { - name string - accs []simtypes.Account - expected []simtypes.Account - count uint64 - err string - }{ - { - name: "valid - return nothing when count is 0", - accs: []simtypes.Account{}, - expected: []simtypes.Account{}, - count: 0, - }, - { - name: "valid - return 1 when count is 1", - accs: []simtypes.Account{accounts[0]}, - expected: []simtypes.Account{accounts[0]}, - count: 1, - }, - { - name: "valid - return multiple when count greater than 1", - accs: []simtypes.Account{accounts[0], accounts[1]}, - expected: []simtypes.Account{accounts[1], accounts[0]}, - count: 2, - }, - { - name: "valid - return is limited by count", - accs: []simtypes.Account{accounts[0], accounts[1], accounts[2]}, - expected: []simtypes.Account{accounts[1]}, - count: 1, - }, - { - name: "invalid - return error when count is greater than length", - accs: []simtypes.Account{accounts[0], accounts[1]}, - expected: []simtypes.Account{}, - count: 3, - err: "cannot choose 3 accounts because there are only 2", - }, - } - - for _, tc := range tests { - s.Run(tc.name, func() { - raccs, err := simulation.RandomAccs(r, tc.accs, tc.count) - if len(tc.err) == 0 { - s.Require().NoError(err, "should have no error for successful RandomAccs") - s.Require().Equal(tc.expected, raccs, "should have correct output for successful RandomAccs") - } else { - s.Require().EqualError(err, tc.err, "should have correct error message for RandomAccs") - } - }) - } -} - func (s *SimTestSuite) getTestingAccounts(r *rand.Rand, n int) []simtypes.Account { - accounts := simtypes.RandomAccounts(r, n) - - initAmt := sdk.TokensFromConsensusPower(1000000, sdk.DefaultPowerReduction) - initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) - - // add coins to the accounts - for _, account := range accounts { - acc := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, account.Address) - s.app.AccountKeeper.SetAccount(s.ctx, acc) - err := testutil.FundAccount(s.ctx, s.app.BankKeeper, account.Address, initCoins) - s.Require().NoError(err) - } - - return accounts + return testutil.GenerateTestingAccounts(s.T(), s.ctx, s.app, r, n) }