github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/staking/genesis.go (about)

     1  package staking
     2  
     3  import (
     4  	"fmt"
     5  
     6  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     7  	supplyexported "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/supply/exported"
     8  	abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types"
     9  	tmtypes "github.com/fibonacci-chain/fbc/libs/tendermint/types"
    10  	"github.com/fibonacci-chain/fbc/x/staking/exported"
    11  	"github.com/fibonacci-chain/fbc/x/staking/types"
    12  )
    13  
    14  // InitGenesis sets the pool and parameters for the provided keeper
    15  // For each validator in data, it sets that validator in the keeper along with manually setting the indexes
    16  // In addition, it also sets any delegations found in data
    17  // Finally, it updates the bonded validators
    18  // Returns final validator set after applying all declaration and delegations
    19  func InitGenesis(ctx sdk.Context, keeper Keeper, accountKeeper types.AccountKeeper,
    20  	supplyKeeper types.SupplyKeeper, data types.GenesisState) (res []abci.ValidatorUpdate) {
    21  	bondedTokens, notBondedTokens := sdk.ZeroDec(), sdk.ZeroDec()
    22  
    23  	// We need to pretend to be "n blocks before genesis", where "n" is the validator update delay, so that e.g.
    24  	// slashing periods are correctly initialized for the validator set e.g. with a one-block offset - the first
    25  	// TM block is at height 1, so state updates applied from genesis.json are in block 0.
    26  	ctx.SetBlockHeight(1 - sdk.ValidatorUpdateDelay)
    27  
    28  	keeper.SetParams(ctx, data.Params)
    29  	keeper.SetLastTotalPower(ctx, data.LastTotalPower)
    30  
    31  	for _, validator := range data.Validators {
    32  		initValidator(ctx, validator, keeper, &bondedTokens, data.Exported)
    33  	}
    34  
    35  	for _, delegator := range data.Delegators {
    36  		initDelegator(ctx, delegator, keeper, &bondedTokens)
    37  	}
    38  
    39  	for _, ubd := range data.UnbondingDelegations {
    40  		initUnbondingDelegation(ctx, ubd, keeper, &notBondedTokens)
    41  	}
    42  	for _, sharesExported := range data.AllShares {
    43  		keeper.SetShares(ctx, sharesExported.DelAddress, sharesExported.ValidatorAddress, sharesExported.Shares)
    44  	}
    45  	for _, proxyDelegatorKeyExported := range data.ProxyDelegatorKeys {
    46  		keeper.SetProxyBinding(ctx, proxyDelegatorKeyExported.ProxyAddr, proxyDelegatorKeyExported.DelAddr, false)
    47  	}
    48  
    49  	checkPools(ctx, keeper, sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, bondedTokens),
    50  		sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, notBondedTokens), data.Exported)
    51  
    52  	// don't need to run Tendermint updates if we exported
    53  	if data.Exported {
    54  		for _, lv := range data.LastValidatorPowers {
    55  			keeper.SetLastValidatorPower(ctx, lv.Address, lv.Power)
    56  			validator, found := keeper.GetValidator(ctx, lv.Address)
    57  			if !found {
    58  				panic(fmt.Sprintf("validator %s not found", lv.Address))
    59  			}
    60  			update := validator.ABCIValidatorUpdate()
    61  			update.Power = lv.Power // keep the next-val-set offset, use the last power for the first block
    62  			res = append(res, update)
    63  		}
    64  	} else {
    65  		res = keeper.ApplyAndReturnValidatorSetUpdates(ctx)
    66  	}
    67  
    68  	return res
    69  }
    70  
    71  // assume that there is only fibo in pool, if not panics
    72  func checkTokenSum(tokenSum sdk.SysCoin, pool supplyexported.ModuleAccountI) {
    73  	poolCoins := pool.GetCoins()
    74  	if !poolCoins.IsZero() {
    75  		if len(poolCoins) != 1 {
    76  			panic(fmt.Sprintf("only fibo in %s, but there are %d kinds of coins", pool.GetName(), len(poolCoins)))
    77  		}
    78  
    79  		if !tokenSum.ToCoins().IsEqual(poolCoins) {
    80  			panic(fmt.Sprintf("coins in %s don't match the token sum, tokenSum: %s, poolCoins: %s",
    81  				pool.GetName(), tokenSum.String(), poolCoins.String()))
    82  		}
    83  	}
    84  }
    85  
    86  func checkPools(ctx sdk.Context, keeper Keeper, bondedDecCoin, notBondedDecCoin sdk.SysCoin, isExported bool) {
    87  	bondedPool := keeper.GetBondedPool(ctx)
    88  	if bondedPool == nil {
    89  		panic(fmt.Sprintf("%s module account has not been set", types.BondedPoolName))
    90  	}
    91  	notBondedPool := keeper.GetNotBondedPool(ctx)
    92  	if notBondedPool == nil {
    93  		panic(fmt.Sprintf("%s module account has not been set", types.NotBondedPoolName))
    94  	}
    95  	if isExported {
    96  		checkTokenSum(bondedDecCoin, bondedPool)
    97  		checkTokenSum(notBondedDecCoin, notBondedPool)
    98  	}
    99  }
   100  
   101  func initUnbondingDelegation(ctx sdk.Context, ubd UndelegationInfo, keeper Keeper, notBondedTokens *sdk.Dec) {
   102  	keeper.SetUndelegating(ctx, ubd)
   103  	keeper.SetAddrByTimeKeyWithNilValue(ctx, ubd.CompletionTime, ubd.DelegatorAddress)
   104  	*notBondedTokens = notBondedTokens.Add(ubd.Quantity)
   105  }
   106  
   107  func initDelegator(ctx sdk.Context, delegator Delegator, keeper Keeper, pBondedTokens *sdk.Dec) {
   108  	keeper.SetDelegator(ctx, delegator)
   109  	*pBondedTokens = pBondedTokens.Add(delegator.Tokens)
   110  }
   111  
   112  func initValidator(ctx sdk.Context, valExported ValidatorExport, keeper Keeper, pBondedTokens *sdk.Dec, exported bool) {
   113  	validator := valExported.Import()
   114  	keeper.SetValidator(ctx, validator)
   115  
   116  	// manually set indices for the first time
   117  	keeper.SetValidatorByConsAddr(ctx, validator)
   118  	keeper.SetValidatorByPowerIndex(ctx, validator)
   119  
   120  	// call the creation hook if not exported
   121  	if !exported {
   122  		keeper.AfterValidatorCreated(ctx, validator.OperatorAddress)
   123  	}
   124  
   125  	// update timeslice if necessary
   126  	if validator.IsUnbonding() {
   127  		keeper.InsertValidatorQueue(ctx, validator)
   128  	}
   129  	// all the msd on validator should be added into bonded pool
   130  	*pBondedTokens = pBondedTokens.Add(validator.MinSelfDelegation)
   131  }
   132  
   133  // ExportGenesis returns a GenesisState for a given context and keeper
   134  // The GenesisState will contain the pool, params, validators, and bonds found in the keeper
   135  func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
   136  	params := keeper.GetParams(ctx)
   137  	lastTotalPower := keeper.GetLastTotalPower(ctx)
   138  	validators := keeper.GetAllValidators(ctx)
   139  	var delegators []types.Delegator
   140  	keeper.IterateDelegator(ctx, func(_ int64, delegator types.Delegator) (stop bool) {
   141  		delegators = append(delegators, delegator)
   142  		return false
   143  	})
   144  	var undelegationInfos []types.UndelegationInfo
   145  	keeper.IterateUndelegationInfo(ctx, func(_ int64, ubd types.UndelegationInfo) (stop bool) {
   146  		undelegationInfos = append(undelegationInfos, ubd)
   147  		return false
   148  	})
   149  	var lastValidatorPowers []types.LastValidatorPower
   150  	keeper.IterateLastValidatorPowers(ctx, func(addr sdk.ValAddress, power int64) (stop bool) {
   151  		lastValidatorPowers = append(lastValidatorPowers, types.NewLastValidatorPower(addr, power))
   152  		return false
   153  	})
   154  	var sharesExportedSlice []types.SharesExported
   155  	keeper.IterateShares(ctx,
   156  		func(_ int64, delAddr sdk.AccAddress, valAddr sdk.ValAddress, shares types.Shares) (stop bool) {
   157  			sharesExportedSlice = append(sharesExportedSlice, types.NewSharesExported(delAddr, valAddr, shares))
   158  			return false
   159  		})
   160  
   161  	var proxyDelegatorKeys []types.ProxyDelegatorKeyExported
   162  	keeper.IterateProxy(ctx, []byte{}, false, func(_ int64, delAddr, proxyAddr sdk.AccAddress) (stop bool) {
   163  		proxyDelegatorKeys = append(proxyDelegatorKeys, types.NewProxyDelegatorKeyExported(delAddr, proxyAddr))
   164  		return false
   165  	})
   166  
   167  	return types.GenesisState{
   168  		Params:               params,
   169  		LastTotalPower:       lastTotalPower,
   170  		LastValidatorPowers:  lastValidatorPowers,
   171  		Validators:           validators.Export(),
   172  		Delegators:           delegators,
   173  		UnbondingDelegations: undelegationInfos,
   174  		AllShares:            sharesExportedSlice,
   175  		ProxyDelegatorKeys:   proxyDelegatorKeys,
   176  		Exported:             true,
   177  	}
   178  }
   179  
   180  // GetLatestGenesisValidator returns a slice of bonded genesis validators
   181  func GetLatestGenesisValidator(ctx sdk.Context, keeper Keeper) (vals []tmtypes.GenesisValidator) {
   182  	keeper.IterateLastValidators(ctx, func(_ int64, validator exported.ValidatorI) (stop bool) {
   183  		vals = append(vals, tmtypes.GenesisValidator{
   184  			PubKey: validator.GetConsPubKey(),
   185  			Power:  validator.GetConsensusPower(),
   186  			Name:   validator.GetMoniker(),
   187  		})
   188  
   189  		return false
   190  	})
   191  
   192  	return
   193  }
   194  
   195  // ValidateGenesis validates the provided staking genesis state to ensure the expected invariants holds
   196  // (i.e. params in correct bounds, no duplicate validators)
   197  func ValidateGenesis(data types.GenesisState) error {
   198  	err := validateGenesisStateValidators(data.Validators)
   199  	if err != nil {
   200  		return err
   201  	}
   202  	return data.Params.Validate()
   203  }
   204  
   205  func validateGenesisStateValidators(valsExported []types.ValidatorExported) (err error) {
   206  	valsLen := len(valsExported)
   207  	addrMap := make(map[string]bool, valsLen)
   208  	for i := 0; i < valsLen; i++ {
   209  		valExported := valsExported[i]
   210  		strKey := valExported.ConsPubKey
   211  		if _, ok := addrMap[strKey]; ok {
   212  			return fmt.Errorf("duplicate validator in genesis state: moniker %v, address %v",
   213  				valExported.Description.Moniker, valExported.ConsAddress())
   214  		}
   215  		if valExported.Jailed && valExported.IsBonded() {
   216  			return fmt.Errorf("validator is bonded and jailed in genesis state: moniker %v, address %v",
   217  				valExported.Description.Moniker, valExported.ConsAddress())
   218  		}
   219  		if valExported.DelegatorShares.IsZero() {
   220  			return fmt.Errorf("it's impossible for a validator with zero delegator shares, validator: %v", valExported)
   221  		}
   222  		addrMap[strKey] = true
   223  	}
   224  	return
   225  }