github.com/cosmos/cosmos-sdk@v0.50.10/x/bank/migrations/v2/store.go (about)

     1  package v2
     2  
     3  import (
     4  	"cosmossdk.io/core/store"
     5  	"cosmossdk.io/log"
     6  	"cosmossdk.io/math"
     7  	"cosmossdk.io/store/prefix"
     8  	storetypes "cosmossdk.io/store/types"
     9  
    10  	"github.com/cosmos/cosmos-sdk/codec"
    11  	"github.com/cosmos/cosmos-sdk/runtime"
    12  	sdk "github.com/cosmos/cosmos-sdk/types"
    13  	v1auth "github.com/cosmos/cosmos-sdk/x/auth/migrations/v1"
    14  	v1 "github.com/cosmos/cosmos-sdk/x/bank/migrations/v1"
    15  	"github.com/cosmos/cosmos-sdk/x/bank/types"
    16  )
    17  
    18  // migrateSupply migrates the supply to be stored by denom key instead in a
    19  // single blob.
    20  // ref: https://github.com/cosmos/cosmos-sdk/issues/7092
    21  func migrateSupply(store storetypes.KVStore, cdc codec.BinaryCodec) error {
    22  	// Old supply was stored as a single blob under the SupplyKey.
    23  	var oldSupplyI v1.SupplyI
    24  	err := cdc.UnmarshalInterface(store.Get(v1.SupplyKey), &oldSupplyI)
    25  	if err != nil {
    26  		return err
    27  	}
    28  
    29  	// We delete the single key holding the whole blob.
    30  	store.Delete(v1.SupplyKey)
    31  
    32  	if oldSupplyI == nil {
    33  		return nil
    34  	}
    35  
    36  	// We add a new key for each denom
    37  	supplyStore := prefix.NewStore(store, SupplyKey)
    38  
    39  	// We're sure that SupplyI is a Supply struct, there's no other
    40  	// implementation.
    41  	oldSupply := oldSupplyI.(*types.Supply)
    42  	for i := range oldSupply.Total {
    43  		coin := oldSupply.Total[i]
    44  		coinBz, err := coin.Amount.Marshal()
    45  		if err != nil {
    46  			return err
    47  		}
    48  
    49  		supplyStore.Set([]byte(coin.Denom), coinBz)
    50  	}
    51  
    52  	return nil
    53  }
    54  
    55  // migrateBalanceKeys migrate the balances keys to cater for variable-length
    56  // addresses.
    57  func migrateBalanceKeys(store storetypes.KVStore, logger log.Logger) {
    58  	// old key is of format:
    59  	// prefix ("balances") || addrBytes (20 bytes) || denomBytes
    60  	// new key is of format
    61  	// prefix (0x02) || addrLen (1 byte) || addrBytes || denomBytes
    62  	oldStore := prefix.NewStore(store, v1.BalancesPrefix)
    63  
    64  	oldStoreIter := oldStore.Iterator(nil, nil)
    65  	defer sdk.LogDeferred(logger, func() error { return oldStoreIter.Close() })
    66  
    67  	for ; oldStoreIter.Valid(); oldStoreIter.Next() {
    68  		addr := v1.AddressFromBalancesStore(oldStoreIter.Key())
    69  		denom := oldStoreIter.Key()[v1auth.AddrLen:]
    70  		newStoreKey := CreatePrefixedAccountStoreKey(addr, denom)
    71  
    72  		// Set new key on store. Values don't change.
    73  		store.Set(newStoreKey, oldStoreIter.Value())
    74  		oldStore.Delete(oldStoreIter.Key())
    75  	}
    76  }
    77  
    78  // MigrateStore performs in-place store migrations from v0.40 to v0.43. The
    79  // migration includes:
    80  //
    81  // - Change addresses to be length-prefixed.
    82  // - Change balances prefix to 1 byte
    83  // - Change supply to be indexed by denom
    84  // - Prune balances & supply with zero coins (ref: https://github.com/cosmos/cosmos-sdk/pull/9229)
    85  func MigrateStore(ctx sdk.Context, storeService store.KVStoreService, cdc codec.BinaryCodec) error {
    86  	store := runtime.KVStoreAdapter(storeService.OpenKVStore(ctx))
    87  	migrateBalanceKeys(store, ctx.Logger())
    88  
    89  	if err := pruneZeroBalances(store, cdc); err != nil {
    90  		return err
    91  	}
    92  
    93  	if err := migrateSupply(store, cdc); err != nil {
    94  		return err
    95  	}
    96  
    97  	return pruneZeroSupply(store)
    98  }
    99  
   100  // pruneZeroBalances removes the zero balance addresses from balances store.
   101  func pruneZeroBalances(store storetypes.KVStore, cdc codec.BinaryCodec) error {
   102  	balancesStore := prefix.NewStore(store, BalancesPrefix)
   103  	iterator := balancesStore.Iterator(nil, nil)
   104  	defer iterator.Close()
   105  
   106  	for ; iterator.Valid(); iterator.Next() {
   107  		var balance sdk.Coin
   108  		if err := cdc.Unmarshal(iterator.Value(), &balance); err != nil {
   109  			return err
   110  		}
   111  
   112  		if balance.IsZero() {
   113  			balancesStore.Delete(iterator.Key())
   114  		}
   115  	}
   116  	return nil
   117  }
   118  
   119  // pruneZeroSupply removes zero balance denom from supply store.
   120  func pruneZeroSupply(store storetypes.KVStore) error {
   121  	supplyStore := prefix.NewStore(store, SupplyKey)
   122  	iterator := supplyStore.Iterator(nil, nil)
   123  	defer iterator.Close()
   124  
   125  	for ; iterator.Valid(); iterator.Next() {
   126  		var amount math.Int
   127  		if err := amount.Unmarshal(iterator.Value()); err != nil {
   128  			return err
   129  		}
   130  
   131  		if amount.IsZero() {
   132  			supplyStore.Delete(iterator.Key())
   133  		}
   134  	}
   135  
   136  	return nil
   137  }
   138  
   139  // CreatePrefixedAccountStoreKey returns the key for the given account and denomination.
   140  // This method can be used when performing an ABCI query for the balance of an account.
   141  func CreatePrefixedAccountStoreKey(addr, denom []byte) []byte {
   142  	return append(CreateAccountBalancesPrefix(addr), denom...)
   143  }