diff --git a/.gitignore b/.gitignore index 3202c829a..cf543eadc 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,9 @@ release/ .envrc .vscode +# OS +.DS_Store + # Localnet localnet/node?/data/*.db localnet/node?/data/snapshots diff --git a/app/simulation_test.go b/app/simulation_test.go index 561a83e4d..283fc5683 100644 --- a/app/simulation_test.go +++ b/app/simulation_test.go @@ -6,6 +6,7 @@ import ( "math/rand" "os" "testing" + "time" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" @@ -50,7 +51,6 @@ func interBlockCacheOpt() func(*baseapp.BaseApp) { return baseapp.SetInterBlockCache(store.NewCommitKVStoreCacheManager()) } -// go test ./app -v -benchmem -run=^$ -bench ^BenchmarkSimulation -Commit=true -cpuprofile cpu.out func BenchmarkSimulation(b *testing.B) { simapp.FlagVerboseValue = true simapp.FlagOnOperationValue = true @@ -118,6 +118,7 @@ func TestAppStateDeterminism(t *testing.T) { config.OnOperation = true config.AllInvariants = true + rand.Seed(time.Now().Unix()) numSeeds := 3 numTimesToRunPerSeed := 5 appHashList := make([]json.RawMessage, numTimesToRunPerSeed) diff --git a/testutil/sample/campaign.go b/testutil/sample/campaign.go index 72b4d26fa..3edc22a07 100644 --- a/testutil/sample/campaign.go +++ b/testutil/sample/campaign.go @@ -91,7 +91,7 @@ func CampaignParams(r *rand.Rand) campaign.Params { maxTotalSupply := campaign.DefaultMaxTotalSupply // assign random small amount of staking denom - campaignCreationFee := sdk.NewCoins(sdk.NewInt64Coin(BondDenom, r.Int63n(100)+1)) + campaignCreationFee := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, r.Int63n(100)+1)) return campaign.NewParams(minTotalSupply, maxTotalSupply, campaignCreationFee) } diff --git a/testutil/sample/launch.go b/testutil/sample/launch.go index beded032c..9c8abdcc0 100644 --- a/testutil/sample/launch.go +++ b/testutil/sample/launch.go @@ -319,7 +319,7 @@ func LaunchParams(r *rand.Rand) launch.Params { minLaunchTime := r.Int63n(10) + launch.DefaultMinLaunchTime // assign random small amount of staking denom - chainCreationFee := sdk.NewCoins(sdk.NewInt64Coin(BondDenom, r.Int63n(100)+1)) + chainCreationFee := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, r.Int63n(100)+1)) return launch.NewParams(minLaunchTime, maxLaunchTime, launch.DefaultRevertDelay, chainCreationFee) } diff --git a/testutil/sample/simulation.go b/testutil/sample/simulation.go index ef6cc4706..5ed976fb3 100644 --- a/testutil/sample/simulation.go +++ b/testutil/sample/simulation.go @@ -10,9 +10,6 @@ import ( ) const ( - // BondDenom defines the bond denom used in testing - BondDenom = "stake" - simAccountsNb = 100 ) @@ -36,3 +33,29 @@ func SimAccounts() (accounts []simtypes.Account) { func Rand() *rand.Rand { return rand.New(rand.NewSource(time.Now().Unix())) } + +// Fees returns a random fee by selecting a random amount of bond denomination +// from the account's available balance. If the user doesn't have enough funds for +// paying fees, it returns empty coins. +func Fees(r *rand.Rand, spendableCoins sdk.Coins) (sdk.Coins, error) { + if spendableCoins.Empty() { + return nil, nil + } + + bondDenomAmt := spendableCoins.AmountOf(sdk.DefaultBondDenom) + if bondDenomAmt.IsZero() { + return nil, nil + } + + amt, err := simtypes.RandPositiveInt(r, bondDenomAmt) + if err != nil { + return nil, err + } + + if amt.IsZero() { + return nil, nil + } + + fees := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, amt)) + return fees, nil +} diff --git a/testutil/simulation/util.go b/testutil/simulation/util.go new file mode 100644 index 000000000..35922e79f --- /dev/null +++ b/testutil/simulation/util.go @@ -0,0 +1,56 @@ +package simulation + +import ( + "github.com/cosmos/cosmos-sdk/simapp/helpers" + sdk "github.com/cosmos/cosmos-sdk/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + sdksimulation "github.com/cosmos/cosmos-sdk/x/simulation" + + "github.com/tendermint/spn/testutil/sample" +) + +// GenAndDeliverTxWithRandFees generates a transaction with a random fee and delivers it. +func GenAndDeliverTxWithRandFees(txCtx sdksimulation.OperationInput, gas uint64) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + account := txCtx.AccountKeeper.GetAccount(txCtx.Context, txCtx.SimAccount.Address) + spendable := txCtx.Bankkeeper.SpendableCoins(txCtx.Context, account.GetAddress()) + + var fees sdk.Coins + var err error + + coins, hasNeg := spendable.SafeSub(txCtx.CoinsSpentInMsg) + if hasNeg { + return simtypes.NoOpMsg(txCtx.ModuleName, txCtx.MsgType, "message doesn't leave room for fees"), nil, err + } + + fees, err = sample.Fees(txCtx.R, coins) + if err != nil { + return simtypes.NoOpMsg(txCtx.ModuleName, txCtx.MsgType, "unable to generate fees"), nil, err + } + return GenAndDeliverTx(txCtx, fees, gas) +} + +// GenAndDeliverTx generates a transactions and delivers it. +func GenAndDeliverTx(txCtx sdksimulation.OperationInput, fees sdk.Coins, gas uint64) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + account := txCtx.AccountKeeper.GetAccount(txCtx.Context, txCtx.SimAccount.Address) + tx, err := helpers.GenTx( + txCtx.TxGen, + []sdk.Msg{txCtx.Msg}, + fees, + gas, + txCtx.Context.ChainID(), + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + txCtx.SimAccount.PrivKey, + ) + + if err != nil { + return simtypes.NoOpMsg(txCtx.ModuleName, txCtx.MsgType, "unable to generate mock tx"), nil, err + } + + _, _, err = txCtx.App.Deliver(txCtx.TxGen.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(txCtx.ModuleName, txCtx.MsgType, "unable to deliver tx"), nil, err + } + + return simtypes.NewOperationMsg(txCtx.Msg, true, "", txCtx.Cdc), nil, nil +} diff --git a/x/campaign/simulation/simulation.go b/x/campaign/simulation/simulation.go index 24442f0c0..581d33114 100644 --- a/x/campaign/simulation/simulation.go +++ b/x/campaign/simulation/simulation.go @@ -4,13 +4,15 @@ import ( "math/rand" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/simapp/helpers" simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/cosmos/cosmos-sdk/x/simulation" + sdksimulation "github.com/cosmos/cosmos-sdk/x/simulation" "github.com/tendermint/spn/testutil/sample" + "github.com/tendermint/spn/testutil/simulation" "github.com/tendermint/spn/x/campaign/keeper" "github.com/tendermint/spn/x/campaign/types" ) @@ -32,7 +34,7 @@ func deliverSimTx( msg TypedMsg, coinsSpent sdk.Coins, ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -46,7 +48,7 @@ func deliverSimTx( ModuleName: types.ModuleName, CoinsSpentInMsg: coinsSpent, } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } // SimulateMsgCreateCampaign simulates a MsgCreateCampaign message diff --git a/x/launch/simulation/simulation.go b/x/launch/simulation/simulation.go index 0444aa9d9..93b58951d 100644 --- a/x/launch/simulation/simulation.go +++ b/x/launch/simulation/simulation.go @@ -4,12 +4,14 @@ import ( "math/rand" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/simapp/helpers" simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/x/simulation" + sdksimulation "github.com/cosmos/cosmos-sdk/x/simulation" "github.com/tendermint/spn/testutil/sample" + "github.com/tendermint/spn/testutil/simulation" "github.com/tendermint/spn/x/launch/keeper" "github.com/tendermint/spn/x/launch/types" ) @@ -44,7 +46,7 @@ func SimulateMsgCreateChain(ak types.AccountKeeper, bk types.BankKeeper, k keepe false, 0, ) - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -58,7 +60,7 @@ func SimulateMsgCreateChain(ak types.AccountKeeper, bk types.BankKeeper, k keepe ModuleName: types.ModuleName, CoinsSpentInMsg: creationFee, } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } } @@ -107,7 +109,7 @@ func SimulateMsgEditChain(ak types.AccountKeeper, bk types.BankKeeper, k keeper. modify, ) - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -121,7 +123,7 @@ func SimulateMsgEditChain(ak types.AccountKeeper, bk types.BankKeeper, k keeper. ModuleName: types.ModuleName, CoinsSpentInMsg: sdk.NewCoins(), } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } } @@ -144,7 +146,7 @@ func SimulateMsgRequestAddGenesisAccount(ak types.AccountKeeper, bk types.BankKe simAccount.Address.String(), chain.LaunchID, ) - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -158,7 +160,7 @@ func SimulateMsgRequestAddGenesisAccount(ak types.AccountKeeper, bk types.BankKe ModuleName: types.ModuleName, CoinsSpentInMsg: sdk.NewCoins(), } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } } @@ -181,7 +183,7 @@ func SimulateMsgRequestAddVestingAccount(ak types.AccountKeeper, bk types.BankKe simAccount.Address.String(), chain.LaunchID, ) - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -195,7 +197,7 @@ func SimulateMsgRequestAddVestingAccount(ak types.AccountKeeper, bk types.BankKe ModuleName: types.ModuleName, CoinsSpentInMsg: sdk.NewCoins(), } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } } @@ -262,7 +264,7 @@ func SimulateMsgRequestRemoveAccount(ak types.AccountKeeper, bk types.BankKeeper accAddr, ) - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -276,7 +278,7 @@ func SimulateMsgRequestRemoveAccount(ak types.AccountKeeper, bk types.BankKeeper ModuleName: types.ModuleName, CoinsSpentInMsg: sdk.NewCoins(), } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } } @@ -299,7 +301,7 @@ func SimulateMsgRequestAddValidator(ak types.AccountKeeper, bk types.BankKeeper, simAccount.Address.String(), chain.LaunchID, ) - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -313,7 +315,7 @@ func SimulateMsgRequestAddValidator(ak types.AccountKeeper, bk types.BankKeeper, ModuleName: types.ModuleName, CoinsSpentInMsg: sdk.NewCoins(), } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } } @@ -333,7 +335,7 @@ func SimulateMsgRequestRemoveValidator(ak types.AccountKeeper, bk types.BankKeep valAcc.Address, valAcc.LaunchID, ) - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -347,7 +349,7 @@ func SimulateMsgRequestRemoveValidator(ak types.AccountKeeper, bk types.BankKeep ModuleName: types.ModuleName, CoinsSpentInMsg: sdk.NewCoins(), } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } } @@ -369,7 +371,7 @@ func SimulateMsgTriggerLaunch(ak types.AccountKeeper, bk types.BankKeeper, k kee return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgTriggerLaunch, err.Error()), nil, nil } msg := sample.MsgTriggerLaunch(r, simAccount.Address.String(), chain.LaunchID) - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -383,7 +385,7 @@ func SimulateMsgTriggerLaunch(ak types.AccountKeeper, bk types.BankKeeper, k kee ModuleName: types.ModuleName, CoinsSpentInMsg: sdk.NewCoins(), } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } } @@ -417,7 +419,7 @@ func SimulateMsgSettleRequest(ak types.AccountKeeper, bk types.BankKeeper, k kee msg.Approve = false } - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -431,7 +433,7 @@ func SimulateMsgSettleRequest(ak types.AccountKeeper, bk types.BankKeeper, k kee ModuleName: types.ModuleName, CoinsSpentInMsg: sdk.NewCoins(), } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } } @@ -458,7 +460,7 @@ func SimulateMsgRevertLaunch(ak types.AccountKeeper, bk types.BankKeeper, k keep return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgRevertLaunch, err.Error()), nil, nil } msg := sample.MsgRevertLaunch(simAccount.Address.String(), chain.LaunchID) - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -472,7 +474,7 @@ func SimulateMsgRevertLaunch(ak types.AccountKeeper, bk types.BankKeeper, k keep ModuleName: types.ModuleName, CoinsSpentInMsg: sdk.NewCoins(), } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } } @@ -501,7 +503,7 @@ func SimulateMsgUpdateLaunchInformation(ak types.AccountKeeper, bk types.BankKee modify, !modify && r.Intn(100) < 50, ) - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -515,6 +517,6 @@ func SimulateMsgUpdateLaunchInformation(ak types.AccountKeeper, bk types.BankKee ModuleName: types.ModuleName, CoinsSpentInMsg: sdk.NewCoins(), } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } } diff --git a/x/participation/keeper/msg_participate.go b/x/participation/keeper/msg_participate.go index 8a2648f62..031d08232 100644 --- a/x/participation/keeper/msg_participate.go +++ b/x/participation/keeper/msg_participate.go @@ -2,7 +2,6 @@ package keeper import ( "context" - "time" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -13,7 +12,6 @@ import ( func (k msgServer) Participate(goCtx context.Context, msg *types.MsgParticipate) (*types.MsgParticipateResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - blockTime := ctx.BlockTime() availableAlloc, err := k.GetAvailableAllocations(ctx, msg.Participant) if err != nil { @@ -32,16 +30,7 @@ func (k msgServer) Participate(goCtx context.Context, msg *types.MsgParticipate) } // check if auction allows participation at this time - registrationPeriod := k.RegistrationPeriod(ctx) - auctionStartTime := auction.GetStartTime() - if auctionStartTime.Unix() < int64(registrationPeriod.Seconds()) { - // subtraction would result in negative value, clamp the result to ~0 - // by making registrationPeriod ~= auctionStartTime - registrationPeriod = time.Duration(auctionStartTime.Unix()) * time.Second - } - // as commented in `Time.Sub()`: To compute t-d for a duration d, use t.Add(-d). - registrationStart := auctionStartTime.Add(-registrationPeriod) - if !blockTime.After(registrationStart) { + if !k.IsRegistrationEnabled(ctx, auction.GetStartTime()) { return nil, sdkerrors.Wrapf(types.ErrParticipationNotAllowed, "participation period for auction %d not yet started", msg.AuctionID) } diff --git a/x/participation/keeper/registration_period.go b/x/participation/keeper/registration_period.go new file mode 100644 index 000000000..25540f848 --- /dev/null +++ b/x/participation/keeper/registration_period.go @@ -0,0 +1,28 @@ +package keeper + +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// IsRegistrationEnabled returns true if the current block time is within the allowed registration period +func (k Keeper) IsRegistrationEnabled(ctx sdk.Context, auctionStartTime time.Time) bool { + blockTime := ctx.BlockTime() + if !blockTime.Before(auctionStartTime) { + return false + } + + registrationPeriod := k.RegistrationPeriod(ctx) + if auctionStartTime.Unix() < int64(registrationPeriod.Seconds()) { + // subtraction would result in negative value, clamp the result to ~0 + // by making registrationPeriod ~= auctionStartTime + registrationPeriod = time.Duration(auctionStartTime.Unix()) * time.Second + } + // as commented in `Time.Sub()`: To compute t-d for a duration d, use t.Add(-d). + registrationStart := auctionStartTime.Add(-registrationPeriod) + if !blockTime.After(registrationStart) { + return false + } + return true +} diff --git a/x/participation/keeper/registration_period_test.go b/x/participation/keeper/registration_period_test.go new file mode 100644 index 000000000..6a41ba8f4 --- /dev/null +++ b/x/participation/keeper/registration_period_test.go @@ -0,0 +1,57 @@ +package keeper_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + testkeeper "github.com/tendermint/spn/testutil/keeper" +) + +func TestIsRegistrationEnabled(t *testing.T) { + ctx, tk, _ := testkeeper.NewTestSetup(t) + registrationPeriod := time.Hour + + params := tk.ParticipationKeeper.GetParams(ctx) + params.RegistrationPeriod = registrationPeriod + tk.ParticipationKeeper.SetParams(ctx, params) + + for _, tc := range []struct { + name string + auctionStartTime time.Time + blockTime time.Time + expected bool + }{ + { + name: "registration window not yet started", + auctionStartTime: ctx.BlockTime().Add(time.Hour * 5), + blockTime: ctx.BlockTime(), + expected: false, + }, + { + name: "auction is started", + auctionStartTime: ctx.BlockTime(), + blockTime: ctx.BlockTime(), + expected: false, + }, + { + name: "registration enabled", + auctionStartTime: ctx.BlockTime().Add(time.Minute * 30), + blockTime: ctx.BlockTime(), + expected: true, + }, + { + name: "registration enabled when registration period is longer than range between Unix time 0 and auction's start time", + auctionStartTime: time.Unix(int64((registrationPeriod - time.Minute).Seconds()), 0), + blockTime: time.Unix(1, 0), + expected: true, + }, + } { + t.Run(tc.name, func(t *testing.T) { + tmpCtx := ctx.WithBlockTime(tc.blockTime) + res := tk.ParticipationKeeper.IsRegistrationEnabled(tmpCtx, tc.auctionStartTime) + require.Equal(t, tc.expected, res) + }) + } +} diff --git a/x/participation/simulation/simulation.go b/x/participation/simulation/simulation.go index a2b0d0fd7..b677c4a0f 100644 --- a/x/participation/simulation/simulation.go +++ b/x/participation/simulation/simulation.go @@ -7,17 +7,19 @@ import ( "time" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/simapp/helpers" simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" - "github.com/cosmos/cosmos-sdk/x/simulation" + sdksimulation "github.com/cosmos/cosmos-sdk/x/simulation" fundraisingkeeper "github.com/tendermint/fundraising/x/fundraising/keeper" fundraisingtypes "github.com/tendermint/fundraising/x/fundraising/types" "github.com/tendermint/spn/app/simutil" "github.com/tendermint/spn/testutil/sample" + "github.com/tendermint/spn/testutil/simulation" "github.com/tendermint/spn/x/participation/keeper" "github.com/tendermint/spn/x/participation/types" ) @@ -31,7 +33,7 @@ func SimulateMsgParticipate( return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { msg := &types.MsgParticipate{} - auction, found := RandomAuction(ctx, r, fk) + auction, found := RandomAuctionParticipationEnabled(ctx, r, fk, k) if !found { return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "no valid auction found"), nil, nil } @@ -53,7 +55,7 @@ func SimulateMsgParticipate( tier.TierID, ) - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -67,7 +69,7 @@ func SimulateMsgParticipate( ModuleName: types.ModuleName, CoinsSpentInMsg: sdk.NewCoins(), } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } } @@ -116,7 +118,7 @@ func SimulateCreateAuction( endTime := startTime.Add(time.Hour * 24 * 7) msg = sample.MsgCreateFixedAuction(r, simAccount.Address.String(), sellCoin, startTime, endTime) - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -131,7 +133,7 @@ func SimulateCreateAuction( CoinsSpentInMsg: desiredCoins, } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } } @@ -159,7 +161,7 @@ func SimulateMsgWithdrawAllocations( auction.GetId(), ) - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -173,7 +175,7 @@ func SimulateMsgWithdrawAllocations( ModuleName: types.ModuleName, CoinsSpentInMsg: sdk.NewCoins(), } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } } @@ -186,7 +188,7 @@ func SimulateMsgCancelAuction( ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { var simAccount simtypes.Account msg := &fundraisingtypes.MsgCancelAuction{} - auction, found := RandomAuction(ctx, r, fk) + auction, found := RandomAuctionStandby(ctx, r, fk) if !found { return simtypes.NoOpMsg(fundraisingtypes.ModuleName, msg.Type(), "no valid auction found"), nil, nil } @@ -207,7 +209,7 @@ func SimulateMsgCancelAuction( msg = fundraisingtypes.NewMsgCancelAuction(simAccount.Address.String(), auction.GetId()) - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -221,6 +223,6 @@ func SimulateMsgCancelAuction( ModuleName: fundraisingtypes.ModuleName, CoinsSpentInMsg: sdk.NewCoins(), } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } } diff --git a/x/participation/simulation/store.go b/x/participation/simulation/store.go index 7f8c3f287..27b4127d2 100644 --- a/x/participation/simulation/store.go +++ b/x/participation/simulation/store.go @@ -38,8 +38,8 @@ func RandomAccWithBalance(ctx sdk.Context, r *rand.Rand, return simtypes.Account{}, sdk.NewCoins(), false } -// RandomAuction returns random auction that is not started nor cancelled -func RandomAuction(ctx sdk.Context, r *rand.Rand, fk fundraisingkeeper.Keeper) (auction fundraisingtypes.AuctionI, found bool) { +// RandomAuctionStandby returns random auction that is in standby +func RandomAuctionStandby(ctx sdk.Context, r *rand.Rand, fk fundraisingkeeper.Keeper) (auction fundraisingtypes.AuctionI, found bool) { auctions := fk.GetAuctions(ctx) if len(auctions) == 0 { return auction, false @@ -59,6 +59,36 @@ func RandomAuction(ctx sdk.Context, r *rand.Rand, fk fundraisingkeeper.Keeper) ( return auction, false } +// RandomAuctionParticipationEnabled returns random auction where participation is enabled +func RandomAuctionParticipationEnabled( + ctx sdk.Context, + r *rand.Rand, + fk fundraisingkeeper.Keeper, + k keeper.Keeper, +) (auction fundraisingtypes.AuctionI, found bool) { + auctions := fk.GetAuctions(ctx) + if len(auctions) == 0 { + return auction, false + } + + r.Shuffle(len(auctions), func(i, j int) { + auctions[i], auctions[j] = auctions[j], auctions[i] + }) + + for _, a := range auctions { + if a.GetStatus() != fundraisingtypes.AuctionStatusStandBy { + continue + } + if !k.IsRegistrationEnabled(ctx, a.GetStartTime()) { + continue + } + auction = a + found = true + } + + return +} + // RandomAuctionWithdrawEnabled returns random auction where used allocations can be withdrawn at blockTime func RandomAuctionWithdrawEnabled( ctx sdk.Context, diff --git a/x/participation/simulation/store_test.go b/x/participation/simulation/store_test.go index c4ae965fd..10ada81e4 100644 --- a/x/participation/simulation/store_test.go +++ b/x/participation/simulation/store_test.go @@ -64,7 +64,7 @@ func TestRandomAccWithBalance(t *testing.T) { } } -func TestRandomAuction(t *testing.T) { +func TestRandomAuctionStandby(t *testing.T) { var ( r = sample.Rand() accs = simulation.RandomAccounts(r, 5) @@ -104,7 +104,7 @@ func TestRandomAuction(t *testing.T) { auction = fundraisingtypes.NewFixedPriceAuction(ba) tk.FundraisingKeeper.SetAuction(ctx, auction) - _, found := participationsim.RandomAuction(ctx, r, *tk.FundraisingKeeper) + _, found := participationsim.RandomAuctionStandby(ctx, r, *tk.FundraisingKeeper) require.False(t, found) }) @@ -119,7 +119,7 @@ func TestRandomAuction(t *testing.T) { auction1, found := tk.FundraisingKeeper.GetAuction(ctx, auctionID1) require.True(t, found) - got, found := participationsim.RandomAuction(ctx, r, *tk.FundraisingKeeper) + got, found := participationsim.RandomAuctionStandby(ctx, r, *tk.FundraisingKeeper) require.True(t, found) require.Equal(t, auction1, got) }) @@ -127,11 +127,59 @@ func TestRandomAuction(t *testing.T) { t.Run("no auctions", func(t *testing.T) { ctx, tk, _ := testkeeper.NewTestSetup(t) - _, found := participationsim.RandomAuction(ctx, r, *tk.FundraisingKeeper) + _, found := participationsim.RandomAuctionStandby(ctx, r, *tk.FundraisingKeeper) require.False(t, found) }) } +func TestRandomAuctionParticipationEnabled(t *testing.T) { + var ( + r = sample.Rand() + accs = simulation.RandomAccounts(r, 5) + sellingCoin = sample.Coin(r) + ctx, tk, _ = testkeeper.NewTestSetup(t) + registrationPeriod = time.Hour + ) + + params := tk.ParticipationKeeper.GetParams(ctx) + params.RegistrationPeriod = registrationPeriod + tk.ParticipationKeeper.SetParams(ctx, params) + + t.Run("no auctions", func(t *testing.T) { + _, found := participationsim.RandomAuctionParticipationEnabled(ctx, r, *tk.FundraisingKeeper, *tk.ParticipationKeeper) + require.False(t, found) + }) + + t.Run("no auction to be found that satisfy requirements", func(t *testing.T) { + startTime := ctx.BlockTime().Add(time.Hour * 10) + endTime := ctx.BlockTime().Add(time.Hour * 24 * 7) + + // initialize auction + tk.Mint(ctx, accs[0].Address.String(), sdk.NewCoins(sellingCoin)) + auctionID := tk.CreateFixedPriceAuction(ctx, r, accs[0].Address.String(), sellingCoin, startTime, endTime) + _, found := tk.FundraisingKeeper.GetAuction(ctx, auctionID) + require.True(t, found) + + _, found = participationsim.RandomAuctionParticipationEnabled(ctx, r, *tk.FundraisingKeeper, *tk.ParticipationKeeper) + require.False(t, found) + }) + + t.Run("one auction to be found", func(t *testing.T) { + startTime := ctx.BlockTime().Add(time.Minute * 30) + endTime := ctx.BlockTime().Add(time.Hour * 24 * 7) + + // initialize auction + tk.Mint(ctx, accs[0].Address.String(), sdk.NewCoins(sellingCoin)) + auctionID := tk.CreateFixedPriceAuction(ctx, r, accs[0].Address.String(), sellingCoin, startTime, endTime) + auction, found := tk.FundraisingKeeper.GetAuction(ctx, auctionID) + require.True(t, found) + + got, found := participationsim.RandomAuctionParticipationEnabled(ctx, r, *tk.FundraisingKeeper, *tk.ParticipationKeeper) + require.True(t, found) + require.Equal(t, auction, got) + }) +} + func TestRandomAuctionWithdrawEnabled(t *testing.T) { var ( ctx, tk, _ = testkeeper.NewTestSetup(t) diff --git a/x/profile/simulation/simulation.go b/x/profile/simulation/simulation.go index bcdf26b86..7999897b4 100644 --- a/x/profile/simulation/simulation.go +++ b/x/profile/simulation/simulation.go @@ -9,15 +9,16 @@ import ( simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/x/simulation" + sdksimulation "github.com/cosmos/cosmos-sdk/x/simulation" "github.com/tendermint/spn/testutil/sample" + "github.com/tendermint/spn/testutil/simulation" "github.com/tendermint/spn/x/profile/keeper" "github.com/tendermint/spn/x/profile/types" ) // generate a Tx with 2 signatures if validator account is not equal to operator address account -func genAndDeliverTxWithRandFeesAddOpAddr(txCtx simulation.OperationInput, opSimAcc simtypes.Account) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { +func genAndDeliverTxWithRandFeesAddOpAddr(txCtx sdksimulation.OperationInput, opSimAcc simtypes.Account) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { account := txCtx.AccountKeeper.GetAccount(txCtx.Context, txCtx.SimAccount.Address) spendable := txCtx.Bankkeeper.SpendableCoins(txCtx.Context, account.GetAddress()) opAccout := txCtx.AccountKeeper.GetAccount(txCtx.Context, opSimAcc.Address) @@ -40,7 +41,7 @@ func genAndDeliverTxWithRandFeesAddOpAddr(txCtx simulation.OperationInput, opSim return simtypes.NoOpMsg(txCtx.ModuleName, txCtx.MsgType, "message doesn't leave room for fees"), nil, err } - fees, err = simtypes.RandomFees(txCtx.R, txCtx.Context, coins) + fees, err = sample.Fees(txCtx.R, coins) if err != nil { return simtypes.NoOpMsg(txCtx.ModuleName, txCtx.MsgType, "unable to generate fees"), nil, err } @@ -85,7 +86,7 @@ func SimulateMsgUpdateValidatorDescription(ak types.AccountKeeper, bk types.Bank desc.SecurityContact, desc.Details, ) - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -99,7 +100,7 @@ func SimulateMsgUpdateValidatorDescription(ak types.AccountKeeper, bk types.Bank ModuleName: types.ModuleName, CoinsSpentInMsg: sdk.NewCoins(), } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } } @@ -120,7 +121,7 @@ func SimulateMsgAddValidatorOperatorAddress(ak types.AccountKeeper, bk types.Ban OperatorAddress: opAccount.Address.String(), } - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -156,7 +157,7 @@ func SimulateMsgCreateCoordinator(ak types.AccountKeeper, bk types.BankKeeper, k sample.String(r, 30), sample.String(r, 30), ) - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -170,7 +171,7 @@ func SimulateMsgCreateCoordinator(ak types.AccountKeeper, bk types.BankKeeper, k ModuleName: types.ModuleName, CoinsSpentInMsg: sdk.NewCoins(), } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } } @@ -194,7 +195,7 @@ func SimulateMsgUpdateCoordinatorDescription(ak types.AccountKeeper, bk types.Ba desc.Details, ) - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -208,7 +209,7 @@ func SimulateMsgUpdateCoordinatorDescription(ak types.AccountKeeper, bk types.Ba ModuleName: types.ModuleName, CoinsSpentInMsg: sdk.NewCoins(), } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } } @@ -228,7 +229,7 @@ func SimulateMsgUpdateCoordinatorAddress(ak types.AccountKeeper, bk types.BankKe return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgUpdateCoordinatorAddress, "skip update coordinator address"), nil, nil } msg := types.NewMsgUpdateCoordinatorAddress(coord.Address.String(), simAccount.Address.String()) - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -242,7 +243,7 @@ func SimulateMsgUpdateCoordinatorAddress(ak types.AccountKeeper, bk types.BankKe ModuleName: types.ModuleName, CoinsSpentInMsg: sdk.NewCoins(), } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } } @@ -260,7 +261,7 @@ func SimulateMsgDisableCoordinator(ak types.AccountKeeper, bk types.BankKeeper, } msg := types.NewMsgDisableCoordinator(simAccount.Address.String()) - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -274,6 +275,6 @@ func SimulateMsgDisableCoordinator(ak types.AccountKeeper, bk types.BankKeeper, ModuleName: types.ModuleName, CoinsSpentInMsg: sdk.NewCoins(), } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } } diff --git a/x/reward/keeper/reward_distribution_test.go b/x/reward/keeper/reward_distribution_test.go index 970f219cd..ce1308170 100644 --- a/x/reward/keeper/reward_distribution_test.go +++ b/x/reward/keeper/reward_distribution_test.go @@ -2,12 +2,12 @@ package keeper_test import ( "fmt" - spnerrors "github.com/tendermint/spn/pkg/errors" "testing" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" + spnerrors "github.com/tendermint/spn/pkg/errors" spntypes "github.com/tendermint/spn/pkg/types" tc "github.com/tendermint/spn/testutil/constructor" testkeeper "github.com/tendermint/spn/testutil/keeper" diff --git a/x/reward/simulation/simulation.go b/x/reward/simulation/simulation.go index 2e256a653..e02c3e7b6 100644 --- a/x/reward/simulation/simulation.go +++ b/x/reward/simulation/simulation.go @@ -4,11 +4,13 @@ import ( "math/rand" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/simapp/helpers" simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/x/simulation" + sdksimulation "github.com/cosmos/cosmos-sdk/x/simulation" + "github.com/tendermint/spn/testutil/simulation" "github.com/tendermint/spn/x/reward/keeper" "github.com/tendermint/spn/x/reward/types" ) @@ -84,7 +86,7 @@ func SimulateMsgSetRewards( msg.Coins = sdk.NewCoins() } - txCtx := simulation.OperationInput{ + txCtx := sdksimulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, @@ -99,6 +101,6 @@ func SimulateMsgSetRewards( CoinsSpentInMsg: wantCoin, } - return simulation.GenAndDeliverTxWithRandFees(txCtx) + return simulation.GenAndDeliverTxWithRandFees(txCtx, helpers.DefaultGenTxGas) } }