github.com/Finschia/finschia-sdk@v0.48.1/x/staking/genesis.go (about)

     1  package staking
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  
     7  	octypes "github.com/Finschia/ostracon/types"
     8  	abci "github.com/tendermint/tendermint/abci/types"
     9  
    10  	cryptocodec "github.com/Finschia/finschia-sdk/crypto/codec"
    11  	sdk "github.com/Finschia/finschia-sdk/types"
    12  	"github.com/Finschia/finschia-sdk/x/staking/keeper"
    13  	"github.com/Finschia/finschia-sdk/x/staking/types"
    14  )
    15  
    16  // InitGenesis sets the pool and parameters for the provided keeper.  For each
    17  // validator in data, it sets that validator in the keeper along with manually
    18  // setting the indexes. In addition, it also sets any delegations found in
    19  // data. Finally, it updates the bonded validators.
    20  // Returns final validator set after applying all declaration and delegations
    21  func InitGenesis(
    22  	ctx sdk.Context, keeper keeper.Keeper, accountKeeper types.AccountKeeper,
    23  	bankKeeper types.BankKeeper, data *types.GenesisState,
    24  ) (res []abci.ValidatorUpdate) {
    25  	bondedTokens := sdk.ZeroInt()
    26  	notBondedTokens := sdk.ZeroInt()
    27  
    28  	// We need to pretend to be "n blocks before genesis", where "n" is the
    29  	// validator update delay, so that e.g. slashing periods are correctly
    30  	// initialized for the validator set e.g. with a one-block offset - the
    31  	// first TM block is at height 1, so state updates applied from
    32  	// genesis.json are in block 0.
    33  	ctx = ctx.WithBlockHeight(1 - sdk.ValidatorUpdateDelay)
    34  
    35  	keeper.SetParams(ctx, data.Params)
    36  	keeper.SetLastTotalPower(ctx, data.LastTotalPower)
    37  
    38  	for _, validator := range data.Validators {
    39  		keeper.SetValidator(ctx, validator)
    40  
    41  		// Manually set indices for the first time
    42  		if err := keeper.SetValidatorByConsAddr(ctx, validator); err != nil {
    43  			panic(err)
    44  		}
    45  		keeper.SetValidatorByPowerIndex(ctx, validator)
    46  
    47  		// Call the creation hook if not exported
    48  		if !data.Exported {
    49  			keeper.AfterValidatorCreated(ctx, validator.GetOperator())
    50  		}
    51  
    52  		// update timeslice if necessary
    53  		if validator.IsUnbonding() {
    54  			keeper.InsertUnbondingValidatorQueue(ctx, validator)
    55  		}
    56  
    57  		switch validator.GetStatus() {
    58  		case types.Bonded:
    59  			bondedTokens = bondedTokens.Add(validator.GetTokens())
    60  		case types.Unbonding, types.Unbonded:
    61  			notBondedTokens = notBondedTokens.Add(validator.GetTokens())
    62  		default:
    63  			panic("invalid validator status")
    64  		}
    65  	}
    66  
    67  	for _, delegation := range data.Delegations {
    68  		delegatorAddress := sdk.MustAccAddressFromBech32(delegation.DelegatorAddress)
    69  
    70  		// Call the before-creation hook if not exported
    71  		if !data.Exported {
    72  			keeper.BeforeDelegationCreated(ctx, delegatorAddress, delegation.GetValidatorAddr())
    73  		}
    74  
    75  		keeper.SetDelegation(ctx, delegation)
    76  		// Call the after-modification hook if not exported
    77  		if !data.Exported {
    78  			keeper.AfterDelegationModified(ctx, delegatorAddress, delegation.GetValidatorAddr())
    79  		}
    80  	}
    81  
    82  	for _, ubd := range data.UnbondingDelegations {
    83  		keeper.SetUnbondingDelegation(ctx, ubd)
    84  
    85  		for _, entry := range ubd.Entries {
    86  			keeper.InsertUBDQueue(ctx, ubd, entry.CompletionTime)
    87  			notBondedTokens = notBondedTokens.Add(entry.Balance)
    88  		}
    89  	}
    90  
    91  	for _, red := range data.Redelegations {
    92  		keeper.SetRedelegation(ctx, red)
    93  
    94  		for _, entry := range red.Entries {
    95  			keeper.InsertRedelegationQueue(ctx, red, entry.CompletionTime)
    96  		}
    97  	}
    98  
    99  	bondedCoins := sdk.NewCoins(sdk.NewCoin(data.Params.BondDenom, bondedTokens))
   100  	notBondedCoins := sdk.NewCoins(sdk.NewCoin(data.Params.BondDenom, notBondedTokens))
   101  
   102  	// check if the unbonded and bonded pools accounts exists
   103  	bondedPool := keeper.GetBondedPool(ctx)
   104  	if bondedPool == nil {
   105  		panic(fmt.Sprintf("%s module account has not been set", types.BondedPoolName))
   106  	}
   107  	// TODO remove with genesis 2-phases refactor https://github.com/cosmos/cosmos-sdk/issues/2862
   108  	bondedBalance := bankKeeper.GetAllBalances(ctx, bondedPool.GetAddress())
   109  	if bondedBalance.IsZero() {
   110  		accountKeeper.SetModuleAccount(ctx, bondedPool)
   111  	}
   112  	// if balance is different from bonded coins panic because genesis is most likely malformed
   113  	if !bondedBalance.IsEqual(bondedCoins) {
   114  		panic(fmt.Sprintf("bonded pool balance is different from bonded coins: %s <-> %s", bondedBalance, bondedCoins))
   115  	}
   116  	notBondedPool := keeper.GetNotBondedPool(ctx)
   117  	if notBondedPool == nil {
   118  		panic(fmt.Sprintf("%s module account has not been set", types.NotBondedPoolName))
   119  	}
   120  
   121  	notBondedBalance := bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress())
   122  	if notBondedBalance.IsZero() {
   123  		accountKeeper.SetModuleAccount(ctx, notBondedPool)
   124  	}
   125  	// if balance is different from non bonded coins panic because genesis is most likely malformed
   126  	if !notBondedBalance.IsEqual(notBondedCoins) {
   127  		panic(fmt.Sprintf("not bonded pool balance is different from not bonded coins: %s <-> %s", notBondedBalance, notBondedCoins))
   128  	}
   129  	// don't need to run Tendermint updates if we exported
   130  	if data.Exported {
   131  		for _, lv := range data.LastValidatorPowers {
   132  			valAddr, err := sdk.ValAddressFromBech32(lv.Address)
   133  			if err != nil {
   134  				panic(err)
   135  			}
   136  			keeper.SetLastValidatorPower(ctx, valAddr, lv.Power)
   137  			validator, found := keeper.GetValidator(ctx, valAddr)
   138  
   139  			if !found {
   140  				panic(fmt.Sprintf("validator %s not found", lv.Address))
   141  			}
   142  
   143  			update := validator.ABCIValidatorUpdate(keeper.PowerReduction(ctx))
   144  			update.Power = lv.Power // keep the next-val-set offset, use the last power for the first block
   145  			res = append(res, update)
   146  		}
   147  	} else {
   148  		var err error
   149  		res, err = keeper.ApplyAndReturnValidatorSetUpdates(ctx)
   150  		if err != nil {
   151  			log.Fatal(err)
   152  		}
   153  	}
   154  
   155  	return res
   156  }
   157  
   158  // ExportGenesis returns a GenesisState for a given context and keeper. The
   159  // GenesisState will contain the pool, params, validators, and bonds found in
   160  // the keeper.
   161  func ExportGenesis(ctx sdk.Context, keeper keeper.Keeper) *types.GenesisState {
   162  	var unbondingDelegations []types.UnbondingDelegation
   163  
   164  	keeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd types.UnbondingDelegation) (stop bool) {
   165  		unbondingDelegations = append(unbondingDelegations, ubd)
   166  		return false
   167  	})
   168  
   169  	var redelegations []types.Redelegation
   170  
   171  	keeper.IterateRedelegations(ctx, func(_ int64, red types.Redelegation) (stop bool) {
   172  		redelegations = append(redelegations, red)
   173  		return false
   174  	})
   175  
   176  	var lastValidatorPowers []types.LastValidatorPower
   177  
   178  	keeper.IterateLastValidatorPowers(ctx, func(addr sdk.ValAddress, power int64) (stop bool) {
   179  		lastValidatorPowers = append(lastValidatorPowers, types.LastValidatorPower{Address: addr.String(), Power: power})
   180  		return false
   181  	})
   182  
   183  	return &types.GenesisState{
   184  		Params:               keeper.GetParams(ctx),
   185  		LastTotalPower:       keeper.GetLastTotalPower(ctx),
   186  		LastValidatorPowers:  lastValidatorPowers,
   187  		Validators:           keeper.GetAllValidators(ctx),
   188  		Delegations:          keeper.GetAllDelegations(ctx),
   189  		UnbondingDelegations: unbondingDelegations,
   190  		Redelegations:        redelegations,
   191  		Exported:             true,
   192  	}
   193  }
   194  
   195  // WriteValidators returns a slice of bonded genesis validators.
   196  func WriteValidators(ctx sdk.Context, keeper keeper.Keeper) (vals []octypes.GenesisValidator, err error) {
   197  	keeper.IterateLastValidators(ctx, func(_ int64, validator types.ValidatorI) (stop bool) {
   198  		pk, err := validator.ConsPubKey()
   199  		if err != nil {
   200  			return true
   201  		}
   202  		tmPk, err := cryptocodec.ToOcPubKeyInterface(pk)
   203  		if err != nil {
   204  			return true
   205  		}
   206  
   207  		vals = append(vals, octypes.GenesisValidator{
   208  			Address: sdk.ConsAddress(tmPk.Address()).Bytes(),
   209  			PubKey:  tmPk,
   210  			Power:   validator.GetConsensusPower(keeper.PowerReduction(ctx)),
   211  			Name:    validator.GetMoniker(),
   212  		})
   213  
   214  		return false
   215  	})
   216  
   217  	return
   218  }
   219  
   220  // ValidateGenesis validates the provided staking genesis state to ensure the
   221  // expected invariants holds. (i.e. params in correct bounds, no duplicate validators)
   222  func ValidateGenesis(data *types.GenesisState) error {
   223  	if err := validateGenesisStateValidators(data.Validators); err != nil {
   224  		return err
   225  	}
   226  
   227  	return data.Params.Validate()
   228  }
   229  
   230  func validateGenesisStateValidators(validators []types.Validator) error {
   231  	addrMap := make(map[string]bool, len(validators))
   232  
   233  	for i := 0; i < len(validators); i++ {
   234  		val := validators[i]
   235  		consPk, err := val.ConsPubKey()
   236  		if err != nil {
   237  			return err
   238  		}
   239  
   240  		strKey := string(consPk.Bytes())
   241  
   242  		if _, ok := addrMap[strKey]; ok {
   243  			consAddr, err := val.GetConsAddr()
   244  			if err != nil {
   245  				return err
   246  			}
   247  			return fmt.Errorf("duplicate validator in genesis state: moniker %v, address %v", val.Description.Moniker, consAddr)
   248  		}
   249  
   250  		if val.Jailed && val.IsBonded() {
   251  			consAddr, err := val.GetConsAddr()
   252  			if err != nil {
   253  				return err
   254  			}
   255  			return fmt.Errorf("validator is bonded and jailed in genesis state: moniker %v, address %v", val.Description.Moniker, consAddr)
   256  		}
   257  
   258  		if val.DelegatorShares.IsZero() && !val.IsUnbonding() {
   259  			return fmt.Errorf("bonded/unbonded genesis validator cannot have zero delegator shares, validator: %v", val)
   260  		}
   261  
   262  		addrMap[strKey] = true
   263  	}
   264  
   265  	return nil
   266  }