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  }