Skip to content

Commit

Permalink
chore: fix simulation logic, add minter permission to module account,…
Browse files Browse the repository at this point in the history
… work in progress to solve harvest issue
  • Loading branch information
jaybxyz committed Sep 6, 2021
1 parent 2d25621 commit a7d3e70
Show file tree
Hide file tree
Showing 7 changed files with 294 additions and 77 deletions.
11 changes: 10 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ var (
stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking},
stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking},
govtypes.ModuleName: {authtypes.Burner},
farmingtypes.ModuleName: nil,
farmingtypes.ModuleName: {authtypes.Minter},
// todo: farming Staking Reserve Coin TBD
}
)
Expand Down Expand Up @@ -580,6 +580,15 @@ func RegisterSwaggerAPI(ctx client.Context, rtr *mux.Router) {
rtr.PathPrefix("/swagger/").Handler(http.StripPrefix("/swagger/", staticServer))
}

// GetMaccPerms returns a copy of the module account permissions
func GetMaccPerms() map[string][]string {
dupMaccPerms := make(map[string][]string)
for k, v := range maccPerms {
dupMaccPerms[k] = v
}
return dupMaccPerms
}

// initParamsKeeper init params keeper and its subspaces
func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey sdk.StoreKey) paramskeeper.Keeper {
paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey)
Expand Down
2 changes: 1 addition & 1 deletion app/params/weights.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ const (
DefaultWeightMsgCreateFixedAmountPlan int = 10
DefaultWeightMsgCreateRatioPlan int = 10
DefaultWeightMsgStake int = 85
DefaultWeightMsgUnstake int = 50
DefaultWeightMsgUnstake int = 30
DefaultWeightMsgHarvest int = 30
)
16 changes: 9 additions & 7 deletions x/farming/simulation/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/kv"

