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 }