mirror of
				https://github.com/0glabs/0g-chain.git
				synced 2025-11-04 11:37:27 +00:00 
			
		
		
		
	x/incentive: genesis validation (#519)
* x/incentive: genesis validation * validation funcs for arrays * tests * genesis tests * rewards tests * address @alexanderbez comments * fix genesis incentive simulation
This commit is contained in:
		
							parent
							
								
									b2edeb8549
								
							
						
					
					
						commit
						d130734c2e
					
				@ -48,8 +48,8 @@ func genParams(r *rand.Rand) types.Params {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// genRewards generates rewards for each specified collateral type
 | 
					// genRewards generates rewards for each specified collateral type
 | 
				
			||||||
func genRewards(r *rand.Rand) types.Rewards {
 | 
					func genRewards(r *rand.Rand) types.Rewards {
 | 
				
			||||||
	var rewards types.Rewards
 | 
						rewards := make(types.Rewards, len(CollateralDenoms))
 | 
				
			||||||
	for _, denom := range CollateralDenoms {
 | 
						for i, denom := range CollateralDenoms {
 | 
				
			||||||
		active := true
 | 
							active := true
 | 
				
			||||||
		// total reward is in range (half max total reward, max total reward)
 | 
							// total reward is in range (half max total reward, max total reward)
 | 
				
			||||||
		amount := simulation.RandIntBetween(r, int(MaxTotalAssetReward.Int64()/2), int(MaxTotalAssetReward.Int64()))
 | 
							amount := simulation.RandIntBetween(r, int(MaxTotalAssetReward.Int64()/2), int(MaxTotalAssetReward.Int64()))
 | 
				
			||||||
@ -59,32 +59,29 @@ func genRewards(r *rand.Rand) types.Rewards {
 | 
				
			|||||||
		duration := time.Duration(time.Hour * time.Duration(numbHours))
 | 
							duration := time.Duration(time.Hour * time.Duration(numbHours))
 | 
				
			||||||
		timeLock := time.Duration(time.Hour * time.Duration(numbHours/2)) // half as long as duration
 | 
							timeLock := time.Duration(time.Hour * time.Duration(numbHours/2)) // half as long as duration
 | 
				
			||||||
		claimDuration := time.Hour * time.Duration(numbHours*2)           // twice as long as duration
 | 
							claimDuration := time.Hour * time.Duration(numbHours*2)           // twice as long as duration
 | 
				
			||||||
		reward := types.NewReward(active, denom, totalRewards, duration, timeLock, claimDuration)
 | 
							rewards[i] = types.NewReward(active, denom, totalRewards, duration, timeLock, claimDuration)
 | 
				
			||||||
		rewards = append(rewards, reward)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return rewards
 | 
						return rewards
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// genRewardPeriods generates chronological reward periods for each given reward type
 | 
					// genRewardPeriods generates chronological reward periods for each given reward type
 | 
				
			||||||
func genRewardPeriods(r *rand.Rand, timestamp time.Time, rewards types.Rewards) types.RewardPeriods {
 | 
					func genRewardPeriods(r *rand.Rand, timestamp time.Time, rewards types.Rewards) types.RewardPeriods {
 | 
				
			||||||
	var rewardPeriods types.RewardPeriods
 | 
						rewardPeriods := make(types.RewardPeriods, len(rewards))
 | 
				
			||||||
	for _, reward := range rewards {
 | 
						rewardPeriodStart := timestamp
 | 
				
			||||||
		rewardPeriodStart := timestamp
 | 
					
 | 
				
			||||||
		for i := 10; i >= simulation.RandIntBetween(r, 2, 9); i-- {
 | 
						for i, reward := range rewards {
 | 
				
			||||||
			// Set up reward period parameters
 | 
							// Set up reward period parameters
 | 
				
			||||||
			start := rewardPeriodStart
 | 
							start := rewardPeriodStart
 | 
				
			||||||
			end := start.Add(reward.Duration).UTC()
 | 
							end := start.Add(reward.Duration).UTC()
 | 
				
			||||||
			baseRewardAmount := reward.AvailableRewards.Amount.Quo(sdk.NewInt(100)) // base period reward is 1/100 total reward
 | 
							baseRewardAmount := reward.AvailableRewards.Amount.Quo(sdk.NewInt(100)) // base period reward is 1/100 total reward
 | 
				
			||||||
			// Earlier periods have larger rewards
 | 
							// Earlier periods have larger rewards
 | 
				
			||||||
			amount := sdk.NewCoin(reward.Denom, baseRewardAmount.Mul(sdk.NewInt(int64(i))))
 | 
							amount := sdk.NewCoin(reward.Denom, baseRewardAmount.Mul(sdk.NewInt(int64(i))))
 | 
				
			||||||
			claimEnd := end.Add(reward.ClaimDuration)
 | 
							claimEnd := end.Add(reward.ClaimDuration)
 | 
				
			||||||
			claimTimeLock := reward.TimeLock
 | 
							claimTimeLock := reward.TimeLock
 | 
				
			||||||
			// Create reward period and append to array
 | 
							// Create reward period and append to array
 | 
				
			||||||
			rewardPeriod := types.NewRewardPeriod(reward.Denom, start, end, amount, claimEnd, claimTimeLock)
 | 
							rewardPeriods[i] = types.NewRewardPeriod(reward.Denom, start, end, amount, claimEnd, claimTimeLock)
 | 
				
			||||||
			rewardPeriods = append(rewardPeriods, rewardPeriod)
 | 
							// Update start time of next reward period
 | 
				
			||||||
			// Update start time of next reward period
 | 
							rewardPeriodStart = end
 | 
				
			||||||
			rewardPeriodStart = end
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return rewardPeriods
 | 
						return rewardPeriods
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -92,8 +89,8 @@ func genRewardPeriods(r *rand.Rand, timestamp time.Time, rewards types.Rewards)
 | 
				
			|||||||
// genClaimPeriods loads valid claim periods for an array of reward periods
 | 
					// genClaimPeriods loads valid claim periods for an array of reward periods
 | 
				
			||||||
func genClaimPeriods(rewardPeriods types.RewardPeriods) types.ClaimPeriods {
 | 
					func genClaimPeriods(rewardPeriods types.RewardPeriods) types.ClaimPeriods {
 | 
				
			||||||
	denomRewardPeriodsCount := make(map[string]uint64)
 | 
						denomRewardPeriodsCount := make(map[string]uint64)
 | 
				
			||||||
	var claimPeriods types.ClaimPeriods
 | 
						claimPeriods := make(types.ClaimPeriods, len(rewardPeriods))
 | 
				
			||||||
	for _, rewardPeriod := range rewardPeriods {
 | 
						for i, rewardPeriod := range rewardPeriods {
 | 
				
			||||||
		// Increment reward period count for this denom (this is our claim period's ID)
 | 
							// Increment reward period count for this denom (this is our claim period's ID)
 | 
				
			||||||
		denom := rewardPeriod.Denom
 | 
							denom := rewardPeriod.Denom
 | 
				
			||||||
		numbRewardPeriods := denomRewardPeriodsCount[denom] + 1
 | 
							numbRewardPeriods := denomRewardPeriodsCount[denom] + 1
 | 
				
			||||||
@ -102,8 +99,7 @@ func genClaimPeriods(rewardPeriods types.RewardPeriods) types.ClaimPeriods {
 | 
				
			|||||||
		end := rewardPeriod.ClaimEnd
 | 
							end := rewardPeriod.ClaimEnd
 | 
				
			||||||
		claimTimeLock := rewardPeriod.ClaimTimeLock
 | 
							claimTimeLock := rewardPeriod.ClaimTimeLock
 | 
				
			||||||
		// Create the new claim period for this reward period
 | 
							// Create the new claim period for this reward period
 | 
				
			||||||
		claimPeriod := types.NewClaimPeriod(denom, numbRewardPeriods, end, claimTimeLock)
 | 
							claimPeriods[i] = types.NewClaimPeriod(denom, numbRewardPeriods, end, claimTimeLock)
 | 
				
			||||||
		claimPeriods = append(claimPeriods, claimPeriod)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return claimPeriods
 | 
						return claimPeriods
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -112,16 +108,14 @@ func genClaimPeriods(rewardPeriods types.RewardPeriods) types.ClaimPeriods {
 | 
				
			|||||||
func genNextClaimPeriodIds(cps types.ClaimPeriods) types.GenesisClaimPeriodIDs {
 | 
					func genNextClaimPeriodIds(cps types.ClaimPeriods) types.GenesisClaimPeriodIDs {
 | 
				
			||||||
	// Build a map of the most recent claim periods by denom
 | 
						// Build a map of the most recent claim periods by denom
 | 
				
			||||||
	mostRecentClaimPeriodByDenom := make(map[string]uint64)
 | 
						mostRecentClaimPeriodByDenom := make(map[string]uint64)
 | 
				
			||||||
	for _, cp := range cps {
 | 
					 | 
				
			||||||
		if cp.ID > mostRecentClaimPeriodByDenom[cp.Denom] {
 | 
					 | 
				
			||||||
			mostRecentClaimPeriodByDenom[cp.Denom] = cp.ID
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	// Write map contents to an array of GenesisClaimPeriodIDs
 | 
					 | 
				
			||||||
	var claimPeriodIDs types.GenesisClaimPeriodIDs
 | 
						var claimPeriodIDs types.GenesisClaimPeriodIDs
 | 
				
			||||||
	for key, value := range mostRecentClaimPeriodByDenom {
 | 
						for _, cp := range cps {
 | 
				
			||||||
		claimPeriodID := types.GenesisClaimPeriodID{Denom: key, ID: value}
 | 
							if cp.ID <= mostRecentClaimPeriodByDenom[cp.Denom] {
 | 
				
			||||||
		claimPeriodIDs = append(claimPeriodIDs, claimPeriodID)
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							claimPeriodIDs = append(claimPeriodIDs, types.GenesisClaimPeriodID{Denom: cp.Denom, ID: cp.ID})
 | 
				
			||||||
 | 
							mostRecentClaimPeriodByDenom[cp.Denom] = cp.ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return claimPeriodIDs
 | 
						return claimPeriodIDs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -2,8 +2,11 @@ package types
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sdk "github.com/cosmos/cosmos-sdk/types"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GenesisClaimPeriodID stores the next claim id and its corresponding denom
 | 
					// GenesisClaimPeriodID stores the next claim id and its corresponding denom
 | 
				
			||||||
@ -12,9 +15,37 @@ type GenesisClaimPeriodID struct {
 | 
				
			|||||||
	ID    uint64 `json:"id" yaml:"id"`
 | 
						ID    uint64 `json:"id" yaml:"id"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Validate performs a basic check of a GenesisClaimPeriodID fields.
 | 
				
			||||||
 | 
					func (gcp GenesisClaimPeriodID) Validate() error {
 | 
				
			||||||
 | 
						if gcp.ID == 0 {
 | 
				
			||||||
 | 
							return errors.New("genesis claim period id cannot be 0")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return sdk.ValidateDenom(gcp.Denom)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GenesisClaimPeriodIDs array of GenesisClaimPeriodID
 | 
					// GenesisClaimPeriodIDs array of GenesisClaimPeriodID
 | 
				
			||||||
type GenesisClaimPeriodIDs []GenesisClaimPeriodID
 | 
					type GenesisClaimPeriodIDs []GenesisClaimPeriodID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Validate checks if all the GenesisClaimPeriodIDs are valid and there are no duplicated
 | 
				
			||||||
 | 
					// entries.
 | 
				
			||||||
 | 
					func (gcps GenesisClaimPeriodIDs) Validate() error {
 | 
				
			||||||
 | 
						seenIDS := make(map[string]bool)
 | 
				
			||||||
 | 
						var key string
 | 
				
			||||||
 | 
						for _, gcp := range gcps {
 | 
				
			||||||
 | 
							key = gcp.Denom + string(gcp.ID)
 | 
				
			||||||
 | 
							if seenIDS[key] {
 | 
				
			||||||
 | 
								return fmt.Errorf("duplicated genesis claim period with id %d and denom %s", gcp.ID, gcp.Denom)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err := gcp.Validate(); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							seenIDS[key] = true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GenesisState is the state that must be provided at genesis.
 | 
					// GenesisState is the state that must be provided at genesis.
 | 
				
			||||||
type GenesisState struct {
 | 
					type GenesisState struct {
 | 
				
			||||||
	Params             Params                `json:"params" yaml:"params"`
 | 
						Params             Params                `json:"params" yaml:"params"`
 | 
				
			||||||
@ -52,14 +83,22 @@ func DefaultGenesisState() GenesisState {
 | 
				
			|||||||
// Validate performs basic validation of genesis data returning an
 | 
					// Validate performs basic validation of genesis data returning an
 | 
				
			||||||
// error for any failed validation criteria.
 | 
					// error for any failed validation criteria.
 | 
				
			||||||
func (gs GenesisState) Validate() error {
 | 
					func (gs GenesisState) Validate() error {
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err := gs.Params.Validate(); err != nil {
 | 
						if err := gs.Params.Validate(); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if gs.PreviousBlockTime.IsZero() {
 | 
						if gs.PreviousBlockTime.IsZero() {
 | 
				
			||||||
		return fmt.Errorf("previous block time not set or zero")
 | 
							return errors.New("previous block time cannot be 0")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						if err := gs.RewardPeriods.Validate(); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := gs.ClaimPeriods.Validate(); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := gs.Claims.Validate(); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return gs.NextClaimPeriodIDs.Validate()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Equal checks whether two gov GenesisState structs are equivalent
 | 
					// Equal checks whether two gov GenesisState structs are equivalent
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										163
									
								
								x/incentive/types/genesis_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								x/incentive/types/genesis_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,163 @@
 | 
				
			|||||||
 | 
					package types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/stretchr/testify/require"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tmtypes "github.com/tendermint/tendermint/types"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sdk "github.com/cosmos/cosmos-sdk/types"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestGenesisClaimPeriodIDsValidate(t *testing.T) {
 | 
				
			||||||
 | 
						testCases := []struct {
 | 
				
			||||||
 | 
							msg                   string
 | 
				
			||||||
 | 
							genesisClaimPeriodIDs GenesisClaimPeriodIDs
 | 
				
			||||||
 | 
							expPass               bool
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"valid",
 | 
				
			||||||
 | 
								GenesisClaimPeriodIDs{
 | 
				
			||||||
 | 
									{Denom: "bnb", ID: 1},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"invalid denom",
 | 
				
			||||||
 | 
								GenesisClaimPeriodIDs{
 | 
				
			||||||
 | 
									{Denom: "", ID: 1},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"invalid ID",
 | 
				
			||||||
 | 
								GenesisClaimPeriodIDs{
 | 
				
			||||||
 | 
									{Denom: "bnb", ID: 0},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"duplicate",
 | 
				
			||||||
 | 
								GenesisClaimPeriodIDs{
 | 
				
			||||||
 | 
									{Denom: "bnb", ID: 1},
 | 
				
			||||||
 | 
									{Denom: "bnb", ID: 1},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, tc := range testCases {
 | 
				
			||||||
 | 
							err := tc.genesisClaimPeriodIDs.Validate()
 | 
				
			||||||
 | 
							if tc.expPass {
 | 
				
			||||||
 | 
								require.NoError(t, err, tc.msg)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								require.Error(t, err, tc.msg)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestGenesisStateValidate(t *testing.T) {
 | 
				
			||||||
 | 
						now := time.Now()
 | 
				
			||||||
 | 
						owner := sdk.AccAddress(tmtypes.NewMockPV().GetPubKey().Address())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rewards := Rewards{
 | 
				
			||||||
 | 
							NewReward(
 | 
				
			||||||
 | 
								true, "bnb", sdk.NewCoin("ukava", sdk.NewInt(10000000000)),
 | 
				
			||||||
 | 
								time.Hour*24*7, time.Hour*8766, time.Hour*24*14,
 | 
				
			||||||
 | 
							),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						rewardPeriods := RewardPeriods{NewRewardPeriod("bnb", now, now.Add(time.Hour), sdk.NewCoin("bnb", sdk.OneInt()), now, 10)}
 | 
				
			||||||
 | 
						claimPeriods := ClaimPeriods{NewClaimPeriod("bnb", 10, now, 100)}
 | 
				
			||||||
 | 
						claims := Claims{NewClaim(owner, sdk.NewCoin("bnb", sdk.OneInt()), "bnb", 10)}
 | 
				
			||||||
 | 
						gcps := GenesisClaimPeriodIDs{{Denom: "bnb", ID: 1}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						testCases := []struct {
 | 
				
			||||||
 | 
							msg          string
 | 
				
			||||||
 | 
							genesisState GenesisState
 | 
				
			||||||
 | 
							expPass      bool
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								msg:          "default",
 | 
				
			||||||
 | 
								genesisState: DefaultGenesisState(),
 | 
				
			||||||
 | 
								expPass:      true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								msg: "valid genesis",
 | 
				
			||||||
 | 
								genesisState: NewGenesisState(
 | 
				
			||||||
 | 
									NewParams(true, rewards),
 | 
				
			||||||
 | 
									now, rewardPeriods, claimPeriods, claims, gcps,
 | 
				
			||||||
 | 
								),
 | 
				
			||||||
 | 
								expPass: true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								msg: "invalid Params",
 | 
				
			||||||
 | 
								genesisState: GenesisState{
 | 
				
			||||||
 | 
									Params: Params{
 | 
				
			||||||
 | 
										Active: true,
 | 
				
			||||||
 | 
										Rewards: Rewards{
 | 
				
			||||||
 | 
											Reward{},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expPass: false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								msg: "zero PreviousBlockTime",
 | 
				
			||||||
 | 
								genesisState: GenesisState{
 | 
				
			||||||
 | 
									PreviousBlockTime: time.Time{},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expPass: false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								msg: "invalid RewardsPeriod",
 | 
				
			||||||
 | 
								genesisState: GenesisState{
 | 
				
			||||||
 | 
									PreviousBlockTime: now,
 | 
				
			||||||
 | 
									RewardPeriods: RewardPeriods{
 | 
				
			||||||
 | 
										{Start: time.Time{}},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expPass: false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								msg: "invalid ClaimPeriods",
 | 
				
			||||||
 | 
								genesisState: GenesisState{
 | 
				
			||||||
 | 
									PreviousBlockTime: now,
 | 
				
			||||||
 | 
									ClaimPeriods: ClaimPeriods{
 | 
				
			||||||
 | 
										{ID: 0},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expPass: false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								msg: "invalid Claims",
 | 
				
			||||||
 | 
								genesisState: GenesisState{
 | 
				
			||||||
 | 
									PreviousBlockTime: now,
 | 
				
			||||||
 | 
									Claims: Claims{
 | 
				
			||||||
 | 
										{ClaimPeriodID: 0},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expPass: false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								msg: "invalid NextClaimPeriodIds",
 | 
				
			||||||
 | 
								genesisState: GenesisState{
 | 
				
			||||||
 | 
									PreviousBlockTime: now,
 | 
				
			||||||
 | 
									NextClaimPeriodIDs: GenesisClaimPeriodIDs{
 | 
				
			||||||
 | 
										{ID: 0},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expPass: false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, tc := range testCases {
 | 
				
			||||||
 | 
							err := tc.genesisState.Validate()
 | 
				
			||||||
 | 
							if tc.expPass {
 | 
				
			||||||
 | 
								require.NoError(t, err, tc.msg)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								require.Error(t, err, tc.msg)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -2,7 +2,6 @@ package types
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
						sdk "github.com/cosmos/cosmos-sdk/types"
 | 
				
			||||||
@ -71,11 +70,7 @@ func (p Params) Validate() error {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := validateRewardsParam(p.Rewards); err != nil {
 | 
						return validateRewardsParam(p.Rewards)
 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func validateActiveParam(i interface{}) error {
 | 
					func validateActiveParam(i interface{}) error {
 | 
				
			||||||
@ -91,33 +86,8 @@ func validateRewardsParam(i interface{}) error {
 | 
				
			|||||||
	if !ok {
 | 
						if !ok {
 | 
				
			||||||
		return fmt.Errorf("invalid parameter type: %T", i)
 | 
							return fmt.Errorf("invalid parameter type: %T", i)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	rewardDenoms := make(map[string]bool)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, reward := range rewards {
 | 
						return rewards.Validate()
 | 
				
			||||||
		if strings.TrimSpace(reward.Denom) == "" {
 | 
					 | 
				
			||||||
			return fmt.Errorf("cannot have empty reward denom: %s", reward)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if rewardDenoms[reward.Denom] {
 | 
					 | 
				
			||||||
			return fmt.Errorf("cannot have duplicate reward denoms: %s", reward.Denom)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		rewardDenoms[reward.Denom] = true
 | 
					 | 
				
			||||||
		if !reward.AvailableRewards.IsValid() {
 | 
					 | 
				
			||||||
			return fmt.Errorf("invalid reward coins %s for %s", reward.AvailableRewards, reward.Denom)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if !reward.AvailableRewards.IsPositive() {
 | 
					 | 
				
			||||||
			return fmt.Errorf("reward amount must be positive, is %s for %s", reward.AvailableRewards, reward.Denom)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if int(reward.Duration.Seconds()) <= 0 {
 | 
					 | 
				
			||||||
			return fmt.Errorf("reward duration must be positive, is %s for %s", reward.Duration.String(), reward.Denom)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if int(reward.TimeLock.Seconds()) < 0 {
 | 
					 | 
				
			||||||
			return fmt.Errorf("reward timelock must be non-negative, is %s for %s", reward.TimeLock.String(), reward.Denom)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if int(reward.ClaimDuration.Seconds()) <= 0 {
 | 
					 | 
				
			||||||
			return fmt.Errorf("claim duration must be positive, is %s for %s", reward.ClaimDuration.String(), reward.Denom)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Reward stores the specified state for a single reward period.
 | 
					// Reward stores the specified state for a single reward period.
 | 
				
			||||||
@ -154,9 +124,47 @@ func (r Reward) String() string {
 | 
				
			|||||||
		r.Active, r.Denom, r.AvailableRewards, r.Duration, r.TimeLock, r.ClaimDuration)
 | 
							r.Active, r.Denom, r.AvailableRewards, r.Duration, r.TimeLock, r.ClaimDuration)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Validate performs a basic check of a reward fields.
 | 
				
			||||||
 | 
					func (r Reward) Validate() error {
 | 
				
			||||||
 | 
						if !r.AvailableRewards.IsValid() {
 | 
				
			||||||
 | 
							return fmt.Errorf("invalid reward coins %s for %s", r.AvailableRewards, r.Denom)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !r.AvailableRewards.IsPositive() {
 | 
				
			||||||
 | 
							return fmt.Errorf("reward amount must be positive, is %s for %s", r.AvailableRewards, r.Denom)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if r.Duration <= 0 {
 | 
				
			||||||
 | 
							return fmt.Errorf("reward duration must be positive, is %s for %s", r.Duration, r.Denom)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if r.TimeLock < 0 {
 | 
				
			||||||
 | 
							return fmt.Errorf("reward timelock must be non-negative, is %s for %s", r.TimeLock, r.Denom)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if r.ClaimDuration <= 0 {
 | 
				
			||||||
 | 
							return fmt.Errorf("claim duration must be positive, is %s for %s", r.ClaimDuration, r.Denom)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return sdk.ValidateDenom(r.Denom)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Rewards array of Reward
 | 
					// Rewards array of Reward
 | 
				
			||||||
type Rewards []Reward
 | 
					type Rewards []Reward
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Validate checks if all the rewards are valid and there are no duplicated
 | 
				
			||||||
 | 
					// entries.
 | 
				
			||||||
 | 
					func (rs Rewards) Validate() error {
 | 
				
			||||||
 | 
						rewardDenoms := make(map[string]bool)
 | 
				
			||||||
 | 
						for _, r := range rs {
 | 
				
			||||||
 | 
							if rewardDenoms[r.Denom] {
 | 
				
			||||||
 | 
								return fmt.Errorf("cannot have duplicate reward denoms: %s", r.Denom)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err := r.Validate(); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rewardDenoms[r.Denom] = true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// String implements fmt.Stringer
 | 
					// String implements fmt.Stringer
 | 
				
			||||||
func (rs Rewards) String() string {
 | 
					func (rs Rewards) String() string {
 | 
				
			||||||
	out := "Rewards\n"
 | 
						out := "Rewards\n"
 | 
				
			||||||
 | 
				
			|||||||
@ -187,7 +187,7 @@ func (suite *ParamTestSuite) SetupTest() {
 | 
				
			|||||||
					types.Reward{
 | 
										types.Reward{
 | 
				
			||||||
						Active:           true,
 | 
											Active:           true,
 | 
				
			||||||
						Denom:            "",
 | 
											Denom:            "",
 | 
				
			||||||
						AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(0)),
 | 
											AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(1)),
 | 
				
			||||||
						Duration:         time.Hour * 24 * 7,
 | 
											Duration:         time.Hour * 24 * 7,
 | 
				
			||||||
						TimeLock:         time.Hour * 8766,
 | 
											TimeLock:         time.Hour * 8766,
 | 
				
			||||||
						ClaimDuration:    time.Hour * 24 * 14,
 | 
											ClaimDuration:    time.Hour * 24 * 14,
 | 
				
			||||||
@ -196,7 +196,7 @@ func (suite *ParamTestSuite) SetupTest() {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
			errResult: errResult{
 | 
								errResult: errResult{
 | 
				
			||||||
				expectPass: false,
 | 
									expectPass: false,
 | 
				
			||||||
				contains:   "cannot have empty reward denom",
 | 
									contains:   "invalid denom",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
package types
 | 
					package types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -41,9 +42,50 @@ func NewRewardPeriod(denom string, start time.Time, end time.Time, reward sdk.Co
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Validate performs a basic check of a RewardPeriod fields.
 | 
				
			||||||
 | 
					func (rp RewardPeriod) Validate() error {
 | 
				
			||||||
 | 
						if rp.Start.IsZero() {
 | 
				
			||||||
 | 
							return errors.New("reward period start time cannot be 0")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if rp.End.IsZero() {
 | 
				
			||||||
 | 
							return errors.New("reward period end time cannot be 0")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if rp.Start.After(rp.End) {
 | 
				
			||||||
 | 
							return fmt.Errorf("end period time %s cannot be before start time %s", rp.End, rp.Start)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !rp.Reward.IsValid() {
 | 
				
			||||||
 | 
							return fmt.Errorf("invalid reward amount: %s", rp.Reward)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if rp.ClaimEnd.IsZero() {
 | 
				
			||||||
 | 
							return errors.New("reward period claim end time cannot be 0")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if rp.ClaimTimeLock == 0 {
 | 
				
			||||||
 | 
							return errors.New("reward claim time lock cannot be 0")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return sdk.ValidateDenom(rp.Denom)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RewardPeriods array of RewardPeriod
 | 
					// RewardPeriods array of RewardPeriod
 | 
				
			||||||
type RewardPeriods []RewardPeriod
 | 
					type RewardPeriods []RewardPeriod
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Validate checks if all the RewardPeriods are valid and there are no duplicated
 | 
				
			||||||
 | 
					// entries.
 | 
				
			||||||
 | 
					func (rps RewardPeriods) Validate() error {
 | 
				
			||||||
 | 
						seenPeriods := make(map[string]bool)
 | 
				
			||||||
 | 
						for _, rp := range rps {
 | 
				
			||||||
 | 
							if seenPeriods[rp.Denom] {
 | 
				
			||||||
 | 
								return fmt.Errorf("duplicated reward period with denom %s", rp.Denom)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err := rp.Validate(); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							seenPeriods[rp.Denom] = true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ClaimPeriod stores the state of an ongoing claim period
 | 
					// ClaimPeriod stores the state of an ongoing claim period
 | 
				
			||||||
type ClaimPeriod struct {
 | 
					type ClaimPeriod struct {
 | 
				
			||||||
	Denom    string        `json:"denom" yaml:"denom"`
 | 
						Denom    string        `json:"denom" yaml:"denom"`
 | 
				
			||||||
@ -52,16 +94,6 @@ type ClaimPeriod struct {
 | 
				
			|||||||
	TimeLock time.Duration `json:"time_lock" yaml:"time_lock"`
 | 
						TimeLock time.Duration `json:"time_lock" yaml:"time_lock"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// String implements fmt.Stringer
 | 
					 | 
				
			||||||
func (cp ClaimPeriod) String() string {
 | 
					 | 
				
			||||||
	return fmt.Sprintf(`Claim Period:
 | 
					 | 
				
			||||||
	Denom: %s,
 | 
					 | 
				
			||||||
	ID: %d,
 | 
					 | 
				
			||||||
	End: %s,
 | 
					 | 
				
			||||||
	Claim Time Lock: %s
 | 
					 | 
				
			||||||
	`, cp.Denom, cp.ID, cp.End, cp.TimeLock)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// NewClaimPeriod returns a new ClaimPeriod
 | 
					// NewClaimPeriod returns a new ClaimPeriod
 | 
				
			||||||
func NewClaimPeriod(denom string, id uint64, end time.Time, timeLock time.Duration) ClaimPeriod {
 | 
					func NewClaimPeriod(denom string, id uint64, end time.Time, timeLock time.Duration) ClaimPeriod {
 | 
				
			||||||
	return ClaimPeriod{
 | 
						return ClaimPeriod{
 | 
				
			||||||
@ -72,9 +104,53 @@ func NewClaimPeriod(denom string, id uint64, end time.Time, timeLock time.Durati
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Validate performs a basic check of a ClaimPeriod fields.
 | 
				
			||||||
 | 
					func (cp ClaimPeriod) Validate() error {
 | 
				
			||||||
 | 
						if cp.ID == 0 {
 | 
				
			||||||
 | 
							return errors.New("claim period id cannot be 0")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if cp.End.IsZero() {
 | 
				
			||||||
 | 
							return errors.New("claim period end time cannot be 0")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if cp.TimeLock == 0 {
 | 
				
			||||||
 | 
							return errors.New("claim period time lock cannot be 0")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return sdk.ValidateDenom(cp.Denom)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// String implements fmt.Stringer
 | 
				
			||||||
 | 
					func (cp ClaimPeriod) String() string {
 | 
				
			||||||
 | 
						return fmt.Sprintf(`Claim Period:
 | 
				
			||||||
 | 
						Denom: %s,
 | 
				
			||||||
 | 
						ID: %d,
 | 
				
			||||||
 | 
						End: %s,
 | 
				
			||||||
 | 
						Claim Time Lock: %s
 | 
				
			||||||
 | 
						`, cp.Denom, cp.ID, cp.End, cp.TimeLock)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ClaimPeriods array of ClaimPeriod
 | 
					// ClaimPeriods array of ClaimPeriod
 | 
				
			||||||
type ClaimPeriods []ClaimPeriod
 | 
					type ClaimPeriods []ClaimPeriod
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Validate checks if all the ClaimPeriods are valid and there are no duplicated
 | 
				
			||||||
 | 
					// entries.
 | 
				
			||||||
 | 
					func (cps ClaimPeriods) Validate() error {
 | 
				
			||||||
 | 
						seenPeriods := make(map[string]bool)
 | 
				
			||||||
 | 
						var key string
 | 
				
			||||||
 | 
						for _, cp := range cps {
 | 
				
			||||||
 | 
							key = cp.Denom + string(cp.ID)
 | 
				
			||||||
 | 
							if seenPeriods[key] {
 | 
				
			||||||
 | 
								return fmt.Errorf("duplicated claim period with id %d and denom %s", cp.ID, cp.Denom)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err := cp.Validate(); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							seenPeriods[key] = true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Claim stores the rewards that can be claimed by owner
 | 
					// Claim stores the rewards that can be claimed by owner
 | 
				
			||||||
type Claim struct {
 | 
					type Claim struct {
 | 
				
			||||||
	Owner         sdk.AccAddress `json:"owner" yaml:"owner"`
 | 
						Owner         sdk.AccAddress `json:"owner" yaml:"owner"`
 | 
				
			||||||
@ -93,6 +169,20 @@ func NewClaim(owner sdk.AccAddress, reward sdk.Coin, denom string, claimPeriodID
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Validate performs a basic check of a Claim fields.
 | 
				
			||||||
 | 
					func (c Claim) Validate() error {
 | 
				
			||||||
 | 
						if c.Owner.Empty() {
 | 
				
			||||||
 | 
							return errors.New("claim owner cannot be empty")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !c.Reward.IsValid() {
 | 
				
			||||||
 | 
							return fmt.Errorf("invalid reward amount: %s", c.Reward)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if c.ClaimPeriodID == 0 {
 | 
				
			||||||
 | 
							return errors.New("claim period id cannot be 0")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return sdk.ValidateDenom(c.Denom)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// String implements fmt.Stringer
 | 
					// String implements fmt.Stringer
 | 
				
			||||||
func (c Claim) String() string {
 | 
					func (c Claim) String() string {
 | 
				
			||||||
	return fmt.Sprintf(`Claim:
 | 
						return fmt.Sprintf(`Claim:
 | 
				
			||||||
@ -106,6 +196,26 @@ func (c Claim) String() string {
 | 
				
			|||||||
// Claims array of Claim
 | 
					// Claims array of Claim
 | 
				
			||||||
type Claims []Claim
 | 
					type Claims []Claim
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Validate checks if all the claims are valid and there are no duplicated
 | 
				
			||||||
 | 
					// entries.
 | 
				
			||||||
 | 
					func (cs Claims) Validate() error {
 | 
				
			||||||
 | 
						seemClaims := make(map[string]bool)
 | 
				
			||||||
 | 
						var key string
 | 
				
			||||||
 | 
						for _, c := range cs {
 | 
				
			||||||
 | 
							key = c.Denom + string(c.ClaimPeriodID) + c.Owner.String()
 | 
				
			||||||
 | 
							if c.Owner != nil && seemClaims[key] {
 | 
				
			||||||
 | 
								return fmt.Errorf("duplicated claim from owner %s and denom %s", c.Owner, c.Denom)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err := c.Validate(); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							seemClaims[key] = true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewRewardPeriodFromReward returns a new reward period from the input reward and block time
 | 
					// NewRewardPeriodFromReward returns a new reward period from the input reward and block time
 | 
				
			||||||
func NewRewardPeriodFromReward(reward Reward, blockTime time.Time) RewardPeriod {
 | 
					func NewRewardPeriodFromReward(reward Reward, blockTime time.Time) RewardPeriod {
 | 
				
			||||||
	// note: reward periods store the amount of rewards paid PER SECOND
 | 
						// note: reward periods store the amount of rewards paid PER SECOND
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										272
									
								
								x/incentive/types/rewards_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										272
									
								
								x/incentive/types/rewards_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,272 @@
 | 
				
			|||||||
 | 
					package types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/stretchr/testify/require"
 | 
				
			||||||
 | 
						tmtypes "github.com/tendermint/tendermint/types"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sdk "github.com/cosmos/cosmos-sdk/types"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestRewardPeriodsValidate(t *testing.T) {
 | 
				
			||||||
 | 
						now := time.Now()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						testCases := []struct {
 | 
				
			||||||
 | 
							msg           string
 | 
				
			||||||
 | 
							rewardPeriods RewardPeriods
 | 
				
			||||||
 | 
							expPass       bool
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"valid",
 | 
				
			||||||
 | 
								RewardPeriods{
 | 
				
			||||||
 | 
									NewRewardPeriod("bnb", now, now.Add(time.Hour), sdk.NewCoin("bnb", sdk.OneInt()), now, 10),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"zero start time",
 | 
				
			||||||
 | 
								RewardPeriods{
 | 
				
			||||||
 | 
									{Start: time.Time{}},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"zero end time",
 | 
				
			||||||
 | 
								RewardPeriods{
 | 
				
			||||||
 | 
									{Start: now, End: time.Time{}},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"zero end time",
 | 
				
			||||||
 | 
								RewardPeriods{
 | 
				
			||||||
 | 
									{Start: now, End: time.Time{}},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"start time > end time",
 | 
				
			||||||
 | 
								RewardPeriods{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Start: now.Add(time.Hour),
 | 
				
			||||||
 | 
										End:   now,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"invalid reward",
 | 
				
			||||||
 | 
								RewardPeriods{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Start:  now,
 | 
				
			||||||
 | 
										End:    now.Add(time.Hour),
 | 
				
			||||||
 | 
										Reward: sdk.Coin{Denom: "", Amount: sdk.ZeroInt()},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"zero claim end time",
 | 
				
			||||||
 | 
								RewardPeriods{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Start:    now,
 | 
				
			||||||
 | 
										End:      now.Add(time.Hour),
 | 
				
			||||||
 | 
										Reward:   sdk.NewCoin("bnb", sdk.OneInt()),
 | 
				
			||||||
 | 
										ClaimEnd: time.Time{},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"zero claim time lock",
 | 
				
			||||||
 | 
								RewardPeriods{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Start:         now,
 | 
				
			||||||
 | 
										End:           now.Add(time.Hour),
 | 
				
			||||||
 | 
										Reward:        sdk.NewCoin("bnb", sdk.OneInt()),
 | 
				
			||||||
 | 
										ClaimEnd:      now,
 | 
				
			||||||
 | 
										ClaimTimeLock: 0,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"invalid denom",
 | 
				
			||||||
 | 
								RewardPeriods{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Start:         now,
 | 
				
			||||||
 | 
										End:           now.Add(time.Hour),
 | 
				
			||||||
 | 
										Reward:        sdk.NewCoin("bnb", sdk.OneInt()),
 | 
				
			||||||
 | 
										ClaimEnd:      now,
 | 
				
			||||||
 | 
										ClaimTimeLock: 10,
 | 
				
			||||||
 | 
										Denom:         "",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"duplicate reward period",
 | 
				
			||||||
 | 
								RewardPeriods{
 | 
				
			||||||
 | 
									NewRewardPeriod("bnb", now, now.Add(time.Hour), sdk.NewCoin("bnb", sdk.OneInt()), now, 10),
 | 
				
			||||||
 | 
									NewRewardPeriod("bnb", now, now.Add(time.Hour), sdk.NewCoin("bnb", sdk.OneInt()), now, 10),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, tc := range testCases {
 | 
				
			||||||
 | 
							err := tc.rewardPeriods.Validate()
 | 
				
			||||||
 | 
							if tc.expPass {
 | 
				
			||||||
 | 
								require.NoError(t, err, tc.msg)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								require.Error(t, err, tc.msg)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestClaimPeriodsValidate(t *testing.T) {
 | 
				
			||||||
 | 
						now := time.Now()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						testCases := []struct {
 | 
				
			||||||
 | 
							msg          string
 | 
				
			||||||
 | 
							claimPeriods ClaimPeriods
 | 
				
			||||||
 | 
							expPass      bool
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"valid",
 | 
				
			||||||
 | 
								ClaimPeriods{
 | 
				
			||||||
 | 
									NewClaimPeriod("bnb", 10, now, 100),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"invalid ID",
 | 
				
			||||||
 | 
								ClaimPeriods{
 | 
				
			||||||
 | 
									{ID: 0},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"zero end time",
 | 
				
			||||||
 | 
								ClaimPeriods{
 | 
				
			||||||
 | 
									{ID: 10, End: time.Time{}},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"zero time lock",
 | 
				
			||||||
 | 
								ClaimPeriods{
 | 
				
			||||||
 | 
									{ID: 10, End: now, TimeLock: 0},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"start time > end time",
 | 
				
			||||||
 | 
								ClaimPeriods{
 | 
				
			||||||
 | 
									{ID: 10, End: now, TimeLock: 0},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"invalid denom",
 | 
				
			||||||
 | 
								ClaimPeriods{
 | 
				
			||||||
 | 
									{ID: 10, End: now, TimeLock: 100, Denom: ""},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"duplicate reward period",
 | 
				
			||||||
 | 
								ClaimPeriods{
 | 
				
			||||||
 | 
									NewClaimPeriod("bnb", 10, now, 100),
 | 
				
			||||||
 | 
									NewClaimPeriod("bnb", 10, now, 100),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, tc := range testCases {
 | 
				
			||||||
 | 
							err := tc.claimPeriods.Validate()
 | 
				
			||||||
 | 
							if tc.expPass {
 | 
				
			||||||
 | 
								require.NoError(t, err, tc.msg)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								require.Error(t, err, tc.msg)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestClaimsValidate(t *testing.T) {
 | 
				
			||||||
 | 
						owner := sdk.AccAddress(tmtypes.NewMockPV().GetPubKey().Address())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						testCases := []struct {
 | 
				
			||||||
 | 
							msg     string
 | 
				
			||||||
 | 
							claims  Claims
 | 
				
			||||||
 | 
							expPass bool
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"valid",
 | 
				
			||||||
 | 
								Claims{
 | 
				
			||||||
 | 
									NewClaim(owner, sdk.NewCoin("bnb", sdk.OneInt()), "bnb", 10),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"invalid owner",
 | 
				
			||||||
 | 
								Claims{
 | 
				
			||||||
 | 
									{Owner: nil},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"invalid reward",
 | 
				
			||||||
 | 
								Claims{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Owner:  owner,
 | 
				
			||||||
 | 
										Reward: sdk.Coin{Denom: "", Amount: sdk.ZeroInt()},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"zero claim period id",
 | 
				
			||||||
 | 
								Claims{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Owner:         owner,
 | 
				
			||||||
 | 
										Reward:        sdk.NewCoin("bnb", sdk.OneInt()),
 | 
				
			||||||
 | 
										ClaimPeriodID: 0,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"invalid denom",
 | 
				
			||||||
 | 
								Claims{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Owner:         owner,
 | 
				
			||||||
 | 
										Reward:        sdk.NewCoin("bnb", sdk.OneInt()),
 | 
				
			||||||
 | 
										ClaimPeriodID: 10,
 | 
				
			||||||
 | 
										Denom:         "",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"duplicate reward period",
 | 
				
			||||||
 | 
								Claims{
 | 
				
			||||||
 | 
									NewClaim(owner, sdk.NewCoin("bnb", sdk.OneInt()), "bnb", 10),
 | 
				
			||||||
 | 
									NewClaim(owner, sdk.NewCoin("bnb", sdk.OneInt()), "bnb", 10),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, tc := range testCases {
 | 
				
			||||||
 | 
							err := tc.claims.Validate()
 | 
				
			||||||
 | 
							if tc.expPass {
 | 
				
			||||||
 | 
								require.NoError(t, err, tc.msg)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								require.Error(t, err, tc.msg)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user