github.com/Finschia/finschia-sdk@v0.48.1/x/collection/keeper/migrations/v2/store.go (about) 1 package v2 2 3 import ( 4 "fmt" 5 6 "github.com/Finschia/finschia-sdk/codec" 7 storetypes "github.com/Finschia/finschia-sdk/store/types" 8 sdk "github.com/Finschia/finschia-sdk/types" 9 "github.com/Finschia/finschia-sdk/x/collection" 10 ) 11 12 // MigrateStore performs in-place store migrations from v1 to v2. 13 func MigrateStore(ctx sdk.Context, storeKey storetypes.StoreKey, cdc codec.BinaryCodec) error { 14 store := ctx.KVStore(storeKey) 15 16 // fix ft statistics 17 if err := fixFTStatistics(store, cdc); err != nil { 18 return err 19 } 20 21 return nil 22 } 23 24 func fixFTStatistics(store storetypes.KVStore, cdc codec.BinaryCodec) error { 25 iterator := sdk.KVStorePrefixIterator(store, contractKeyPrefix) 26 defer iterator.Close() 27 28 for ; iterator.Valid(); iterator.Next() { 29 var contract collection.Contract 30 if err := cdc.Unmarshal(iterator.Value(), &contract); err != nil { 31 return err 32 } 33 34 if err := fixContractFTStatistics(store, contract.Id); err != nil { 35 return err 36 } 37 } 38 39 return nil 40 } 41 42 func fixContractFTStatistics(store storetypes.KVStore, contractID string) error { 43 supplies, err := evalContractFTSupplies(store, contractID) 44 if err != nil { 45 return err 46 } 47 48 if err := updateContractFTStatistics(store, contractID, supplies); err != nil { 49 return err 50 } 51 52 return nil 53 } 54 55 func evalContractFTSupplies(store storetypes.KVStore, contractID string) (map[string]sdk.Int, error) { 56 prefix := balanceKeyPrefixByContractID(contractID) 57 iterator := sdk.KVStorePrefixIterator(store, prefix) 58 defer iterator.Close() 59 60 supplies := map[string]sdk.Int{} 61 for ; iterator.Valid(); iterator.Next() { 62 _, _, tokenID := splitBalanceKey(iterator.Key()) 63 if err := collection.ValidateFTID(tokenID); err != nil { 64 continue 65 } 66 67 var amount sdk.Int 68 if err := amount.Unmarshal(iterator.Value()); err != nil { 69 return nil, err 70 } 71 72 classID := collection.SplitTokenID(tokenID) 73 if supply, ok := supplies[classID]; ok { 74 supplies[classID] = supply.Add(amount) 75 } else { 76 supplies[classID] = amount 77 } 78 } 79 80 return supplies, nil 81 } 82 83 func updateContractFTStatistics(store storetypes.KVStore, contractID string, supplies map[string]sdk.Int) error { 84 bz := store.Get(NextClassIDKey(contractID)) 85 if bz == nil { 86 return fmt.Errorf("no next class ids of contract %s", contractID) 87 } 88 89 var nextClassIDs collection.NextClassIDs 90 if err := nextClassIDs.Unmarshal(bz); err != nil { 91 return err 92 } 93 94 // In the old chains, classID of fungible tokens starts from zero 95 // In the new chains, it starts from one, but it does not hurts because amount of zero is not set to the store. 96 for intClassID := uint64(0); intClassID < nextClassIDs.Fungible.Uint64(); intClassID++ { 97 classID := fmt.Sprintf("%08x", intClassID) 98 99 // update supply 100 supplyKey := StatisticKey(SupplyKeyPrefix, contractID, classID) 101 supply, ok := supplies[classID] 102 if ok { 103 bz, err := supply.Marshal() 104 if err != nil { 105 return err 106 } 107 store.Set(supplyKey, bz) 108 } else { 109 supply = sdk.ZeroInt() 110 store.Delete(supplyKey) 111 } 112 113 // get burnt 114 burntKey := StatisticKey(BurntKeyPrefix, contractID, classID) 115 burnt := sdk.ZeroInt() 116 if bz := store.Get(burntKey); bz != nil { 117 if err := burnt.Unmarshal(bz); err != nil { 118 return err 119 } 120 } 121 122 // update minted 123 minted := supply.Add(burnt) 124 mintedKey := StatisticKey(MintedKeyPrefix, contractID, classID) 125 if !minted.IsZero() { 126 bz, err := minted.Marshal() 127 if err != nil { 128 return err 129 } 130 store.Set(mintedKey, bz) 131 } else { 132 store.Delete(mintedKey) 133 } 134 } 135 136 return nil 137 }