github.com/cosmos/cosmos-sdk@v0.50.10/x/bank/keeper/invariants.go (about) 1 package keeper 2 3 import ( 4 "fmt" 5 6 sdk "github.com/cosmos/cosmos-sdk/types" 7 "github.com/cosmos/cosmos-sdk/types/query" 8 "github.com/cosmos/cosmos-sdk/x/bank/types" 9 ) 10 11 // RegisterInvariants registers the bank module invariants 12 func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) { 13 ir.RegisterRoute(types.ModuleName, "nonnegative-outstanding", NonnegativeBalanceInvariant(k)) 14 ir.RegisterRoute(types.ModuleName, "total-supply", TotalSupply(k)) 15 } 16 17 // AllInvariants runs all invariants of the X/bank module. 18 func AllInvariants(k Keeper) sdk.Invariant { 19 return func(ctx sdk.Context) (string, bool) { 20 res, stop := NonnegativeBalanceInvariant(k)(ctx) 21 if stop { 22 return res, stop 23 } 24 return TotalSupply(k)(ctx) 25 } 26 } 27 28 // NonnegativeBalanceInvariant checks that all accounts in the application have non-negative balances 29 func NonnegativeBalanceInvariant(k ViewKeeper) sdk.Invariant { 30 return func(ctx sdk.Context) (string, bool) { 31 var ( 32 msg string 33 count int 34 ) 35 36 k.IterateAllBalances(ctx, func(addr sdk.AccAddress, balance sdk.Coin) bool { 37 if balance.IsNegative() { 38 count++ 39 msg += fmt.Sprintf("\t%s has a negative balance of %s\n", addr, balance) 40 } 41 42 return false 43 }) 44 45 broken := count != 0 46 47 return sdk.FormatInvariant( 48 types.ModuleName, "nonnegative-outstanding", 49 fmt.Sprintf("amount of negative balances found %d\n%s", count, msg), 50 ), broken 51 } 52 } 53 54 // TotalSupply checks that the total supply reflects all the coins held in accounts 55 func TotalSupply(k Keeper) sdk.Invariant { 56 return func(ctx sdk.Context) (string, bool) { 57 expectedTotal := sdk.Coins{} 58 supply, _, err := k.GetPaginatedTotalSupply(ctx, &query.PageRequest{Limit: query.PaginationMaxLimit}) 59 if err != nil { 60 return sdk.FormatInvariant(types.ModuleName, "query supply", 61 fmt.Sprintf("error querying total supply %v", err)), false 62 } 63 64 k.IterateAllBalances(ctx, func(_ sdk.AccAddress, balance sdk.Coin) bool { 65 expectedTotal = expectedTotal.Add(balance) 66 return false 67 }) 68 69 broken := !expectedTotal.Equal(supply) 70 71 return sdk.FormatInvariant(types.ModuleName, "total supply", 72 fmt.Sprintf( 73 "\tsum of accounts coins: %v\n"+ 74 "\tsupply.Total: %v\n", 75 expectedTotal, supply)), broken 76 } 77 }