Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: fix epoch params #103

Merged
merged 24 commits into from
Sep 16, 2021
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
460cb71
feat: add global keys prefix for the current epoch days
jaybxyz Sep 13, 2021
ac49357
test: add test for key store prefixes
jaybxyz Sep 13, 2021
d25affb
chore: fix broken store prefix test, rename EpochDays to NextEpochDays
jaybxyz Sep 13, 2021
dcde757
test: add more tests and update address to have 20 bytes
jaybxyz Sep 14, 2021
75b527a
test: remove comments
jaybxyz Sep 14, 2021
2a5ecd2
Merge commit '14db7b773a339004f824410b3ec150fd340c91e7' into kogisin/…
jaybxyz Sep 14, 2021
3f128ad
test: update epoch days to next epoch days
jaybxyz Sep 14, 2021
95009e0
test: add handler tests
jaybxyz Sep 14, 2021
4e19116
refactor: add comment for global current epoch days
jaybxyz Sep 14, 2021
4a216b7
test: apply module testing suit
jaybxyz Sep 15, 2021
9569cde
Merge commit '600c2cc0597050f283a10a0128d9d56c9f7bb671' into kogisin/…
jaybxyz Sep 15, 2021
f8a0bd5
test: remove tests for deprecated PlansByFarmerIndex
jaybxyz Sep 15, 2021
f3c6df6
feat: move mustParseRFC3339 function to utils #109
jaybxyz Sep 15, 2021
9cc402b
docs: update spec docs
jaybxyz Sep 15, 2021
793bfe1
feat: adding test for end blocker
jaybxyz Sep 15, 2021
15a4d45
chore: rename GlobalCurrentEpochDays to CurrentEpochDays and refactor…
jaybxyz Sep 15, 2021
c594268
test: improve code coverage
jaybxyz Sep 15, 2021
7146c75
chore: apply code review feedbacks and suggestions
jaybxyz Sep 16, 2021
53f8d6f
feat: add gRPC query and cli for current epoch days
jaybxyz Sep 16, 2021
5f87e7f
Merge commit '9d7cd9cd397de91c39c07f388e83524458bc0bc2' into kogisin/…
jaybxyz Sep 16, 2021
83bfd7e
fix: apply code review feedbacks and suggestions
jaybxyz Sep 16, 2021
e9b77aa
fix: resolve conflicts
jaybxyz Sep 16, 2021
3760c11
Merge commit '1e6f94641f22d89210c5de7e92f6b268514751cd' into kogisin/…
jaybxyz Sep 16, 2021
33b41ad
fix: panic when unstake due to total stakings is not set
jaybxyz Sep 16, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,545 changes: 234 additions & 1,311 deletions client/docs/swagger-ui/swagger.yaml

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions proto/tendermint/farming/v1beta1/farming.proto
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ message Params {
(gogoproto.nullable) = false
];

// The universal epoch length in number of days. Every process for staking and
// reward distribution is executed with this epoch_days frequency
uint32 epoch_days = 2 [(gogoproto.moretags) = "yaml:\"epoch_days\""];
// next_epoch_days is the epoch length in number of days
// it updates internal parameter called CurrentEpochDays that is used to process
jaybxyz marked this conversation as resolved.
Show resolved Hide resolved
// staking and reward distribution in end blocker
uint32 next_epoch_days = 2 [(gogoproto.moretags) = "yaml:\"next_epoch_days\""];

// farming_fee_collector is the module account address to collect fees within the farming module
string farming_fee_collector = 3 [(gogoproto.moretags) = "yaml:\"farming_fee_collector\""];
Expand Down
3 changes: 3 additions & 0 deletions proto/tendermint/farming/v1beta1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ message GenesisState {
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"global_last_epoch_time\""
];

// current_epoch_days specifies the epoch used when allocating farming rewards in end blocker
uint32 current_epoch_days = 10;
}

