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 }