github.com/cosmos/cosmos-sdk@v0.50.10/x/auth/keeper/keeper.go (about) 1 package keeper 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 8 "cosmossdk.io/collections" 9 "cosmossdk.io/collections/indexes" 10 "cosmossdk.io/core/address" 11 "cosmossdk.io/core/store" 12 errorsmod "cosmossdk.io/errors" 13 "cosmossdk.io/log" 14 15 "github.com/cosmos/cosmos-sdk/codec" 16 cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" 17 sdk "github.com/cosmos/cosmos-sdk/types" 18 sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" 19 "github.com/cosmos/cosmos-sdk/x/auth/types" 20 ) 21 22 // AccountKeeperI is the interface contract that x/auth's keeper implements. 23 type AccountKeeperI interface { 24 // Return a new account with the next account number and the specified address. Does not save the new account to the store. 25 NewAccountWithAddress(context.Context, sdk.AccAddress) sdk.AccountI 26 27 // Return a new account with the next account number. Does not save the new account to the store. 28 NewAccount(context.Context, sdk.AccountI) sdk.AccountI 29 30 // Check if an account exists in the store. 31 HasAccount(context.Context, sdk.AccAddress) bool 32 33 // Retrieve an account from the store. 34 GetAccount(context.Context, sdk.AccAddress) sdk.AccountI 35 36 // Set an account in the store. 37 SetAccount(context.Context, sdk.AccountI) 38 39 // Remove an account from the store. 40 RemoveAccount(context.Context, sdk.AccountI) 41 42 // Iterate over all accounts, calling the provided function. Stop iteration when it returns true. 43 IterateAccounts(context.Context, func(sdk.AccountI) bool) 44 45 // Fetch the public key of an account at a specified address 46 GetPubKey(context.Context, sdk.AccAddress) (cryptotypes.PubKey, error) 47 48 // Fetch the sequence of an account at a specified address. 49 GetSequence(context.Context, sdk.AccAddress) (uint64, error) 50 51 // Fetch the next account number, and increment the internal counter. 52 NextAccountNumber(context.Context) uint64 53 54 // GetModulePermissions fetches per-module account permissions 55 GetModulePermissions() map[string]types.PermissionsForAddress 56 57 // AddressCodec returns the account address codec. 58 AddressCodec() address.Codec 59 } 60 61 func NewAccountIndexes(sb *collections.SchemaBuilder) AccountsIndexes { 62 return AccountsIndexes{ 63 Number: indexes.NewUnique( 64 sb, types.AccountNumberStoreKeyPrefix, "account_by_number", collections.Uint64Key, sdk.AccAddressKey, 65 func(_ sdk.AccAddress, v sdk.AccountI) (uint64, error) { 66 return v.GetAccountNumber(), nil 67 }, 68 ), 69 } 70 } 71 72 type AccountsIndexes struct { 73 // Number is a unique index that indexes accounts by their account number. 74 Number *indexes.Unique[uint64, sdk.AccAddress, sdk.AccountI] 75 } 76 77 func (a AccountsIndexes) IndexesList() []collections.Index[sdk.AccAddress, sdk.AccountI] { 78 return []collections.Index[sdk.AccAddress, sdk.AccountI]{ 79 a.Number, 80 } 81 } 82 83 // AccountKeeper encodes/decodes accounts using the go-amino (binary) 84 // encoding/decoding library. 85 type AccountKeeper struct { 86 addressCodec address.Codec 87 88 storeService store.KVStoreService 89 cdc codec.BinaryCodec 90 permAddrs map[string]types.PermissionsForAddress 91 bech32Prefix string 92 93 // The prototypical AccountI constructor. 94 proto func() sdk.AccountI 95 96 // the address capable of executing a MsgUpdateParams message. Typically, this 97 // should be the x/gov module account. 98 authority string 99 100 // State 101 Schema collections.Schema 102 Params collections.Item[types.Params] 103 AccountNumber collections.Sequence 104 Accounts *collections.IndexedMap[sdk.AccAddress, sdk.AccountI, AccountsIndexes] 105 } 106 107 var _ AccountKeeperI = &AccountKeeper{} 108 109 // NewAccountKeeper returns a new AccountKeeperI that uses go-amino to 110 // (binary) encode and decode concrete sdk.Accounts. 111 // `maccPerms` is a map that takes accounts' addresses as keys, and their respective permissions as values. This map is used to construct 112 // types.PermissionsForAddress and is used in keeper.ValidatePermissions. Permissions are plain strings, 113 // and don't have to fit into any predefined structure. This auth module does not use account permissions internally, though other modules 114 // may use auth.Keeper to access the accounts permissions map. 115 func NewAccountKeeper( 116 cdc codec.BinaryCodec, storeService store.KVStoreService, proto func() sdk.AccountI, 117 maccPerms map[string][]string, ac address.Codec, bech32Prefix, authority string, 118 ) AccountKeeper { 119 permAddrs := make(map[string]types.PermissionsForAddress) 120 for name, perms := range maccPerms { 121 permAddrs[name] = types.NewPermissionsForAddress(name, perms) 122 } 123 124 sb := collections.NewSchemaBuilder(storeService) 125 126 ak := AccountKeeper{ 127 addressCodec: ac, 128 bech32Prefix: bech32Prefix, 129 storeService: storeService, 130 proto: proto, 131 cdc: cdc, 132 permAddrs: permAddrs, 133 authority: authority, 134 Params: collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[types.Params](cdc)), 135 AccountNumber: collections.NewSequence(sb, types.GlobalAccountNumberKey, "account_number"), 136 Accounts: collections.NewIndexedMap(sb, types.AddressStoreKeyPrefix, "accounts", sdk.AccAddressKey, codec.CollInterfaceValue[sdk.AccountI](cdc), NewAccountIndexes(sb)), 137 } 138 schema, err := sb.Build() 139 if err != nil { 140 panic(err) 141 } 142 ak.Schema = schema 143 return ak 144 } 145 146 // GetAuthority returns the x/auth module's authority. 147 func (ak AccountKeeper) GetAuthority() string { 148 return ak.authority 149 } 150 151 // AddressCodec returns the x/auth account address codec. 152 // x/auth is tied to bech32 encoded user accounts 153 func (ak AccountKeeper) AddressCodec() address.Codec { 154 return ak.addressCodec 155 } 156 157 // Logger returns a module-specific logger. 158 func (ak AccountKeeper) Logger(ctx context.Context) log.Logger { 159 return sdk.UnwrapSDKContext(ctx).Logger().With("module", "x/"+types.ModuleName) 160 } 161 162 // GetPubKey Returns the PubKey of the account at address 163 func (ak AccountKeeper) GetPubKey(ctx context.Context, addr sdk.AccAddress) (cryptotypes.PubKey, error) { 164 acc := ak.GetAccount(ctx, addr) 165 if acc == nil { 166 return nil, errorsmod.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr) 167 } 168 169 return acc.GetPubKey(), nil 170 } 171 172 // GetSequence Returns the Sequence of the account at address 173 func (ak AccountKeeper) GetSequence(ctx context.Context, addr sdk.AccAddress) (uint64, error) { 174 acc := ak.GetAccount(ctx, addr) 175 if acc == nil { 176 return 0, errorsmod.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr) 177 } 178 179 return acc.GetSequence(), nil 180 } 181 182 // NextAccountNumber returns and increments the global account number counter. 183 // If the global account number is not set, it initializes it with value 0. 184 func (ak AccountKeeper) NextAccountNumber(ctx context.Context) uint64 { 185 n, err := ak.AccountNumber.Next(ctx) 186 if err != nil { 187 panic(err) 188 } 189 return n 190 } 191 192 // GetModulePermissions fetches per-module account permissions. 193 func (ak AccountKeeper) GetModulePermissions() map[string]types.PermissionsForAddress { 194 return ak.permAddrs 195 } 196 197 // ValidatePermissions validates that the module account has been granted 198 // permissions within its set of allowed permissions. 199 func (ak AccountKeeper) ValidatePermissions(macc sdk.ModuleAccountI) error { 200 permAddr := ak.permAddrs[macc.GetName()] 201 for _, perm := range macc.GetPermissions() { 202 if !permAddr.HasPermission(perm) { 203 return fmt.Errorf("invalid module permission %s", perm) 204 } 205 } 206 207 return nil 208 } 209 210 // GetModuleAddress returns an address based on the module name 211 func (ak AccountKeeper) GetModuleAddress(moduleName string) sdk.AccAddress { 212 permAddr, ok := ak.permAddrs[moduleName] 213 if !ok { 214 return nil 215 } 216 217 return permAddr.GetAddress() 218 } 219 220 // GetModuleAddressAndPermissions returns an address and permissions based on the module name 221 func (ak AccountKeeper) GetModuleAddressAndPermissions(moduleName string) (addr sdk.AccAddress, permissions []string) { 222 permAddr, ok := ak.permAddrs[moduleName] 223 if !ok { 224 return addr, permissions 225 } 226 227 return permAddr.GetAddress(), permAddr.GetPermissions() 228 } 229 230 // GetModuleAccountAndPermissions gets the module account from the auth account store and its 231 // registered permissions 232 func (ak AccountKeeper) GetModuleAccountAndPermissions(ctx context.Context, moduleName string) (sdk.ModuleAccountI, []string) { 233 addr, perms := ak.GetModuleAddressAndPermissions(moduleName) 234 if addr == nil { 235 return nil, []string{} 236 } 237 238 acc := ak.GetAccount(ctx, addr) 239 if acc != nil { 240 macc, ok := acc.(sdk.ModuleAccountI) 241 if !ok { 242 panic("account is not a module account") 243 } 244 return macc, perms 245 } 246 247 // create a new module account 248 macc := types.NewEmptyModuleAccount(moduleName, perms...) 249 maccI := (ak.NewAccount(ctx, macc)).(sdk.ModuleAccountI) // set the account number 250 ak.SetModuleAccount(ctx, maccI) 251 252 return maccI, perms 253 } 254 255 // GetModuleAccount gets the module account from the auth account store, if the account does not 256 // exist in the AccountKeeper, then it is created. 257 func (ak AccountKeeper) GetModuleAccount(ctx context.Context, moduleName string) sdk.ModuleAccountI { 258 acc, _ := ak.GetModuleAccountAndPermissions(ctx, moduleName) 259 return acc 260 } 261 262 // SetModuleAccount sets the module account to the auth account store 263 func (ak AccountKeeper) SetModuleAccount(ctx context.Context, macc sdk.ModuleAccountI) { 264 ak.SetAccount(ctx, macc) 265 } 266 267 // add getter for bech32Prefix 268 func (ak AccountKeeper) getBech32Prefix() (string, error) { 269 return ak.bech32Prefix, nil 270 } 271 272 // GetParams gets the auth module's parameters. 273 func (ak AccountKeeper) GetParams(ctx context.Context) (params types.Params) { 274 params, err := ak.Params.Get(ctx) 275 if err != nil && !errors.Is(err, collections.ErrNotFound) { 276 panic(err) 277 } 278 return params 279 }