// PlanRecord is used for import/export via genesis json.
Expand Down
13 changes: 13 additions & 0 deletions proto/tendermint/farming/v1beta1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ service Query {
rpc Plan(QueryPlanRequest) returns (QueryPlanResponse) {
option (google.api.http).get = "/cosmos/farming/v1beta1/plans/{plan_id}";
}

// CurrentEpochDays returns current epoch days.
rpc CurrentEpochDays(QueryCurrentEpochDaysRequest) returns (QueryCurrentEpochDaysResponse) {
option (google.api.http).get = "/cosmos/farming/v1beta1/current_epoch_days";
}
}

// QueryParamsRequest is the request type for the Query/Params RPC method.
Expand Down Expand Up @@ -62,3 +67,11 @@ message QueryPlanRequest {
message QueryPlanResponse {
google.protobuf.Any plan = 1 [(cosmos_proto.accepts_interface) = "PlanI"];
}

// QueryCurrentEpochDaysRequest is the request type for the Query/CurrentEpochDays RPC method.
message QueryCurrentEpochDaysRequest {}

// QuerCurrentEpochDaysResponse is the response type for the Query/CurrentEpochDays RPC method.
message QueryCurrentEpochDaysResponse {
uint32 current_epoch_days = 1;
}
11 changes: 9 additions & 2 deletions x/farming/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,25 @@ func EndBlocker(ctx sdk.Context, k keeper.Keeper) {
}
}

params := k.GetParams(ctx)
// CurrentEpochDays is intialized with the value of NextEpochDays in genesis and
// it is used here to prevent from affecting the epoch days for farming rewards allocation.
// Suppose NextEpochDays is 7 days and it is proposed to change the value to 1 day through governance proposal.
// Although the proposal is passed, farming rewards allocation should continue to proceed with 7 days and then it gets updated.
currentEpochDays := k.GetCurrentEpochDays(ctx)

lastEpochTime, found := k.GetLastEpochTime(ctx)
if !found {
k.SetLastEpochTime(ctx, ctx.BlockTime())
} else {
y, m, d := lastEpochTime.AddDate(0, 0, int(params.EpochDays)).Date()
y, m, d := lastEpochTime.AddDate(0, 0, int(currentEpochDays)).Date()
y2, m2, d2 := ctx.BlockTime().Date()
if y == y2 && m == m2 && d == d2 {
if err := k.AdvanceEpoch(ctx); err != nil {
panic(err)
}
if params := k.GetParams(ctx); params.NextEpochDays != currentEpochDays {
k.SetCurrentEpochDays(ctx, params.NextEpochDays)
}
}
}
}
64 changes: 64 additions & 0 deletions x/farming/abci_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package farming_test

import (
"time"

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

_ "github.com/stretchr/testify/suite"
)

