github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/capability/keeper/keeper.go (about)

     1  package keeper
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	tmtypes "github.com/fibonacci-chain/fbc/libs/tendermint/types"
     8  
     9  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec"
    10  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/prefix"
    11  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    12  	sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
    13  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/capability/types"
    14  	"github.com/fibonacci-chain/fbc/libs/tendermint/libs/log"
    15  )
    16  
    17  // initialized is a global variable used by GetCapability to ensure that the memory store
    18  // and capability map are correctly populated. A state-synced node may copy over all the persistent
    19  // state and start running the application without having the in-memory state required for x/capability.
    20  // Thus, we must initialized the memory stores on-the-fly during tx execution once the first GetCapability
    21  // is called.
    22  // This is a temporary fix and should be replaced by a more robust solution in the next breaking release.
    23  var initialized = false
    24  
    25  type (
    26  	// Keeper defines the capability module's keeper. It is responsible for provisioning,
    27  	// tracking, and authenticating capabilities at runtime. During application
    28  	// initialization, the keeper can be hooked up to modules through unique function
    29  	// references so that it can identify the calling module when later invoked.
    30  	//
    31  	// When the initial state is loaded from disk, the keeper allows the ability to
    32  	// create new capability keys for all previously allocated capability identifiers
    33  	// (allocated during execution of past transactions and assigned to particular modes),
    34  	// and keep them in a memory-only store while the chain is running.
    35  	//
    36  	// The keeper allows the ability to create scoped sub-keepers which are tied to
    37  	// a single specific module.
    38  	Keeper struct {
    39  		cdc           *codec.Codec
    40  		storeKey      sdk.StoreKey
    41  		memKey        sdk.StoreKey
    42  		capMap        map[uint64]*types.Capability
    43  		scopedModules map[string]struct{}
    44  		sealed        bool
    45  	}
    46  
    47  	// ScopedKeeper defines a scoped sub-keeper which is tied to a single specific
    48  	// module provisioned by the capability keeper. Scoped keepers must be created
    49  	// at application initialization and passed to modules, which can then use them
    50  	// to claim capabilities they receive and retrieve capabilities which they own
    51  	// by name, in addition to creating new capabilities & authenticating capabilities
    52  	// passed by other modules.
    53  	ScopedKeeper struct {
    54  		cdc      *codec.Codec
    55  		storeKey sdk.StoreKey
    56  		memKey   sdk.StoreKey
    57  		capMap   map[uint64]*types.Capability
    58  		module   string
    59  	}
    60  )
    61  
    62  // NewKeeper constructs a new CapabilityKeeper instance and initializes maps
    63  // for capability map and scopedModules map.
    64  func NewKeeper(cdc *codec.CodecProxy, storeKey, memKey sdk.StoreKey) *Keeper {
    65  	return &Keeper{
    66  		cdc:           cdc.GetCdc(),
    67  		storeKey:      storeKey,
    68  		memKey:        memKey,
    69  		capMap:        make(map[uint64]*types.Capability),
    70  		scopedModules: make(map[string]struct{}),
    71  		sealed:        false,
    72  	}
    73  }
    74  
    75  // ScopeToModule attempts to create and return a ScopedKeeper for a given module
    76  // by name. It will panic if the keeper is already sealed or if the module name
    77  // already has a ScopedKeeper.
    78  func (k *Keeper) ScopeToModule(moduleName string) ScopedKeeper {
    79  	if k.sealed {
    80  		panic("cannot scope to module via a sealed capability keeper")
    81  	}
    82  	if strings.TrimSpace(moduleName) == "" {
    83  		panic("cannot scope to an empty module name")
    84  	}
    85  
    86  	if _, ok := k.scopedModules[moduleName]; ok {
    87  		panic(fmt.Sprintf("cannot create multiple scoped keepers for the same module name: %s", moduleName))
    88  	}
    89  
    90  	k.scopedModules[moduleName] = struct{}{}
    91  
    92  	return ScopedKeeper{
    93  		cdc:      k.cdc,
    94  		storeKey: k.storeKey,
    95  		memKey:   k.memKey,
    96  		capMap:   k.capMap,
    97  		module:   moduleName,
    98  	}
    99  }
   100  
   101  // InitializeAndSeal loads all capabilities from the persistent KVStore into the
   102  // in-memory store and seals the keeper to prevent further modules from creating
   103  // a scoped keeper. InitializeAndSeal must be called once after the application
   104  // state is loaded.
   105  func (k *Keeper) InitializeAndSeal(ctx sdk.Context) {
   106  	if k.sealed {
   107  		panic("cannot initialize and seal an already sealed capability keeper")
   108  	}
   109  
   110  	memStore := ctx.KVStore(k.memKey)
   111  	memStoreType := memStore.GetStoreType()
   112  
   113  	if memStoreType != sdk.StoreTypeMemory {
   114  		panic(fmt.Sprintf("invalid memory store type; got %d, expected: %d", memStoreType, sdk.StoreTypeMemory))
   115  	}
   116  
   117  	prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixIndexCapability)
   118  	iterator := sdk.KVStorePrefixIterator(prefixStore, nil)
   119  
   120  	// initialize the in-memory store for all persisted capabilities
   121  	defer iterator.Close()
   122  
   123  	for ; iterator.Valid(); iterator.Next() {
   124  		index := types.IndexFromKey(iterator.Key())
   125  
   126  		var capOwners types.CapabilityOwners
   127  
   128  		k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &capOwners)
   129  		k.InitializeCapability(ctx, index, capOwners)
   130  	}
   131  
   132  	k.sealed = true
   133  }
   134  
   135  // InitializeIndex sets the index to one (or greater) in InitChain according
   136  // to the GenesisState. It must only be called once.
   137  // It will panic if the provided index is 0, or if the index is already set.
   138  func (k Keeper) InitializeIndex(ctx sdk.Context, index uint64) error {
   139  	if index == 0 {
   140  		panic("SetIndex requires index > 0")
   141  	}
   142  	latest := k.GetLatestIndex(ctx)
   143  	if latest > 0 {
   144  		panic("SetIndex requires index to not be set")
   145  	}
   146  
   147  	// set the global index to the passed index
   148  	store := ctx.KVStore(k.storeKey)
   149  	store.Set(types.KeyIndex, types.IndexToKey(index))
   150  	return nil
   151  }
   152  
   153  // GetLatestIndex returns the latest index of the CapabilityKeeper
   154  func (k Keeper) GetLatestIndex(ctx sdk.Context) uint64 {
   155  	store := ctx.KVStore(k.storeKey)
   156  	return types.IndexFromKey(store.Get(types.KeyIndex))
   157  }
   158  
   159  // SetOwners set the capability owners to the store
   160  func (k Keeper) SetOwners(ctx sdk.Context, index uint64, owners types.CapabilityOwners) {
   161  	prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixIndexCapability)
   162  	indexKey := types.IndexToKey(index)
   163  
   164  	// set owners in persistent store
   165  	prefixStore.Set(indexKey, k.cdc.MustMarshalBinaryBare(&owners))
   166  }
   167  
   168  // GetOwners returns the capability owners with a given index.
   169  func (k Keeper) GetOwners(ctx sdk.Context, index uint64) (types.CapabilityOwners, bool) {
   170  	prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixIndexCapability)
   171  	indexKey := types.IndexToKey(index)
   172  
   173  	// get owners for index from persistent store
   174  	ownerBytes := prefixStore.Get(indexKey)
   175  	if ownerBytes == nil {
   176  		return types.CapabilityOwners{}, false
   177  	}
   178  	var owners types.CapabilityOwners
   179  	k.cdc.MustUnmarshalBinaryBare(ownerBytes, &owners)
   180  	return owners, true
   181  }
   182  
   183  // InitializeCapability takes in an index and an owners array. It creates the capability in memory
   184  // and sets the fwd and reverse keys for each owner in the memstore.
   185  // It is used during initialization from genesis.
   186  func (k Keeper) InitializeCapability(ctx sdk.Context, index uint64, owners types.CapabilityOwners) {
   187  
   188  	memStore := ctx.KVStore(k.memKey)
   189  
   190  	cap := types.NewCapability(index)
   191  	for _, owner := range owners.Owners {
   192  		// Set the forward mapping between the module and capability tuple and the
   193  		// capability name in the memKVStore
   194  		memStore.Set(types.FwdCapabilityKey(owner.Module, cap), []byte(owner.Name))
   195  
   196  		// Set the reverse mapping between the module and capability name and the
   197  		// index in the in-memory store. Since marshalling and unmarshalling into a store
   198  		// will change memory address of capability, we simply store index as value here
   199  		// and retrieve the in-memory pointer to the capability from our map
   200  		memStore.Set(types.RevCapabilityKey(owner.Module, owner.Name), sdk.Uint64ToBigEndian(index))
   201  
   202  		// Set the mapping from index from index to in-memory capability in the go map
   203  		k.capMap[index] = cap
   204  	}
   205  
   206  }
   207  
   208  // NewCapability attempts to create a new capability with a given name. If the
   209  // capability already exists in the in-memory store, an error will be returned.
   210  // Otherwise, a new capability is created with the current global unique index.
   211  // The newly created capability has the scoped module name and capability name
   212  // tuple set as the initial owner. Finally, the global index is incremented along
   213  // with forward and reverse indexes set in the in-memory store.
   214  //
   215  // Note, namespacing is completely local, which is safe since records are prefixed
   216  // with the module name and no two ScopedKeeper can have the same module name.
   217  func (sk ScopedKeeper) NewCapability(ctx sdk.Context, name string) (*types.Capability, error) {
   218  	if strings.TrimSpace(name) == "" {
   219  		return nil, sdkerrors.Wrap(types.ErrInvalidCapabilityName, "capability name cannot be empty")
   220  	}
   221  	store := ctx.KVStore(sk.storeKey)
   222  
   223  	if _, ok := sk.GetCapability(ctx, name); ok {
   224  		return nil, sdkerrors.Wrapf(types.ErrCapabilityTaken, fmt.Sprintf("module: %s, name: %s", sk.module, name))
   225  	}
   226  
   227  	// create new capability with the current global index
   228  	index := types.IndexFromKey(store.Get(types.KeyIndex))
   229  	cap := types.NewCapability(index)
   230  
   231  	// update capability owner set
   232  	if err := sk.addOwner(ctx, cap, name); err != nil {
   233  		return nil, err
   234  	}
   235  
   236  	// increment global index
   237  	store.Set(types.KeyIndex, types.IndexToKey(index+1))
   238  
   239  	memStore := ctx.KVStore(sk.memKey)
   240  
   241  	// Set the forward mapping between the module and capability tuple and the
   242  	// capability name in the memKVStore
   243  	memStore.Set(types.FwdCapabilityKey(sk.module, cap), []byte(name))
   244  
   245  	// Set the reverse mapping between the module and capability name and the
   246  	// index in the in-memory store. Since marshalling and unmarshalling into a store
   247  	// will change memory address of capability, we simply store index as value here
   248  	// and retrieve the in-memory pointer to the capability from our map
   249  	memStore.Set(types.RevCapabilityKey(sk.module, name), sdk.Uint64ToBigEndian(index))
   250  
   251  	// Set the mapping from index from index to in-memory capability in the go map
   252  	sk.capMap[index] = cap
   253  
   254  	logger(ctx).Info("created new capability", "module", sk.module, "name", name)
   255  
   256  	return cap, nil
   257  }
   258  
   259  // AuthenticateCapability attempts to authenticate a given capability and name
   260  // from a caller. It allows for a caller to check that a capability does in fact
   261  // correspond to a particular name. The scoped keeper will lookup the capability
   262  // from the internal in-memory store and check against the provided name. It returns
   263  // true upon success and false upon failure.
   264  //
   265  // Note, the capability's forward mapping is indexed by a string which should
   266  // contain its unique memory reference.
   267  func (sk ScopedKeeper) AuthenticateCapability(ctx sdk.Context, cap *types.Capability, name string) bool {
   268  	if strings.TrimSpace(name) == "" || cap == nil {
   269  		return false
   270  	}
   271  	return sk.GetCapabilityName(ctx, cap) == name
   272  }
   273  
   274  // ClaimCapability attempts to claim a given Capability. The provided name and
   275  // the scoped module's name tuple are treated as the owner. It will attempt
   276  // to add the owner to the persistent set of capability owners for the capability
   277  // index. If the owner already exists, it will return an error. Otherwise, it will
   278  // also set a forward and reverse index for the capability and capability name.
   279  func (sk ScopedKeeper) ClaimCapability(ctx sdk.Context, cap *types.Capability, name string) error {
   280  	if cap == nil {
   281  		return sdkerrors.Wrap(types.ErrNilCapability, "cannot claim nil capability")
   282  	}
   283  	if strings.TrimSpace(name) == "" {
   284  		return sdkerrors.Wrap(types.ErrInvalidCapabilityName, "capability name cannot be empty")
   285  	}
   286  	// update capability owner set
   287  	if err := sk.addOwner(ctx, cap, name); err != nil {
   288  		return err
   289  	}
   290  
   291  	memStore := ctx.KVStore(sk.memKey)
   292  
   293  	// Set the forward mapping between the module and capability tuple and the
   294  	// capability name in the memKVStore
   295  	memStore.Set(types.FwdCapabilityKey(sk.module, cap), []byte(name))
   296  
   297  	// Set the reverse mapping between the module and capability name and the
   298  	// index in the in-memory store. Since marshalling and unmarshalling into a store
   299  	// will change memory address of capability, we simply store index as value here
   300  	// and retrieve the in-memory pointer to the capability from our map
   301  	memStore.Set(types.RevCapabilityKey(sk.module, name), sdk.Uint64ToBigEndian(cap.GetIndex()))
   302  
   303  	logger(ctx).Info("claimed capability", "module", sk.module, "name", name, "capability", cap.GetIndex())
   304  
   305  	return nil
   306  }
   307  
   308  // ReleaseCapability allows a scoped module to release a capability which it had
   309  // previously claimed or created. After releasing the capability, if no more
   310  // owners exist, the capability will be globally removed.
   311  func (sk ScopedKeeper) ReleaseCapability(ctx sdk.Context, cap *types.Capability) error {
   312  	if cap == nil {
   313  		return sdkerrors.Wrap(types.ErrNilCapability, "cannot release nil capability")
   314  	}
   315  	name := sk.GetCapabilityName(ctx, cap)
   316  	if len(name) == 0 {
   317  		return sdkerrors.Wrap(types.ErrCapabilityNotOwned, sk.module)
   318  	}
   319  
   320  	memStore := ctx.KVStore(sk.memKey)
   321  	name1 := types.FwdCapabilityKey(sk.module, cap)
   322  	name2 := types.RevCapabilityKey(sk.module, name)
   323  	logger(ctx).Info("deleteCap", "name", name, "name1", name1, "name2", name2)
   324  	// Delete the forward mapping between the module and capability tuple and the
   325  	// capability name in the memKVStore
   326  	memStore.Delete(types.FwdCapabilityKey(sk.module, cap))
   327  
   328  	// Delete the reverse mapping between the module and capability name and the
   329  	// index in the in-memory store.
   330  	memStore.Delete(types.RevCapabilityKey(sk.module, name))
   331  
   332  	// remove owner
   333  	capOwners := sk.getOwners(ctx, cap)
   334  	capOwners.Remove(types.NewOwner(sk.module, name))
   335  
   336  	prefixStore := prefix.NewStore(ctx.KVStore(sk.storeKey), types.KeyPrefixIndexCapability)
   337  	indexKey := types.IndexToKey(cap.GetIndex())
   338  
   339  	if len(capOwners.Owners) == 0 {
   340  		// remove capability owner set
   341  		prefixStore.Delete(indexKey)
   342  		// since no one owns capability, we can delete capability from map
   343  		delete(sk.capMap, cap.GetIndex())
   344  	} else {
   345  		// update capability owner set
   346  		prefixStore.Set(indexKey, sk.cdc.MustMarshalBinaryBare(capOwners))
   347  	}
   348  
   349  	return nil
   350  }
   351  
   352  // GetCapability allows a module to fetch a capability which it previously claimed
   353  // by name. The module is not allowed to retrieve capabilities which it does not
   354  // own.
   355  func (sk ScopedKeeper) GetCapability(ctx sdk.Context, name string) (*types.Capability, bool) {
   356  	//// Create a keeper that will set all in-memory mappings correctly into memstore and capmap if scoped keeper is not initialized yet.
   357  	//// This ensures that the in-memory mappings are correctly filled in, in case this is a state-synced node.
   358  	//// This is a temporary non-breaking fix, a future PR should store the reverse mapping in the persistent store and reconstruct forward mapping and capmap on the fly.
   359  	//if !initialized {
   360  	//	// create context with infinite gas meter to avoid app state mismatch.
   361  	//	initCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
   362  	//	k := Keeper{
   363  	//		cdc:      sk.cdc,
   364  	//		storeKey: sk.storeKey,
   365  	//		memKey:   sk.memKey,
   366  	//		capMap:   sk.capMap,
   367  	//	}
   368  	//	k.InitializeAndSeal(initCtx)
   369  	//	initialized = true
   370  	//}
   371  	//
   372  	//if strings.TrimSpace(name) == "" {
   373  	//	return nil, false
   374  	//}
   375  	//memStore := ctx.KVStore(sk.memKey)
   376  	//
   377  	//key := types.RevCapabilityKey(sk.module, name)
   378  	//indexBytes := memStore.Get(key)
   379  	//index := sdk.BigEndianToUint64(indexBytes)
   380  	//
   381  	//if len(indexBytes) == 0 {
   382  	//	// If a tx failed and NewCapability got reverted, it is possible
   383  	//	// to still have the capability in the go map since changes to
   384  	//	// go map do not automatically get reverted on tx failure,
   385  	//	// so we delete here to remove unnecessary values in map
   386  	//	// TODO: Delete index correctly from capMap by storing some reverse lookup
   387  	//	// in-memory map. Issue: https://github.com/cosmos/cosmos-sdk/issues/7805
   388  	//
   389  	//	return nil, false
   390  	//}
   391  
   392  	//cap := sk.capMap[index]
   393  	//if cap == nil {
   394  	//	panic("capability found in memstore is missing from map")
   395  	//}
   396  	//
   397  	//return cap, true
   398  
   399  	if strings.TrimSpace(name) == "" {
   400  		return nil, false
   401  	}
   402  	memStore := ctx.KVStore(sk.memKey)
   403  
   404  	key := types.RevCapabilityKey(sk.module, name)
   405  	indexBytes := memStore.Get(key)
   406  	index := sdk.BigEndianToUint64(indexBytes)
   407  
   408  	if len(indexBytes) == 0 {
   409  		// If a tx failed and NewCapability got reverted, it is possible
   410  		// to still have the capability in the go map since changes to
   411  		// go map do not automatically get reverted on tx failure,
   412  		// so we delete here to remove unnecessary values in map
   413  		// TODO: Delete index correctly from capMap by storing some reverse lookup
   414  		// in-memory map. Issue: https://github.com/cosmos/cosmos-sdk/issues/7805
   415  
   416  		return nil, false
   417  	}
   418  
   419  	cap := sk.capMap[index]
   420  	if cap == nil {
   421  		panic("capability found in memstore is missing from map")
   422  	}
   423  
   424  	return cap, true
   425  }
   426  
   427  // GetCapabilityName allows a module to retrieve the name under which it stored a given
   428  // capability given the capability
   429  func (sk ScopedKeeper) GetCapabilityName(ctx sdk.Context, cap *types.Capability) string {
   430  	if cap == nil {
   431  		return ""
   432  	}
   433  	memStore := ctx.KVStore(sk.memKey)
   434  
   435  	return string(memStore.Get(types.FwdCapabilityKey(sk.module, cap)))
   436  }
   437  
   438  // GetOwners all the Owners that own the capability associated with the name this ScopedKeeper uses
   439  // to refer to the capability
   440  func (sk ScopedKeeper) GetOwners(ctx sdk.Context, name string) (*types.CapabilityOwners, bool) {
   441  	if strings.TrimSpace(name) == "" {
   442  		return nil, false
   443  	}
   444  	cap, ok := sk.GetCapability(ctx, name)
   445  	if !ok {
   446  		return nil, false
   447  	}
   448  
   449  	prefixStore := prefix.NewStore(ctx.KVStore(sk.storeKey), types.KeyPrefixIndexCapability)
   450  	indexKey := types.IndexToKey(cap.GetIndex())
   451  
   452  	var capOwners types.CapabilityOwners
   453  
   454  	bz := prefixStore.Get(indexKey)
   455  	if len(bz) == 0 {
   456  		return nil, false
   457  	}
   458  
   459  	sk.cdc.MustUnmarshalBinaryBare(bz, &capOwners)
   460  
   461  	return &capOwners, true
   462  }
   463  
   464  // LookupModules returns all the module owners for a given capability
   465  // as a string array and the capability itself.
   466  // The method returns an error if either the capability or the owners cannot be
   467  // retreived from the memstore.
   468  func (sk ScopedKeeper) LookupModules(ctx sdk.Context, name string) ([]string, *types.Capability, error) {
   469  	if strings.TrimSpace(name) == "" {
   470  		return nil, nil, sdkerrors.Wrap(types.ErrInvalidCapabilityName, "cannot lookup modules with empty capability name")
   471  	}
   472  	cap, ok := sk.GetCapability(ctx, name)
   473  	if !ok {
   474  		return nil, nil, sdkerrors.Wrap(types.ErrCapabilityNotFound, name)
   475  	}
   476  
   477  	capOwners, ok := sk.GetOwners(ctx, name)
   478  	if !ok {
   479  		return nil, nil, sdkerrors.Wrap(types.ErrCapabilityOwnersNotFound, name)
   480  	}
   481  
   482  	mods := make([]string, len(capOwners.Owners))
   483  	for i, co := range capOwners.Owners {
   484  		mods[i] = co.Module
   485  	}
   486  
   487  	return mods, cap, nil
   488  }
   489  
   490  func (sk ScopedKeeper) addOwner(ctx sdk.Context, cap *types.Capability, name string) error {
   491  	prefixStore := prefix.NewStore(ctx.KVStore(sk.storeKey), types.KeyPrefixIndexCapability)
   492  	indexKey := types.IndexToKey(cap.GetIndex())
   493  
   494  	capOwners := sk.getOwners(ctx, cap)
   495  
   496  	if err := capOwners.Set(types.NewOwner(sk.module, name)); err != nil {
   497  		return err
   498  	}
   499  
   500  	// update capability owner set
   501  	prefixStore.Set(indexKey, sk.cdc.MustMarshalBinaryBare(capOwners))
   502  
   503  	return nil
   504  }
   505  
   506  func (sk ScopedKeeper) getOwners(ctx sdk.Context, cap *types.Capability) *types.CapabilityOwners {
   507  	prefixStore := prefix.NewStore(ctx.KVStore(sk.storeKey), types.KeyPrefixIndexCapability)
   508  	indexKey := types.IndexToKey(cap.GetIndex())
   509  
   510  	bz := prefixStore.Get(indexKey)
   511  
   512  	if len(bz) == 0 {
   513  		return types.NewCapabilityOwners()
   514  	}
   515  
   516  	var capOwners types.CapabilityOwners
   517  	sk.cdc.MustUnmarshalBinaryBare(bz, &capOwners)
   518  	return &capOwners
   519  }
   520  
   521  func (k *Keeper) InitMemStore(ctx sdk.Context) {
   522  	memStore := ctx.KVStore(k.memKey)
   523  	memStoreType := memStore.GetStoreType()
   524  	if memStoreType != sdk.StoreTypeMemory {
   525  		panic(fmt.Sprintf("invalid memory store type; got %d, expected: %d", memStoreType, sdk.StoreTypeMemory))
   526  	}
   527  
   528  	// create context with no block gas meter to ensure we do not consume gas during local initialization logic.
   529  	noGasCtx := ctx
   530  	noGasCtx.SetBlockGasMeter(sdk.NewInfiniteGasMeter())
   531  
   532  	// check if memory store has not been initialized yet by checking if initialized flag is nil.
   533  	if !k.IsInitialized(noGasCtx) || tmtypes.DownloadDelta {
   534  		prefixStore := prefix.NewStore(noGasCtx.KVStore(k.storeKey), types.KeyPrefixIndexCapability)
   535  		iterator := sdk.KVStorePrefixIterator(prefixStore, nil)
   536  
   537  		// initialize the in-memory store for all persisted capabilities
   538  		defer iterator.Close()
   539  
   540  		for ; iterator.Valid(); iterator.Next() {
   541  			kk := iterator.Key()
   542  			index := types.IndexFromKey(kk)
   543  			var capOwners types.CapabilityOwners
   544  
   545  			k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &capOwners)
   546  			k.InitializeCapability(noGasCtx, index, capOwners)
   547  		}
   548  
   549  		// set the initialized flag so we don't rerun initialization logic
   550  		memStore := noGasCtx.KVStore(k.memKey)
   551  		memStore.Set(types.KeyMemInitialized, []byte{1})
   552  	}
   553  }
   554  
   555  func (k *Keeper) IsInitialized(ctx sdk.Context) bool {
   556  	memStore := ctx.KVStore(k.memKey)
   557  	return memStore.Get(types.KeyMemInitialized) != nil
   558  }
   559  
   560  func logger(ctx sdk.Context) log.Logger {
   561  	return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
   562  }