"github.com/tendermint/farming/x/farming/types"
Expand All @@ -15,27 +16,28 @@ import (
func NewDecodeStore(cdc codec.Codec) func(kvA, kvB kv.Pair) string {
return func(kvA, kvB kv.Pair) string {
switch {
case bytes.Equal(kvA.Key[:1], types.PlanKeyPrefix),
bytes.Equal(kvA.Key[:1], types.PlansByFarmerIndexKeyPrefix):
case bytes.Equal(kvA.Key[:1], types.PlanKeyPrefix):
var pA, pB types.BasePlan
cdc.MustUnmarshal(kvA.Value, &pA)
cdc.MustUnmarshal(kvA.Value, &pB)
return fmt.Sprintf("%v\n%v", pA, pB)

case bytes.Equal(kvA.Key[:1], types.StakingKeyPrefix),
bytes.Equal(kvA.Key[:1], types.StakingByFarmerIndexKeyPrefix),
bytes.Equal(kvA.Key[:1], types.StakingsByStakingCoinDenomIndexKeyPrefix):
case bytes.Equal(kvA.Key[:1], types.StakingKeyPrefix):
var sA, sB types.Staking
cdc.MustUnmarshal(kvA.Value, &sA)
cdc.MustUnmarshal(kvA.Value, &sB)
return fmt.Sprintf("%v\n%v", sA, sB)

case bytes.Equal(kvA.Key[:1], types.RewardKeyPrefix),
bytes.Equal(kvA.Key[:1], types.RewardsByFarmerIndexKeyPrefix):
case bytes.Equal(kvA.Key[:1], types.RewardKeyPrefix):
var rA, rB types.Reward
cdc.MustUnmarshal(kvA.Value, &rA)
return fmt.Sprintf("%v\n%v", rA, rB)

case bytes.Equal(kvA.Key[:1], types.PlansByFarmerIndexKeyPrefix),
bytes.Equal(kvA.Key[:1], types.StakingByFarmerIndexKeyPrefix),
bytes.Equal(kvA.Key[:1], types.RewardsByFarmerIndexKeyPrefix):
return fmt.Sprintf("%v\n%v", sdk.AccAddress(kvA.Value), sdk.AccAddress(kvB.Value))

default:
panic(fmt.Sprintf("invalid farming key prefix %X", kvA.Key[:1]))
}
Expand Down
46 changes: 38 additions & 8 deletions x/farming/simulation/decoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,45 @@ import (

"github.com/stretchr/testify/require"

"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/kv"

"github.com/tendermint/farming/x/farming/simulation"
"github.com/tendermint/farming/x/farming/types"
)

// case bytes.Equal(kvA.Key[:1], types.PlanKeyPrefix):
// var pA, pB types.BasePlan
// cdc.MustUnmarshal(kvA.Value, &pA)
// cdc.MustUnmarshal(kvA.Value, &pB)
// return fmt.Sprintf("%v\n%v", pA, pB)

// case bytes.Equal(kvA.Key[:1], types.PlansByFarmerIndexKeyPrefix),
// bytes.Equal(kvA.Key[:1], types.StakingByFarmerIndexKeyPrefix),
// bytes.Equal(kvA.Key[:1], types.RewardsByFarmerIndexKeyPrefix):
// return fmt.Sprintf("%v\n%v", sdk.AccAddress(kvA.Value), sdk.AccAddress(kvB.Value))

// case bytes.Equal(kvA.Key[:1], types.StakingKeyPrefix):
// var sA, sB types.Staking
// cdc.MustUnmarshal(kvA.Value, &sA)
// cdc.MustUnmarshal(kvA.Value, &sB)
// return fmt.Sprintf("%v\n%v", sA, sB)

// case bytes.Equal(kvA.Key[:1], types.StakingsByStakingCoinDenomIndexKeyPrefix):
// return fmt.Sprintf("%s\n%s", kvA.Value, kvB.Value)

// case bytes.Equal(kvA.Key[:1], types.RewardKeyPrefix):
// var rA, rB types.Reward
// cdc.MustUnmarshal(kvA.Value, &rA)
// return fmt.Sprintf("%v\n%v", rA, rB)

var (
pk1 = ed25519.GenPrivKey().PubKey()
farmerAddr1 = sdk.AccAddress(pk1.Address())
)

func TestDecodeFarmingStore(t *testing.T) {
cdc := simapp.MakeTestEncodingConfig().Marshaler
dec := simulation.NewDecodeStore(cdc)
Expand All @@ -24,12 +56,11 @@ func TestDecodeFarmingStore(t *testing.T) {
kvPairs := kv.Pairs{
Pairs: []kv.Pair{
{Key: types.PlanKeyPrefix, Value: cdc.MustMarshal(&basePlan)},
{Key: types.PlansByFarmerIndexKeyPrefix, Value: cdc.MustMarshal(&basePlan)},
{Key: types.StakingKeyPrefix, Value: cdc.MustMarshal(&staking)},
{Key: types.StakingByFarmerIndexKeyPrefix, Value: cdc.MustMarshal(&staking)},
{Key: types.StakingsByStakingCoinDenomIndexKeyPrefix, Value: cdc.MustMarshal(&staking)},
{Key: types.RewardKeyPrefix, Value: cdc.MustMarshal(&reward)},
{Key: types.RewardsByFarmerIndexKeyPrefix, Value: cdc.MustMarshal(&reward)},
{Key: types.PlansByFarmerIndexKeyPrefix, Value: farmerAddr1.Bytes()},
{Key: types.StakingByFarmerIndexKeyPrefix, Value: farmerAddr1.Bytes()},
{Key: types.RewardsByFarmerIndexKeyPrefix, Value: farmerAddr1.Bytes()},
{Key: []byte{0x99}, Value: []byte{0x99}},
},
}
Expand All @@ -39,12 +70,11 @@ func TestDecodeFarmingStore(t *testing.T) {
expectedLog string
}{
{"Plan", fmt.Sprintf("%v\n%v", basePlan, basePlan)},
{"Plans", fmt.Sprintf("%v\n%v", basePlan, basePlan)},
{"Staking", fmt.Sprintf("%v\n%v", staking, staking)},
{"StakingByFarmer", fmt.Sprintf("%v\n%v", staking, staking)},
{"Stakings", fmt.Sprintf("%v\n%v", staking, staking)},
{"Reward", fmt.Sprintf("%v\n%v", reward, reward)},
{"Rewards", fmt.Sprintf("%v\n%v", reward, reward)},
{"PlansByFarmerIndex", fmt.Sprintf("%v\n%v", farmerAddr1, farmerAddr1)},
{"StakingByFarmerIndex", fmt.Sprintf("%v\n%v", farmerAddr1, farmerAddr1)},
{"RewardsByFarmerIndex", fmt.Sprintf("%v\n%v", farmerAddr1, farmerAddr1)},
{"other", ""},
}
for i, tt := range tests {
Expand Down
6 changes: 3 additions & 3 deletions x/farming/simulation/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ const (

// GenPrivatePlanCreationFee return randomized private plan creation fee.
func GenPrivatePlanCreationFee(r *rand.Rand) sdk.Coins {
return sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, int64(simulation.RandIntBetween(r, 0, 1_000_000_000))))
return sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, int64(simulation.RandIntBetween(r, 0, 100_000_000))))
}

// GenStakingCreationFee return randomized staking creation fee.
func GenStakingCreationFee(r *rand.Rand) sdk.Coins {
return sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, int64(simulation.RandIntBetween(r, 0, 1_000_000_000))))
return sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, int64(simulation.RandIntBetween(r, 0, 100_000_000))))
}

