github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/distribution/keeper/invariants.go (about) 1 package keeper 2 3 import ( 4 "fmt" 5 6 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 7 8 "github.com/fibonacci-chain/fbc/x/distribution/types" 9 "github.com/fibonacci-chain/fbc/x/staking/exported" 10 ) 11 12 // RegisterInvariants registers all distribution invariants 13 func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) { 14 ir.RegisterRoute(types.ModuleName, "nonnegative-commission", NonNegativeCommissionsInvariant(k)) 15 ir.RegisterRoute(types.ModuleName, "can-withdraw", CanWithdrawInvariant(k)) 16 ir.RegisterRoute(types.ModuleName, "module-account", ModuleAccountInvariant(k)) 17 } 18 19 // NonNegativeCommissionsInvariant checks that accumulated commissions unwithdrawned fees are never negative 20 func NonNegativeCommissionsInvariant(k Keeper) sdk.Invariant { 21 return func(ctx sdk.Context) (string, bool) { 22 var msg string 23 var count int 24 var commission sdk.SysCoins 25 26 k.IterateValidatorAccumulatedCommissions(ctx, 27 func(addr sdk.ValAddress, c types.ValidatorAccumulatedCommission) (stop bool) { 28 commission = c 29 if commission.IsAnyNegative() { 30 count++ 31 msg += fmt.Sprintf("\t%v has negative accumulated commission coins: %v\n", addr, commission) 32 } 33 return false 34 }) 35 broken := count != 0 36 37 return sdk.FormatInvariant(types.ModuleName, "nonnegative accumulated commission", 38 fmt.Sprintf("found %d validators with negative accumulated commission\n%s", count, msg)), broken 39 } 40 } 41 42 // CanWithdrawInvariant checks that current commission can be completely withdrawn 43 func CanWithdrawInvariant(k Keeper) sdk.Invariant { 44 return func(ctx sdk.Context) (string, bool) { 45 var msg string 46 var count int 47 48 // cache, we don't want to write changes 49 ctx, _ = ctx.CacheContext() 50 51 // iterate over all validators 52 k.stakingKeeper.IterateValidators(ctx, func(_ int64, val exported.ValidatorI) (stop bool) { 53 valAddr := val.GetOperator() 54 accumCommission := k.GetValidatorAccumulatedCommission(ctx, valAddr) 55 if accumCommission.IsZero() { 56 return false 57 } 58 if _, err := k.WithdrawValidatorCommission(ctx, valAddr); err != nil { 59 count++ 60 msg += fmt.Sprintf("\t%v failed to withdraw accumulated commission coins: %v. error: %v\n", 61 valAddr, accumCommission, err) 62 } 63 return false 64 }) 65 66 broken := count != 0 67 return sdk.FormatInvariant(types.ModuleName, "withdraw commission", msg), broken 68 } 69 } 70 71 // ModuleAccountInvariant checks that the coins held by the distr ModuleAccount 72 // is consistent with the sum of accumulated commissions 73 func ModuleAccountInvariant(k Keeper) sdk.Invariant { 74 return func(ctx sdk.Context) (string, bool) { 75 var accumulatedCommission sdk.SysCoins 76 k.IterateValidatorAccumulatedCommissions(ctx, 77 func(_ sdk.ValAddress, commission types.ValidatorAccumulatedCommission) (stop bool) { 78 accumulatedCommission = accumulatedCommission.Add(commission...) 79 return false 80 }) 81 communityPool := k.GetFeePoolCommunityCoins(ctx) 82 macc := k.GetDistributionAccount(ctx) 83 broken := !macc.GetCoins().IsEqual(communityPool.Add(accumulatedCommission...)) 84 return sdk.FormatInvariant(types.ModuleName, "ModuleAccount coins", 85 fmt.Sprintf("\texpected distribution ModuleAccount coins: %s\n"+ 86 "\tacutal distribution ModuleAccount coins: %s\n", 87 accumulatedCommission, macc.GetCoins())), broken 88 } 89 }