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 }