// GenEpochDays return default EpochDays.
// GenEpochDays return default epoch days.
func GenEpochDays(r *rand.Rand) uint32 {
return uint32(simulation.RandIntBetween(r, int(types.DefaultEpochDays), 10))
}
Expand Down
105 changes: 82 additions & 23 deletions x/farming/simulation/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package simulation

import (
"math/rand"
"time"

"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
Expand Down Expand Up @@ -107,16 +106,28 @@ func SimulateMsgCreateFixedAmountPlan(ak types.AccountKeeper, bk types.BankKeepe
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgCreateFixedAmountPlan, "insufficient balance for plan creation fee"), nil, nil
}

poolCoins, err := mintPoolCoins(ctx, r, bk, simAccount)
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgCreateFixedAmountPlan, "unable to mint pool coins"), nil, nil
}

name := "simulation"
creatorAcc := account.GetAddress()
stakingCoinWeights := sdk.NewDecCoins(sdk.NewInt64DecCoin(sdk.DefaultBondDenom, 1))
startTime := time.Now().UTC()
endTime := startTime.AddDate(0, 0, 1)
startTime := ctx.BlockTime()
endTime := startTime.AddDate(0, 1, 0)
epochAmount := sdk.NewCoins(
sdk.NewInt64Coin(sdk.DefaultBondDenom, int64(simtypes.RandIntBetween(r, 1_000_000, 1_000_000_000))),
sdk.NewInt64Coin(poolCoins[r.Intn(3)].Denom, int64(simtypes.RandIntBetween(r, 10_000_000, 1_000_000_000))),
)

msg := types.NewMsgCreateFixedAmountPlan(name, creatorAcc, stakingCoinWeights, startTime, endTime, epochAmount)
msg := types.NewMsgCreateFixedAmountPlan(
name,
creatorAcc,
stakingCoinWeights,
startTime,
endTime,
epochAmount,
)

txCtx := simulation.OperationInput{
R: r,
Expand Down Expand Up @@ -154,14 +165,26 @@ func SimulateMsgCreateRatioPlan(ak types.AccountKeeper, bk types.BankKeeper, k k
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgCreateRatioPlan, "insufficient balance for plan creation fee"), nil, nil
}

_, err := mintPoolCoins(ctx, r, bk, simAccount)
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgCreateFixedAmountPlan, "unable to mint pool coins"), nil, nil
}

name := "simulation"
creatorAcc := account.GetAddress()
stakingCoinWeights := sdk.NewDecCoins(sdk.NewInt64DecCoin(sdk.DefaultBondDenom, 1))
startTime := time.Now().UTC()
endTime := startTime.AddDate(0, 0, 1)
startTime := ctx.BlockTime()
endTime := startTime.AddDate(0, 1, 0)
epochRatio := sdk.NewDecWithPrec(int64(simtypes.RandIntBetween(r, 1, 10)), 1)

msg := types.NewMsgCreateRatioPlan(name, creatorAcc, stakingCoinWeights, startTime, endTime, epochRatio)
msg := types.NewMsgCreateRatioPlan(
name,
creatorAcc,
stakingCoinWeights,
startTime,
endTime,
epochRatio,
)

txCtx := simulation.OperationInput{
R: r,
Expand Down Expand Up @@ -195,11 +218,11 @@ func SimulateMsgStake(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keep

farmer := account.GetAddress()
stakingCoins := sdk.NewCoins(
sdk.NewInt64Coin(sdk.DefaultBondDenom, int64(simtypes.RandIntBetween(r, 1_000_000, 100_000_000))),
sdk.NewInt64Coin(sdk.DefaultBondDenom, int64(simtypes.RandIntBetween(r, 1_000_000, 1_000_000_000))),
)

params := k.GetParams(ctx)
_, hasNeg := spendable.SafeSub(params.StakingCreationFee.Add(stakingCoins...))
_, hasNeg := spendable.SafeSub(stakingCoins.Add(params.StakingCreationFee...))
if hasNeg {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgStake, "insufficient balance for staking creation fee"), nil, nil
}
Expand Down Expand Up @@ -247,10 +270,16 @@ func SimulateMsgUnstake(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Ke
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgUnstake, "unable to find staking"), nil, nil
}