func (suite *ModuleTestSuite) TestEndBlockerEpochDaysTest() {
epochDaysTest := func(formerEpochDays, targetNextEpochDays uint32) {
suite.SetupTest()

params := suite.keeper.GetParams(suite.ctx)
params.NextEpochDays = formerEpochDays
suite.keeper.SetParams(suite.ctx, params)
suite.keeper.SetCurrentEpochDays(suite.ctx, formerEpochDays)

t := types.ParseTime("2021-08-01T00:00:00Z")
suite.ctx = suite.ctx.WithBlockTime(t)
farming.EndBlocker(suite.ctx, suite.keeper)

lastEpochTime, _ := suite.keeper.GetLastEpochTime(suite.ctx)

for i := 1; i < 200; i++ {
t = t.Add(1 * time.Hour)
suite.ctx = suite.ctx.WithBlockTime(t)
farming.EndBlocker(suite.ctx, suite.keeper)

if i == 10 { // 10 hours passed
params := suite.keeper.GetParams(suite.ctx)
params.NextEpochDays = targetNextEpochDays
suite.keeper.SetParams(suite.ctx, params)
}

currentEpochDays := suite.keeper.GetCurrentEpochDays(suite.ctx)
t2, _ := suite.keeper.GetLastEpochTime(suite.ctx)

if uint32(i) == formerEpochDays*24 {
suite.Require().True(t2.After(lastEpochTime))
suite.Require().Equal(t2.Sub(lastEpochTime).Hours(), float64(formerEpochDays*24))
suite.Require().Equal(targetNextEpochDays, currentEpochDays)
}

if uint32(i) == formerEpochDays*24+targetNextEpochDays*24 {
suite.Require().Equal(t2.Sub(lastEpochTime).Hours(), float64(currentEpochDays*24))
suite.Require().Equal(targetNextEpochDays, currentEpochDays)
}

lastEpochTime = t2
}
}

// increasing case
epochDaysTest(1, 7)

// decreasing case
epochDaysTest(7, 1)

// stay case
epochDaysTest(1, 1)
}
62 changes: 27 additions & 35 deletions x/farming/client/cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package cli_test
import (
"fmt"
"testing"
"time"

"github.com/gogo/protobuf/proto"
"github.com/stretchr/testify/suite"
Expand All @@ -19,6 +18,7 @@ import (

"github.com/tendermint/farming/x/farming/client/cli"
farmingtestutil "github.com/tendermint/farming/x/farming/client/testutil"
"github.com/tendermint/farming/x/farming/types"
farmingtypes "github.com/tendermint/farming/x/farming/types"
)

Expand Down Expand Up @@ -82,8 +82,8 @@ func (s *IntegrationTestSuite) TestNewCreateFixedAmountPlanCmd() {
case1 := cli.PrivateFixedPlanRequest{
Name: name,
StakingCoinWeights: coinWeights,
StartTime: mustParseRFC3339("0001-01-01T00:00:00Z"),
EndTime: mustParseRFC3339("9999-01-01T00:00:00Z"),
StartTime: types.ParseTime("0001-01-01T00:00:00Z"),
EndTime: types.ParseTime("9999-01-01T00:00:00Z"),
EpochAmount: sdk.NewCoins(sdk.NewInt64Coin("uatom", 100_000_000)),
}

Expand All @@ -94,44 +94,44 @@ func (s *IntegrationTestSuite) TestNewCreateFixedAmountPlanCmd() {
OVERMAXLENGTHOVERMAXLENGTHOVERMAXLENGTHOVERMOVERMAXLENGTHOVERMAXLENGTHOVERMAXLENGTHOVERM
OVERMAXLENGTHOVERMAXLENGTHOVERMAXLENGTHOVERMOVERMAXLENGTHOVERMAXLENGTHOVERMAXLENGTHOVERM`,
StakingCoinWeights: sdk.NewDecCoins(),
StartTime: mustParseRFC3339("0001-01-01T00:00:00Z"),
EndTime: mustParseRFC3339("9999-01-01T00:00:00Z"),
StartTime: types.ParseTime("0001-01-01T00:00:00Z"),
EndTime: types.ParseTime("9999-01-01T00:00:00Z"),
EpochAmount: sdk.NewCoins(sdk.NewInt64Coin("uatom", 100_000_000)),
}

// invalid staking coin weights
case3 := cli.PrivateFixedPlanRequest{
Name: name,
StakingCoinWeights: sdk.NewDecCoins(),
StartTime: mustParseRFC3339("0001-01-01T00:00:00Z"),
EndTime: mustParseRFC3339("9999-01-01T00:00:00Z"),
StartTime: types.ParseTime("0001-01-01T00:00:00Z"),
EndTime: types.ParseTime("9999-01-01T00:00:00Z"),
EpochAmount: sdk.NewCoins(sdk.NewInt64Coin("uatom", 100_000_000)),
}

// invalid staking coin weights
case4 := cli.PrivateFixedPlanRequest{
Name: name,
StakingCoinWeights: sdk.NewDecCoins(sdk.NewDecCoin("poolD35A0CC16EE598F90B044CE296A405BA9C381E38837599D96F2F70C2F02A23A4", sdk.NewInt(2))),
StartTime: mustParseRFC3339("0001-01-01T00:00:00Z"),
EndTime: mustParseRFC3339("9999-01-01T00:00:00Z"),
StartTime: types.ParseTime("0001-01-01T00:00:00Z"),
EndTime: types.ParseTime("9999-01-01T00:00:00Z"),
EpochAmount: sdk.NewCoins(sdk.NewInt64Coin("uatom", 100_000_000)),
}

// invalid start time and end time
case5 := cli.PrivateFixedPlanRequest{
Name: name,
StakingCoinWeights: coinWeights,
StartTime: mustParseRFC3339("2021-08-13T00:00:00Z"),
EndTime: mustParseRFC3339("2021-08-06T00:00:00Z"),
StartTime: types.ParseTime("2021-08-13T00:00:00Z"),
EndTime: types.ParseTime("2021-08-06T00:00:00Z"),
EpochAmount: sdk.NewCoins(sdk.NewInt64Coin("uatom", 100_000_000)),
}

// invalid epoch amount
case6 := cli.PrivateFixedPlanRequest{
Name: name,
StakingCoinWeights: coinWeights,
StartTime: mustParseRFC3339("0001-01-01T00:00:00Z"),
EndTime: mustParseRFC3339("9999-01-01T00:00:00Z"),
StartTime: types.ParseTime("0001-01-01T00:00:00Z"),
EndTime: types.ParseTime("9999-01-01T00:00:00Z"),
EpochAmount: sdk.NewCoins(sdk.NewInt64Coin("uatom", 0)),
}

Expand Down Expand Up @@ -247,8 +247,8 @@ func (s *IntegrationTestSuite) TestNewCreateRatioPlanCmd() {
case1 := cli.PrivateRatioPlanRequest{
Name: name,
StakingCoinWeights: coinWeights,
StartTime: mustParseRFC3339("0001-01-01T00:00:00Z"),
EndTime: mustParseRFC3339("9999-01-01T00:00:00Z"),
StartTime: types.ParseTime("0001-01-01T00:00:00Z"),
EndTime: types.ParseTime("9999-01-01T00:00:00Z"),
EpochRatio: sdk.MustNewDecFromStr("0.1"),
}

Expand All @@ -259,44 +259,44 @@ func (s *IntegrationTestSuite) TestNewCreateRatioPlanCmd() {
OVERMAXLENGTHOVERMAXLENGTHOVERMAXLENGTHOVERMOVERMAXLENGTHOVERMAXLENGTHOVERMAXLENGTHOVERM
OVERMAXLENGTHOVERMAXLENGTHOVERMAXLENGTHOVERMOVERMAXLENGTHOVERMAXLENGTHOVERMAXLENGTHOVERM`,
StakingCoinWeights: sdk.NewDecCoins(),
StartTime: mustParseRFC3339("0001-01-01T00:00:00Z"),
EndTime: mustParseRFC3339("9999-01-01T00:00:00Z"),
StartTime: types.ParseTime("0001-01-01T00:00:00Z"),
EndTime: types.ParseTime("9999-01-01T00:00:00Z"),
EpochRatio: sdk.MustNewDecFromStr("0.1"),
}

// invalid staking coin weights
case3 := cli.PrivateRatioPlanRequest{
Name: name,
StakingCoinWeights: sdk.NewDecCoins(),
StartTime: mustParseRFC3339("0001-01-01T00:00:00Z"),
EndTime: mustParseRFC3339("9999-01-01T00:00:00Z"),
StartTime: types.ParseTime("0001-01-01T00:00:00Z"),
EndTime: types.ParseTime("9999-01-01T00:00:00Z"),
EpochRatio: sdk.MustNewDecFromStr("0.1"),
}

// invalid staking coin weights
case4 := cli.PrivateRatioPlanRequest{
Name: name,
StakingCoinWeights: sdk.NewDecCoins(sdk.NewDecCoin("poolD35A0CC16EE598F90B044CE296A405BA9C381E38837599D96F2F70C2F02A23A4", sdk.NewInt(2))),
StartTime: mustParseRFC3339("0001-01-01T00:00:00Z"),
EndTime: mustParseRFC3339("9999-01-01T00:00:00Z"),
StartTime: types.ParseTime("0001-01-01T00:00:00Z"),
EndTime: types.ParseTime("9999-01-01T00:00:00Z"),
EpochRatio: sdk.MustNewDecFromStr("0.1"),
}

// invalid start time and end time
case5 := cli.PrivateRatioPlanRequest{
Name: name,
StakingCoinWeights: coinWeights,
StartTime: mustParseRFC3339("2021-08-13T00:00:00Z"),
EndTime: mustParseRFC3339("2021-08-06T00:00:00Z"),
StartTime: types.ParseTime("2021-08-13T00:00:00Z"),
EndTime: types.ParseTime("2021-08-06T00:00:00Z"),
EpochRatio: sdk.MustNewDecFromStr("0.1"),
}

// invalid epoch ratio
case6 := cli.PrivateRatioPlanRequest{
Name: name,
StakingCoinWeights: coinWeights,
StartTime: mustParseRFC3339("0001-01-01T00:00:00Z"),
EndTime: mustParseRFC3339("9999-01-01T00:00:00Z"),
StartTime: types.ParseTime("0001-01-01T00:00:00Z"),
EndTime: types.ParseTime("9999-01-01T00:00:00Z"),
EpochRatio: sdk.MustNewDecFromStr("1.1"),
}

Expand Down Expand Up @@ -525,8 +525,8 @@ func (s *IntegrationTestSuite) TestNewHarvestCmd() {
req := cli.PrivateFixedPlanRequest{
Name: "test",
StakingCoinWeights: sdk.NewDecCoins(sdk.NewDecCoin("stake", sdk.NewInt(1))),
StartTime: mustParseRFC3339("0001-01-01T00:00:00Z"),
EndTime: mustParseRFC3339("9999-01-01T00:00:00Z"),
StartTime: types.ParseTime("0001-01-01T00:00:00Z"),
EndTime: types.ParseTime("9999-01-01T00:00:00Z"),
EpochAmount: sdk.NewCoins(sdk.NewInt64Coin("node0token", 100_000_000)),
}

Expand Down Expand Up @@ -601,11 +601,3 @@ func (s *IntegrationTestSuite) TestNewHarvestCmd() {
})
}
}

func mustParseRFC3339(s string) time.Time {
t, err := time.Parse(time.RFC3339, s)
if err != nil {
panic(err)
}
return t
}
37 changes: 37 additions & 0 deletions x/farming/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func GetQueryCmd() *cobra.Command {
GetCmdQueryParams(),
GetCmdQueryPlans(),
GetCmdQueryPlan(),
GetCmdQueryCurrentEpochDays(),
)

return farmingQueryCmd
Expand Down Expand Up @@ -188,3 +189,39 @@ $ %s query %s plan

return cmd
}

func GetCmdQueryCurrentEpochDays() *cobra.Command {
cmd := &cobra.Command{
Use: "current-epoch-days",
Args: cobra.NoArgs,
Short: "Query the value of current epoch days",
Long: strings.TrimSpace(
fmt.Sprintf(`Query the value set as current epoch days.

Example:
$ %s query %s current-epoch-days
`,
version.AppName, types.ModuleName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

queryClient := types.NewQueryClient(clientCtx)

resp, err := queryClient.CurrentEpochDays(context.Background(), &types.QueryCurrentEpochDaysRequest{})
if err != nil {
return err
}

return clientCtx.PrintProto(resp)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}
Loading