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  }