github.com/Finschia/finschia-sdk@v0.49.1/x/auth/keeper/keeper.go (about) 1 package keeper 2 3 import ( 4 "fmt" 5 6 "github.com/Finschia/ostracon/libs/log" 7 gogotypes "github.com/gogo/protobuf/types" 8 9 "github.com/Finschia/finschia-sdk/codec" 10 cryptotypes "github.com/Finschia/finschia-sdk/crypto/types" 11 sdk "github.com/Finschia/finschia-sdk/types" 12 sdkerrors "github.com/Finschia/finschia-sdk/types/errors" 13 "github.com/Finschia/finschia-sdk/x/auth/types" 14 paramtypes "github.com/Finschia/finschia-sdk/x/params/types" 15 ) 16 17 // AccountKeeperI is the interface contract that x/auth's keeper implements. 18 type AccountKeeperI interface { 19 // Return a new account with the next account number and the specified address. Does not save the new account to the store. 20 NewAccountWithAddress(sdk.Context, sdk.AccAddress) types.AccountI 21 22 // Return a new account with the next account number. Does not save the new account to the store. 23 NewAccount(sdk.Context, types.AccountI) types.AccountI 24 25 // Check if an account exists in the store. 26 HasAccount(sdk.Context, sdk.AccAddress) bool 27 28 // Retrieve an account from the store. 29 GetAccount(sdk.Context, sdk.AccAddress) types.AccountI 30 31 // Set an account in the store. 32 SetAccount(sdk.Context, types.AccountI) 33 34 // Remove an account from the store. 35 RemoveAccount(sdk.Context, types.AccountI) 36 37 // Iterate over all accounts, calling the provided function. Stop iteration when it returns true. 38 IterateAccounts(sdk.Context, func(types.AccountI) bool) 39 40 // Fetch the public key of an account at a specified address 41 GetPubKey(sdk.Context, sdk.AccAddress) (cryptotypes.PubKey, error) 42 43 // Fetch the sequence of an account at a specified address. 44 GetSequence(sdk.Context, sdk.AccAddress) (uint64, error) 45 46 // Fetch the next account number, and increment the internal counter. 47 GetNextAccountNumber(sdk.Context) uint64 48 } 49 50 // AccountKeeper encodes/decodes accounts using the go-amino (binary) 51 // encoding/decoding library. 52 type AccountKeeper struct { 53 key sdk.StoreKey 54 cdc codec.BinaryCodec 55 paramSubspace paramtypes.Subspace 56 permAddrs map[string]types.PermissionsForAddress 57 58 // The prototypical AccountI constructor. 59 proto func() types.AccountI 60 } 61 62 var _ AccountKeeperI = &AccountKeeper{} 63 64 // NewAccountKeeper returns a new AccountKeeperI that uses go-amino to 65 // (binary) encode and decode concrete sdk.Accounts. 66 // `maccPerms` is a map that takes accounts' addresses as keys, and their respective permissions as values. This map is used to construct 67 // types.PermissionsForAddress and is used in keeper.ValidatePermissions. Permissions are plain strings, 68 // and don't have to fit into any predefined structure. This auth module does not use account permissions internally, though other modules 69 // may use auth.Keeper to access the accounts permissions map. 70 func NewAccountKeeper( 71 cdc codec.BinaryCodec, key sdk.StoreKey, paramstore paramtypes.Subspace, proto func() types.AccountI, 72 maccPerms map[string][]string, 73 ) AccountKeeper { 74 // set KeyTable if it has not already been set 75 if !paramstore.HasKeyTable() { 76 paramstore = paramstore.WithKeyTable(types.ParamKeyTable()) 77 } 78 79 permAddrs := make(map[string]types.PermissionsForAddress) 80 for name, perms := range maccPerms { 81 permAddrs[name] = types.NewPermissionsForAddress(name, perms) 82 } 83 84 return AccountKeeper{ 85 key: key, 86 proto: proto, 87 cdc: cdc, 88 paramSubspace: paramstore, 89 permAddrs: permAddrs, 90 } 91 } 92 93 // Logger returns a module-specific logger. 94 func (ak AccountKeeper) Logger(ctx sdk.Context) log.Logger { 95 return ctx.Logger().With("module", "x/"+types.ModuleName) 96 } 97 98 // GetPubKey Returns the PubKey of the account at address 99 func (ak AccountKeeper) GetPubKey(ctx sdk.Context, addr sdk.AccAddress) (cryptotypes.PubKey, error) { 100 acc := ak.GetAccount(ctx, addr) 101 if acc == nil { 102 return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr) 103 } 104 105 return acc.GetPubKey(), nil 106 } 107 108 // GetSequence Returns the Sequence of the account at address 109 func (ak AccountKeeper) GetSequence(ctx sdk.Context, addr sdk.AccAddress) (uint64, error) { 110 acc := ak.GetAccount(ctx, addr) 111 if acc == nil { 112 return 0, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr) 113 } 114 115 return acc.GetSequence(), nil 116 } 117 118 // QueryNextAccountNumber returns the global account number counter. 119 // This function queries only the number without incrementing values. 120 // And this is a temporary use function. 121 func (ak AccountKeeper) QueryNextAccountNumber(ctx sdk.Context) uint64 { 122 var accNumber uint64 123 store := ctx.KVStore(ak.key) 124 125 bz := store.Get(types.GlobalAccountNumberKey) 126 if bz == nil { 127 accNumber = 0 128 } else { 129 val := gogotypes.UInt64Value{} 130 131 err := ak.cdc.Unmarshal(bz, &val) 132 if err != nil { 133 panic(err) 134 } 135 136 accNumber = val.GetValue() 137 } 138 139 return accNumber 140 } 141 142 // GetNextAccountNumber returns and increments the global account number counter. 143 // If the global account number is not set, it initializes it with value 0. 144 func (ak AccountKeeper) GetNextAccountNumber(ctx sdk.Context) uint64 { 145 var accNumber uint64 146 store := ctx.KVStore(ak.key) 147 148 bz := store.Get(types.GlobalAccountNumberKey) 149 if bz == nil { 150 // initialize the account numbers 151 accNumber = 0 152 } else { 153 val := gogotypes.UInt64Value{} 154 155 err := ak.cdc.Unmarshal(bz, &val) 156 if err != nil { 157 panic(err) 158 } 159 160 accNumber = val.GetValue() 161 } 162 163 bz = ak.cdc.MustMarshal(&gogotypes.UInt64Value{Value: accNumber + 1}) 164 store.Set(types.GlobalAccountNumberKey, bz) 165 166 return accNumber 167 } 168 169 // ValidatePermissions validates that the module account has been granted 170 // permissions within its set of allowed permissions. 171 func (ak AccountKeeper) ValidatePermissions(macc types.ModuleAccountI) error { 172 permAddr := ak.permAddrs[macc.GetName()] 173 for _, perm := range macc.GetPermissions() { 174 if !permAddr.HasPermission(perm) { 175 return fmt.Errorf("invalid module permission %s", perm) 176 } 177 } 178 179 return nil 180 } 181 182 // GetModuleAddress returns an address based on the module name 183 func (ak AccountKeeper) GetModuleAddress(moduleName string) sdk.AccAddress { 184 permAddr, ok := ak.permAddrs[moduleName] 185 if !ok { 186 return nil 187 } 188 189 return permAddr.GetAddress() 190 } 191 192 // GetModuleAddressAndPermissions returns an address and permissions based on the module name 193 func (ak AccountKeeper) GetModuleAddressAndPermissions(moduleName string) (addr sdk.AccAddress, permissions []string) { 194 permAddr, ok := ak.permAddrs[moduleName] 195 if !ok { 196 return addr, permissions 197 } 198 199 return permAddr.GetAddress(), permAddr.GetPermissions() 200 } 201 202 // GetModuleAccountAndPermissions gets the module account from the auth account store and its 203 // registered permissions 204 func (ak AccountKeeper) GetModuleAccountAndPermissions(ctx sdk.Context, moduleName string) (types.ModuleAccountI, []string) { 205 addr, perms := ak.GetModuleAddressAndPermissions(moduleName) 206 if addr.Empty() { 207 return nil, []string{} 208 } 209 210 acc := ak.GetAccount(ctx, addr) 211 if acc != nil { 212 macc, ok := acc.(types.ModuleAccountI) 213 if !ok { 214 panic("account is not a module account") 215 } 216 return macc, perms 217 } 218 219 // create a new module account 220 macc := types.NewEmptyModuleAccount(moduleName, perms...) 221 maccI := (ak.NewAccount(ctx, macc)).(types.ModuleAccountI) // set the account number 222 ak.SetModuleAccount(ctx, maccI) 223 224 return maccI, perms 225 } 226 227 // GetModuleAccount gets the module account from the auth account store, if the account does not 228 // exist in the AccountKeeper, then it is created. 229 func (ak AccountKeeper) GetModuleAccount(ctx sdk.Context, moduleName string) types.ModuleAccountI { 230 acc, _ := ak.GetModuleAccountAndPermissions(ctx, moduleName) 231 return acc 232 } 233 234 // SetModuleAccount sets the module account to the auth account store 235 func (ak AccountKeeper) SetModuleAccount(ctx sdk.Context, macc types.ModuleAccountI) { 236 ak.SetAccount(ctx, macc) 237 } 238 239 func (ak AccountKeeper) decodeAccount(bz []byte) types.AccountI { 240 acc, err := ak.UnmarshalAccount(bz) 241 if err != nil { 242 panic(err) 243 } 244 245 return acc 246 } 247 248 // MarshalAccount protobuf serializes an Account interface 249 func (ak AccountKeeper) MarshalAccount(accountI types.AccountI) ([]byte, error) { //nolint:interfacer 250 return ak.cdc.MarshalInterface(accountI) 251 } 252 253 // UnmarshalAccount returns an Account interface from raw encoded account 254 // bytes of a Proto-based Account type 255 func (ak AccountKeeper) UnmarshalAccount(bz []byte) (types.AccountI, error) { 256 var acc types.AccountI 257 return acc, ak.cdc.UnmarshalInterface(bz, &acc) 258 } 259 260 // GetCodec return codec.Codec object used by the keeper 261 func (ak AccountKeeper) GetCodec() codec.BinaryCodec { return ak.cdc }