2018-05-12 15:22:59 -07:00
|
|
|
package stake
|
|
|
|
|
2018-06-06 09:38:13 -07:00
|
|
|
import (
|
2018-10-07 21:12:37 -07:00
|
|
|
"fmt"
|
2018-11-08 16:28:28 -08:00
|
|
|
"sort"
|
2018-10-07 21:12:37 -07:00
|
|
|
|
2018-07-18 23:39:40 -07:00
|
|
|
abci "github.com/tendermint/tendermint/abci/types"
|
|
|
|
tmtypes "github.com/tendermint/tendermint/types"
|
|
|
|
|
2018-06-06 09:38:13 -07:00
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
2018-06-26 19:00:12 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
2018-06-06 09:38:13 -07:00
|
|
|
)
|
2018-05-12 15:22:59 -07:00
|
|
|
|
2018-07-03 21:21:36 -07:00
|
|
|
// InitGenesis sets the pool and parameters for the provided keeper and
|
|
|
|
// initializes the IntraTxCounter. For each validator in data, it sets that
|
|
|
|
// validator in the keeper along with manually setting the indexes. In
|
|
|
|
// addition, it also sets any delegations found in data. Finally, it updates
|
|
|
|
// the bonded validators.
|
2018-07-18 23:39:40 -07:00
|
|
|
// Returns final validator set after applying all declaration and delegations
|
2018-10-03 08:48:23 -07:00
|
|
|
func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res []abci.ValidatorUpdate, err error) {
|
2018-10-05 05:11:36 -07:00
|
|
|
|
2018-10-05 10:56:17 -07:00
|
|
|
// We need to pretend to be "n blocks before genesis", where "n" is the validator update delay,
|
|
|
|
// so that e.g. slashing periods are correctly initialized for the validator set
|
|
|
|
// e.g. with a one-block offset - the first TM block is at height 0, so state updates applied from genesis.json are in block -1.
|
|
|
|
ctx = ctx.WithBlockHeight(-types.ValidatorUpdateDelay)
|
2018-10-05 05:11:36 -07:00
|
|
|
|
2018-06-26 19:00:12 -07:00
|
|
|
keeper.SetPool(ctx, data.Pool)
|
2018-10-03 09:37:06 -07:00
|
|
|
keeper.SetParams(ctx, data.Params)
|
2018-11-08 16:28:28 -08:00
|
|
|
keeper.SetIntraTxCounter(ctx, data.IntraTxCounter)
|
|
|
|
keeper.SetLastTotalPower(ctx, data.LastTotalPower)
|
|
|
|
|
|
|
|
// We only need to set this if we're starting from a list of validators, not a state export
|
|
|
|
setBondIntraTxCounter := true
|
|
|
|
for _, validator := range data.Validators {
|
|
|
|
if validator.BondIntraTxCounter != 0 {
|
|
|
|
setBondIntraTxCounter = false
|
|
|
|
}
|
|
|
|
}
|
2018-05-30 18:28:02 -07:00
|
|
|
|
2018-07-18 13:09:40 -07:00
|
|
|
for i, validator := range data.Validators {
|
2018-11-08 16:28:28 -08:00
|
|
|
// set the intra-tx counter to the order the validators are presented, if necessary
|
|
|
|
if setBondIntraTxCounter {
|
|
|
|
validator.BondIntraTxCounter = int16(i)
|
2018-07-09 19:51:13 -07:00
|
|
|
}
|
2018-11-08 16:28:28 -08:00
|
|
|
keeper.SetValidator(ctx, validator)
|
2018-07-09 19:51:13 -07:00
|
|
|
|
2018-10-03 09:37:06 -07:00
|
|
|
// Manually set indices for the first time
|
2018-09-19 16:33:12 -07:00
|
|
|
keeper.SetValidatorByConsAddr(ctx, validator)
|
2018-06-26 19:00:12 -07:00
|
|
|
keeper.SetValidatorByPowerIndex(ctx, validator, data.Pool)
|
2018-09-28 00:29:52 -07:00
|
|
|
keeper.OnValidatorCreated(ctx, validator.OperatorAddr)
|
2018-11-08 16:28:28 -08:00
|
|
|
|
|
|
|
// Set timeslice if necessary
|
|
|
|
if validator.Status == sdk.Unbonding {
|
|
|
|
keeper.InsertValidatorQueue(ctx, validator)
|
|
|
|
}
|
2018-05-12 15:22:59 -07:00
|
|
|
}
|
2018-07-03 21:21:36 -07:00
|
|
|
|
2018-09-28 00:29:52 -07:00
|
|
|
for _, delegation := range data.Bonds {
|
|
|
|
keeper.SetDelegation(ctx, delegation)
|
|
|
|
keeper.OnDelegationCreated(ctx, delegation.DelegatorAddr, delegation.ValidatorAddr)
|
2018-05-12 15:22:59 -07:00
|
|
|
}
|
2018-07-03 21:21:36 -07:00
|
|
|
|
2018-11-08 16:28:28 -08:00
|
|
|
sort.SliceStable(data.UnbondingDelegations[:], func(i, j int) bool {
|
|
|
|
return data.UnbondingDelegations[i].CreationHeight < data.UnbondingDelegations[j].CreationHeight
|
|
|
|
})
|
|
|
|
for _, ubd := range data.UnbondingDelegations {
|
|
|
|
keeper.SetUnbondingDelegation(ctx, ubd)
|
|
|
|
keeper.InsertUnbondingQueue(ctx, ubd)
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.SliceStable(data.Redelegations[:], func(i, j int) bool {
|
|
|
|
return data.Redelegations[i].CreationHeight < data.Redelegations[j].CreationHeight
|
|
|
|
})
|
|
|
|
for _, red := range data.Redelegations {
|
|
|
|
keeper.SetRedelegation(ctx, red)
|
|
|
|
keeper.InsertRedelegationQueue(ctx, red)
|
|
|
|
}
|
|
|
|
|
2018-10-03 09:37:06 -07:00
|
|
|
res = keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
2018-07-18 23:39:40 -07:00
|
|
|
return
|
2018-05-12 15:22:59 -07:00
|
|
|
}
|
|
|
|
|
2018-11-08 16:28:28 -08:00
|
|
|
// ExportGenesis returns a GenesisState for a given context and keeper. The
|
2018-07-03 21:21:36 -07:00
|
|
|
// GenesisState will contain the pool, params, validators, and bonds found in
|
|
|
|
// the keeper.
|
2018-11-08 16:28:28 -08:00
|
|
|
func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
|
2018-06-26 19:00:12 -07:00
|
|
|
pool := keeper.GetPool(ctx)
|
|
|
|
params := keeper.GetParams(ctx)
|
2018-11-08 16:28:28 -08:00
|
|
|
intraTxCounter := keeper.GetIntraTxCounter(ctx)
|
|
|
|
lastTotalPower := keeper.GetLastTotalPower(ctx)
|
2018-06-26 19:00:12 -07:00
|
|
|
validators := keeper.GetAllValidators(ctx)
|
|
|
|
bonds := keeper.GetAllDelegations(ctx)
|
2018-11-08 16:28:28 -08:00
|
|
|
var unbondingDelegations []types.UnbondingDelegation
|
|
|
|
keeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd types.UnbondingDelegation) (stop bool) {
|
|
|
|
unbondingDelegations = append(unbondingDelegations, ubd)
|
|
|
|
return false
|
|
|
|
})
|
|
|
|
var redelegations []types.Redelegation
|
|
|
|
keeper.IterateRedelegations(ctx, func(_ int64, red types.Redelegation) (stop bool) {
|
|
|
|
redelegations = append(redelegations, red)
|
|
|
|
return false
|
|
|
|
})
|
2018-07-03 21:21:36 -07:00
|
|
|
|
2018-06-26 19:00:12 -07:00
|
|
|
return types.GenesisState{
|
2018-11-08 16:28:28 -08:00
|
|
|
Pool: pool,
|
|
|
|
Params: params,
|
|
|
|
IntraTxCounter: intraTxCounter,
|
|
|
|
LastTotalPower: lastTotalPower,
|
|
|
|
Validators: validators,
|
|
|
|
Bonds: bonds,
|
|
|
|
UnbondingDelegations: unbondingDelegations,
|
|
|
|
Redelegations: redelegations,
|
2018-05-12 15:22:59 -07:00
|
|
|
}
|
|
|
|
}
|
2018-06-06 09:38:13 -07:00
|
|
|
|
2018-07-03 21:21:36 -07:00
|
|
|
// WriteValidators returns a slice of bonded genesis validators.
|
2018-06-26 19:00:12 -07:00
|
|
|
func WriteValidators(ctx sdk.Context, keeper Keeper) (vals []tmtypes.GenesisValidator) {
|
2018-11-04 20:44:43 -08:00
|
|
|
keeper.IterateLastValidators(ctx, func(_ int64, validator sdk.Validator) (stop bool) {
|
2018-06-06 09:38:13 -07:00
|
|
|
vals = append(vals, tmtypes.GenesisValidator{
|
2018-09-25 14:43:26 -07:00
|
|
|
PubKey: validator.GetConsPubKey(),
|
2018-07-02 08:57:33 -07:00
|
|
|
Power: validator.GetPower().RoundInt64(),
|
2018-06-06 09:38:13 -07:00
|
|
|
Name: validator.GetMoniker(),
|
|
|
|
})
|
2018-07-03 21:21:36 -07:00
|
|
|
|
2018-06-06 09:38:13 -07:00
|
|
|
return false
|
|
|
|
})
|
2018-07-03 21:21:36 -07:00
|
|
|
|
2018-06-06 09:38:13 -07:00
|
|
|
return
|
|
|
|
}
|
2018-10-07 21:12:37 -07:00
|
|
|
|
|
|
|
// ValidateGenesis validates the provided staking genesis state to ensure the
|
|
|
|
// expected invariants holds. (i.e. params in correct bounds, no duplicate validators)
|
|
|
|
func ValidateGenesis(data types.GenesisState) error {
|
|
|
|
err := validateGenesisStateValidators(data.Validators)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = validateParams(data.Params)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func validateParams(params types.Params) error {
|
|
|
|
if params.BondDenom == "" {
|
|
|
|
return fmt.Errorf("staking parameter BondDenom can't be an empty string")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func validateGenesisStateValidators(validators []types.Validator) (err error) {
|
|
|
|
addrMap := make(map[string]bool, len(validators))
|
|
|
|
for i := 0; i < len(validators); i++ {
|
|
|
|
val := validators[i]
|
|
|
|
strKey := string(val.ConsPubKey.Bytes())
|
|
|
|
if _, ok := addrMap[strKey]; ok {
|
|
|
|
return fmt.Errorf("duplicate validator in genesis state: moniker %v, Address %v", val.Description.Moniker, val.ConsAddress())
|
|
|
|
}
|
|
|
|
if val.Jailed && val.Status == sdk.Bonded {
|
|
|
|
return fmt.Errorf("validator is bonded and jailed in genesis state: moniker %v, Address %v", val.Description.Moniker, val.ConsAddress())
|
|
|
|
}
|
2018-11-08 16:28:28 -08:00
|
|
|
if val.DelegatorShares.IsZero() && val.Status != sdk.Unbonding {
|
|
|
|
return fmt.Errorf("bonded/unbonded genesis validator cannot have zero delegator shares, validator: %v", val)
|
2018-10-07 21:12:37 -07:00
|
|
|
}
|
|
|
|
addrMap[strKey] = true
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|