github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/staking/keeper/invariants.go (about) 1 package keeper 2 3 import ( 4 "bytes" 5 "fmt" 6 7 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 8 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/staking/exported" 9 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/staking/types" 10 ) 11 12 // RegisterInvariants registers all staking invariants 13 func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) { 14 15 ir.RegisterRoute(types.ModuleName, "module-accounts", 16 ModuleAccountInvariants(k)) 17 ir.RegisterRoute(types.ModuleName, "nonnegative-power", 18 NonNegativePowerInvariant(k)) 19 ir.RegisterRoute(types.ModuleName, "positive-delegation", 20 PositiveDelegationInvariant(k)) 21 ir.RegisterRoute(types.ModuleName, "delegator-shares", 22 DelegatorSharesInvariant(k)) 23 } 24 25 // AllInvariants runs all invariants of the staking module. 26 func AllInvariants(k Keeper) sdk.Invariant { 27 28 return func(ctx sdk.Context) (string, bool) { 29 res, stop := ModuleAccountInvariants(k)(ctx) 30 if stop { 31 return res, stop 32 } 33 34 res, stop = NonNegativePowerInvariant(k)(ctx) 35 if stop { 36 return res, stop 37 } 38 39 res, stop = PositiveDelegationInvariant(k)(ctx) 40 if stop { 41 return res, stop 42 } 43 44 return DelegatorSharesInvariant(k)(ctx) 45 } 46 } 47 48 // ModuleAccountInvariants checks that the bonded and notBonded ModuleAccounts pools 49 // reflects the tokens actively bonded and not bonded 50 func ModuleAccountInvariants(k Keeper) sdk.Invariant { 51 return func(ctx sdk.Context) (string, bool) { 52 bonded := sdk.ZeroInt() 53 notBonded := sdk.ZeroInt() 54 bondedPool := k.GetBondedPool(ctx) 55 notBondedPool := k.GetNotBondedPool(ctx) 56 bondDenom := k.BondDenom(ctx) 57 58 k.IterateValidators(ctx, func(_ int64, validator exported.ValidatorI) bool { 59 switch validator.GetStatus() { 60 //case sdk.Bonded: 61 //bonded = bonded.Add(validator.GetTokens()) 62 //case sdk.Unbonding, sdk.Unbonded: 63 // notBonded = notBonded.Add(validator.GetTokens()) 64 default: 65 panic("invalid validator status") 66 } 67 return false 68 }) 69 70 k.IterateUnbondingDelegations(ctx, func(_ int64, ubd types.UnbondingDelegation) bool { 71 for _, entry := range ubd.Entries { 72 notBonded = notBonded.Add(entry.Balance) 73 } 74 return false 75 }) 76 77 poolBonded := bondedPool.GetCoins().AmountOf(bondDenom) 78 poolNotBonded := notBondedPool.GetCoins().AmountOf(bondDenom) 79 broken := !poolBonded.Equal(bonded.ToDec()) || !poolNotBonded.Equal(notBonded.ToDec()) 80 81 // Bonded tokens should equal sum of tokens with bonded validators 82 // Not-bonded tokens should equal unbonding delegations plus tokens on unbonded validators 83 return sdk.FormatInvariant(types.ModuleName, "bonded and not bonded module account coins", fmt.Sprintf( 84 "\tPool's bonded tokens: %v\n"+ 85 "\tsum of bonded tokens: %v\n"+ 86 "not bonded token invariance:\n"+ 87 "\tPool's not bonded tokens: %v\n"+ 88 "\tsum of not bonded tokens: %v\n"+ 89 "module accounts total (bonded + not bonded):\n"+ 90 "\tModule Accounts' tokens: %v\n"+ 91 "\tsum tokens: %v\n", 92 poolBonded, bonded, poolNotBonded, notBonded, poolBonded.Add(poolNotBonded), bonded.Add(notBonded))), broken 93 } 94 } 95 96 // NonNegativePowerInvariant checks that all stored validators have >= 0 power. 97 func NonNegativePowerInvariant(k Keeper) sdk.Invariant { 98 return func(ctx sdk.Context) (string, bool) { 99 var msg string 100 var broken bool 101 102 iterator := k.ValidatorsPowerStoreIterator(ctx) 103 104 for ; iterator.Valid(); iterator.Next() { 105 validator, found := k.GetValidator(ctx, iterator.Value()) 106 if !found { 107 panic(fmt.Sprintf("validator record not found for address: %X\n", iterator.Value())) 108 } 109 110 powerKey := types.GetValidatorsByPowerIndexKey(validator) 111 112 if !bytes.Equal(iterator.Key(), powerKey) { 113 broken = true 114 msg += fmt.Sprintf("power store invariance:\n\tvalidator.Power: %v"+ 115 "\n\tkey should be: %v\n\tkey in store: %v\n", 116 validator.GetConsensusPower(), powerKey, iterator.Key()) 117 } 118 119 if validator.Tokens.IsNegative() { 120 broken = true 121 msg += fmt.Sprintf("\tnegative tokens for validator: %v\n", validator) 122 } 123 } 124 iterator.Close() 125 return sdk.FormatInvariant(types.ModuleName, "nonnegative power", fmt.Sprintf("found invalid validator powers\n%s", msg)), broken 126 } 127 } 128 129 // PositiveDelegationInvariant checks that all stored delegations have > 0 shares. 130 func PositiveDelegationInvariant(k Keeper) sdk.Invariant { 131 return func(ctx sdk.Context) (string, bool) { 132 var msg string 133 var count int 134 135 delegations := k.GetAllDelegations(ctx) 136 for _, delegation := range delegations { 137 if delegation.Shares.IsNegative() { 138 count++ 139 msg += fmt.Sprintf("\tdelegation with negative shares: %+v\n", delegation) 140 } 141 if delegation.Shares.IsZero() { 142 count++ 143 msg += fmt.Sprintf("\tdelegation with zero shares: %+v\n", delegation) 144 } 145 } 146 broken := count != 0 147 148 return sdk.FormatInvariant(types.ModuleName, "positive delegations", fmt.Sprintf( 149 "%d invalid delegations found\n%s", count, msg)), broken 150 } 151 } 152 153 // DelegatorSharesInvariant checks whether all the delegator shares which persist 154 // in the delegator object add up to the correct total delegator shares 155 // amount stored in each validator. 156 func DelegatorSharesInvariant(k Keeper) sdk.Invariant { 157 return func(ctx sdk.Context) (string, bool) { 158 var msg string 159 var broken bool 160 161 validators := k.GetAllValidators(ctx) 162 for _, validator := range validators { 163 164 valTotalDelShares := validator.GetDelegatorShares() 165 166 totalDelShares := sdk.ZeroDec() 167 delegations := k.GetValidatorDelegations(ctx, validator.GetOperator()) 168 for _, delegation := range delegations { 169 totalDelShares = totalDelShares.Add(delegation.Shares) 170 } 171 172 if !valTotalDelShares.Equal(totalDelShares) { 173 broken = true 174 msg += fmt.Sprintf("broken delegator shares invariance:\n"+ 175 "\tvalidator.DelegatorShares: %v\n"+ 176 "\tsum of Delegator.Shares: %v\n", valTotalDelShares, totalDelShares) 177 } 178 } 179 return sdk.FormatInvariant(types.ModuleName, "delegator shares", msg), broken 180 } 181 }