// sum of staked and queued coins must be greater than unstaking coins
if !staking.StakedCoins.Add(staking.QueuedCoins...).IsAllGTE(unstakingCoins) {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgUnstake, "insufficient funds"), nil, nil
}

// spendable must be greater than unstaking coins
if !spendable.IsAllGT(unstakingCoins) {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgUnstake, "insufficient funds"), nil, nil
}

msg := types.NewMsgUnstake(farmer, unstakingCoins)

txCtx := simulation.OperationInput{
Expand Down Expand Up @@ -278,28 +307,36 @@ func SimulateMsgHarvest(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Ke
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
simAccount, _ := simtypes.RandomAcc(r, accs)
// TODO: not fully implemented yet. It needs debugging why
// there are no rewards although it processes queued coins and distribute rewards
stakings := k.GetAllStakings(ctx)
if len(stakings) == 0 {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgHarvest, "unable to find any staking"), nil, nil
}

account := ak.GetAccount(ctx, simAccount.Address)
spendable := bk.SpendableCoins(ctx, account.GetAddress())
var simAccount simtypes.Account
simAccount.Address = stakings[r.Intn(len(stakings))].GetFarmer()

farmer := account.GetAddress()
stakingCoinDenoms := []string{sdk.DefaultBondDenom}

// add a day to increase epoch if there is no harvest rewards
rewards := k.GetRewardsByFarmer(ctx, farmer)
if len(rewards) == 0 {
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(0, 0, 1))
k.ProcessQueuedCoins(ctx)
// process queued coins and distribute rewards relative to the current epoch days
params := k.GetParams(ctx)
k.ProcessQueuedCoins(ctx)
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(0, 0, int(params.EpochDays)))
for i := 0; i < int(params.EpochDays); i++ {
if err := k.DistributeRewards(ctx); err != nil {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgHarvest, "unable to distribute rewards"), nil, nil
}
k.SetLastEpochTime(ctx, ctx.BlockTime())
}
k.SetLastEpochTime(ctx, ctx.BlockTime())

rewards := k.GetRewardsByFarmer(ctx, simAccount.Address)
if len(rewards) == 0 {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgHarvest, "no rewards to harvest"), nil, nil
}

msg := types.NewMsgHarvest(farmer, stakingCoinDenoms)
account := ak.GetAccount(ctx, simAccount.Address)
spendable := bk.SpendableCoins(ctx, account.GetAddress())

msg := types.NewMsgHarvest(simAccount.Address, []string{sdk.DefaultBondDenom})

txCtx := simulation.OperationInput{
R: r,
Expand All @@ -319,3 +356,25 @@ func SimulateMsgHarvest(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Ke
return simulation.GenAndDeliverTxWithRandFees(txCtx)
}
}

// mintPoolCoins mints random amount of coins with the provided pool coin denoms and
// send them to the simulated account.
func mintPoolCoins(ctx sdk.Context, r *rand.Rand, bk types.BankKeeper, acc simtypes.Account) (mintCoins sdk.Coins, err error) {
for _, denom := range []string{
"pool93E069B333B5ECEBFE24C6E1437E814003248E0DD7FF8B9F82119F4587449BA5",
"pool3036F43CB8131A1A63D2B3D3B11E9CF6FA2A2B6FEC17D5AD283C25C939614A8C",
"poolE4D2617BFE03E1146F6BBA1D9893F2B3D77BA29E7ED532BB721A39FF1ECC1B07",
} {
mintCoins = mintCoins.Add(sdk.NewInt64Coin(denom, int64(simtypes.RandIntBetween(r, 1e14, 1e15))))
}

if err := bk.MintCoins(ctx, types.ModuleName, mintCoins); err != nil {
return nil, err
}

if err := bk.SendCoinsFromModuleToAccount(ctx, types.ModuleName, acc.Address, mintCoins); err != nil {
return nil, err
}

return mintCoins, nil
}
Loading

0 comments on commit a7d3e70

Please sign in to comment.