github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/sdk/auth/keeper.go (about)

     1  package auth
     2  
     3  import (
     4  	"fmt"
     5  	"log/slog"
     6  
     7  	"github.com/gnolang/gno/tm2/pkg/amino"
     8  	"github.com/gnolang/gno/tm2/pkg/crypto"
     9  	"github.com/gnolang/gno/tm2/pkg/sdk"
    10  	"github.com/gnolang/gno/tm2/pkg/std"
    11  	"github.com/gnolang/gno/tm2/pkg/store"
    12  )
    13  
    14  // Concrete implementation of AccountKeeper.
    15  type AccountKeeper struct {
    16  	// The (unexposed) key used to access the store from the Context.
    17  	key store.StoreKey
    18  
    19  	// The prototypical Account constructor.
    20  	proto func() std.Account
    21  }
    22  
    23  // NewAccountKeeper returns a new AccountKeeper that uses go-amino to
    24  // (binary) encode and decode concrete std.Accounts.
    25  func NewAccountKeeper(
    26  	key store.StoreKey, proto func() std.Account,
    27  ) AccountKeeper {
    28  	return AccountKeeper{
    29  		key:   key,
    30  		proto: proto,
    31  	}
    32  }
    33  
    34  // Logger returns a module-specific logger.
    35  func (ak AccountKeeper) Logger(ctx sdk.Context) *slog.Logger {
    36  	return ctx.Logger().With("module", fmt.Sprintf("auth"))
    37  }
    38  
    39  // NewAccountWithAddress implements AccountKeeper.
    40  func (ak AccountKeeper) NewAccountWithAddress(ctx sdk.Context, addr crypto.Address) std.Account {
    41  	acc := ak.proto()
    42  	// acc.SetSequence(0) // start with 0.
    43  	err := acc.SetAddress(addr)
    44  	if err != nil {
    45  		// Handle w/ #870
    46  		panic(err)
    47  	}
    48  	err = acc.SetAccountNumber(ak.GetNextAccountNumber(ctx))
    49  	if err != nil {
    50  		// Handle w/ #870
    51  		panic(err)
    52  	}
    53  	return acc
    54  }
    55  
    56  // GetAccount implements AccountKeeper.
    57  func (ak AccountKeeper) GetAccount(ctx sdk.Context, addr crypto.Address) std.Account {
    58  	stor := ctx.Store(ak.key)
    59  	bz := stor.Get(AddressStoreKey(addr))
    60  	if bz == nil {
    61  		return nil
    62  	}
    63  	acc := ak.decodeAccount(bz)
    64  	return acc
    65  }
    66  
    67  // GetAllAccounts returns all accounts in the AccountKeeper.
    68  func (ak AccountKeeper) GetAllAccounts(ctx sdk.Context) []std.Account {
    69  	accounts := []std.Account{}
    70  	appendAccount := func(acc std.Account) (stop bool) {
    71  		accounts = append(accounts, acc)
    72  		return false
    73  	}
    74  	ak.IterateAccounts(ctx, appendAccount)
    75  	return accounts
    76  }
    77  
    78  // SetAccount implements AccountKeeper.
    79  func (ak AccountKeeper) SetAccount(ctx sdk.Context, acc std.Account) {
    80  	addr := acc.GetAddress()
    81  	stor := ctx.Store(ak.key)
    82  	bz, err := amino.MarshalAny(acc)
    83  	if err != nil {
    84  		panic(err)
    85  	}
    86  	stor.Set(AddressStoreKey(addr), bz)
    87  }
    88  
    89  // RemoveAccount removes an account for the account mapper store.
    90  // NOTE: this will cause supply invariant violation if called
    91  func (ak AccountKeeper) RemoveAccount(ctx sdk.Context, acc std.Account) {
    92  	addr := acc.GetAddress()
    93  	stor := ctx.Store(ak.key)
    94  	stor.Delete(AddressStoreKey(addr))
    95  }
    96  
    97  // IterateAccounts implements AccountKeeper.
    98  func (ak AccountKeeper) IterateAccounts(ctx sdk.Context, process func(std.Account) (stop bool)) {
    99  	stor := ctx.Store(ak.key)
   100  	iter := store.PrefixIterator(stor, []byte(AddressStoreKeyPrefix))
   101  	defer iter.Close()
   102  	for {
   103  		if !iter.Valid() {
   104  			return
   105  		}
   106  		val := iter.Value()
   107  		acc := ak.decodeAccount(val)
   108  		if process(acc) {
   109  			return
   110  		}
   111  		iter.Next()
   112  	}
   113  }
   114  
   115  // GetPubKey Returns the PubKey of the account at address
   116  func (ak AccountKeeper) GetPubKey(ctx sdk.Context, addr crypto.Address) (crypto.PubKey, error) {
   117  	acc := ak.GetAccount(ctx, addr)
   118  	if acc == nil {
   119  		return nil, std.ErrUnknownAddress(fmt.Sprintf("account %s does not exist", addr))
   120  	}
   121  	return acc.GetPubKey(), nil
   122  }
   123  
   124  // GetSequence Returns the Sequence of the account at address
   125  func (ak AccountKeeper) GetSequence(ctx sdk.Context, addr crypto.Address) (uint64, error) {
   126  	acc := ak.GetAccount(ctx, addr)
   127  	if acc == nil {
   128  		return 0, std.ErrUnknownAddress(fmt.Sprintf("account %s does not exist", addr))
   129  	}
   130  	return acc.GetSequence(), nil
   131  }
   132  
   133  // GetNextAccountNumber Returns and increments the global account number counter
   134  func (ak AccountKeeper) GetNextAccountNumber(ctx sdk.Context) uint64 {
   135  	var accNumber uint64
   136  	stor := ctx.Store(ak.key)
   137  	bz := stor.Get([]byte(GlobalAccountNumberKey))
   138  	if bz == nil {
   139  		accNumber = 0 // start with 0.
   140  	} else {
   141  		err := amino.Unmarshal(bz, &accNumber)
   142  		if err != nil {
   143  			panic(err)
   144  		}
   145  	}
   146  
   147  	bz = amino.MustMarshal(accNumber + 1)
   148  	stor.Set([]byte(GlobalAccountNumberKey), bz)
   149  
   150  	return accNumber
   151  }
   152  
   153  // -----------------------------------------------------------------------------
   154  // Misc.
   155  
   156  func (ak AccountKeeper) decodeAccount(bz []byte) (acc std.Account) {
   157  	err := amino.Unmarshal(bz, &acc)
   158  	if err != nil {
   159  		panic(err)
   160  	}
   161  	return
   162  }