github.com/Finschia/finschia-sdk@v0.48.1/x/collection/keeper/genesis.go (about)

     1  package keeper
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/Finschia/ostracon/libs/log"
     7  
     8  	sdk "github.com/Finschia/finschia-sdk/types"
     9  	"github.com/Finschia/finschia-sdk/x/collection"
    10  )
    11  
    12  type ProgressReporter struct {
    13  	logger log.Logger
    14  
    15  	workName  string
    16  	workSize  int
    17  	workIndex int
    18  
    19  	prevPercentage int
    20  }
    21  
    22  func newProgressReporter(logger log.Logger, workName string, workSize int) ProgressReporter {
    23  	reporter := ProgressReporter{
    24  		logger:   logger,
    25  		workName: workName,
    26  		workSize: workSize,
    27  	}
    28  	reporter.report()
    29  
    30  	return reporter
    31  }
    32  
    33  func (p ProgressReporter) report() {
    34  	if p.workSize == 0 {
    35  		p.logger.Info(fmt.Sprintf("Empty %s", p.workName))
    36  		return
    37  	}
    38  
    39  	switch p.prevPercentage {
    40  	case 0:
    41  		p.logger.Info(fmt.Sprintf("Starting %s ...", p.workName))
    42  	case 100:
    43  		p.logger.Info(fmt.Sprintf("Done %s", p.workName))
    44  	default:
    45  		p.logger.Info(fmt.Sprintf("Progress: %d%%", p.prevPercentage))
    46  	}
    47  }
    48  
    49  func (p *ProgressReporter) Tick() {
    50  	if p.workIndex > p.workSize-1 {
    51  		return
    52  	}
    53  	p.workIndex++
    54  
    55  	if percentage := 100 * p.workIndex / p.workSize; percentage != p.prevPercentage {
    56  		p.prevPercentage = percentage
    57  		p.report()
    58  	}
    59  }
    60  
    61  // InitGenesis new collection genesis
    62  func (k Keeper) InitGenesis(ctx sdk.Context, data *collection.GenesisState) {
    63  	k.SetParams(ctx, data.Params)
    64  
    65  	reporter := newProgressReporter(k.Logger(ctx), "import contract", len(data.Contracts))
    66  	for _, contract := range data.Contracts {
    67  		k.setContract(ctx, contract)
    68  		reporter.Tick()
    69  	}
    70  
    71  	reporter = newProgressReporter(k.Logger(ctx), "import next class ids", len(data.NextClassIds))
    72  	for _, nextClassIDs := range data.NextClassIds {
    73  		k.setNextClassIDs(ctx, nextClassIDs)
    74  		reporter.Tick()
    75  	}
    76  
    77  	reporter = newProgressReporter(k.Logger(ctx), "import classes", len(data.Classes))
    78  	for _, contractClasses := range data.Classes {
    79  		contractID := contractClasses.ContractId
    80  
    81  		for i := range contractClasses.Classes {
    82  			any := &contractClasses.Classes[i]
    83  			class := collection.TokenClassFromAny(any)
    84  			k.setTokenClass(ctx, contractID, class)
    85  
    86  			// legacy
    87  			if nftClass, ok := class.(*collection.NFTClass); ok {
    88  				k.setLegacyTokenType(ctx, contractID, nftClass.Id)
    89  			}
    90  		}
    91  
    92  		reporter.Tick()
    93  	}
    94  
    95  	reporter = newProgressReporter(k.Logger(ctx), "import next token ids", len(data.NextTokenIds))
    96  	for _, contractNextTokenIDs := range data.NextTokenIds {
    97  		contractID := contractNextTokenIDs.ContractId
    98  
    99  		for _, nextTokenID := range contractNextTokenIDs.TokenIds {
   100  			k.setNextTokenID(ctx, contractID, nextTokenID.ClassId, nextTokenID.Id)
   101  		}
   102  
   103  		reporter.Tick()
   104  	}
   105  
   106  	reporter = newProgressReporter(k.Logger(ctx), "import balances", len(data.Balances))
   107  	for _, contractBalances := range data.Balances {
   108  		contractID := contractBalances.ContractId
   109  
   110  		for _, balance := range contractBalances.Balances {
   111  			for _, coin := range balance.Amount {
   112  				addr, err := sdk.AccAddressFromBech32(balance.Address)
   113  				if err != nil {
   114  					panic(err)
   115  				}
   116  
   117  				k.setBalance(ctx, contractID, addr, coin.TokenId, coin.Amount)
   118  
   119  				if err := collection.ValidateNFTID(coin.TokenId); err == nil {
   120  					k.setOwner(ctx, contractID, coin.TokenId, addr)
   121  				}
   122  			}
   123  		}
   124  
   125  		reporter.Tick()
   126  	}
   127  
   128  	reporter = newProgressReporter(k.Logger(ctx), "import nfts", len(data.Nfts))
   129  	for _, contractNFTs := range data.Nfts {
   130  		contractID := contractNFTs.ContractId
   131  
   132  		for _, nft := range contractNFTs.Nfts {
   133  			k.setNFT(ctx, contractID, nft)
   134  		}
   135  
   136  		reporter.Tick()
   137  	}
   138  
   139  	reporter = newProgressReporter(k.Logger(ctx), "import parents", len(data.Parents))
   140  	for _, contractParents := range data.Parents {
   141  		contractID := contractParents.ContractId
   142  
   143  		for _, relation := range contractParents.Relations {
   144  			tokenID := relation.Self
   145  			parentID := relation.Other
   146  			k.setParent(ctx, contractID, tokenID, parentID)
   147  			k.setChild(ctx, contractID, parentID, tokenID)
   148  		}
   149  
   150  		reporter.Tick()
   151  	}
   152  
   153  	reporter = newProgressReporter(k.Logger(ctx), "import authorizations", len(data.Authorizations))
   154  	for _, contractAuthorizations := range data.Authorizations {
   155  		for _, authorization := range contractAuthorizations.Authorizations {
   156  			holderAddr, err := sdk.AccAddressFromBech32(authorization.Holder)
   157  			if err != nil {
   158  				panic(err)
   159  			}
   160  			operatorAddr, err := sdk.AccAddressFromBech32(authorization.Operator)
   161  			if err != nil {
   162  				panic(err)
   163  			}
   164  			k.setAuthorization(ctx, contractAuthorizations.ContractId, holderAddr, operatorAddr)
   165  		}
   166  
   167  		reporter.Tick()
   168  	}
   169  
   170  	reporter = newProgressReporter(k.Logger(ctx), "import grants", len(data.Grants))
   171  	for _, contractGrants := range data.Grants {
   172  		for _, grant := range contractGrants.Grants {
   173  			granteeAddr, err := sdk.AccAddressFromBech32(grant.Grantee)
   174  			if err != nil {
   175  				panic(err)
   176  			}
   177  			k.setGrant(ctx, contractGrants.ContractId, granteeAddr, grant.Permission)
   178  		}
   179  
   180  		reporter.Tick()
   181  	}
   182  
   183  	reporter = newProgressReporter(k.Logger(ctx), "import statistics (burnt)", len(data.Burnts))
   184  	for _, contractBurnts := range data.Burnts {
   185  		contractID := contractBurnts.ContractId
   186  		for _, burnt := range contractBurnts.Statistics {
   187  			k.setBurnt(ctx, contractID, burnt.ClassId, burnt.Amount)
   188  		}
   189  
   190  		reporter.Tick()
   191  	}
   192  
   193  	reporter = newProgressReporter(k.Logger(ctx), "import statistics (supply)", len(data.Supplies))
   194  	for _, contractSupplies := range data.Supplies {
   195  		contractID := contractSupplies.ContractId
   196  		for _, supply := range contractSupplies.Statistics {
   197  			k.setSupply(ctx, contractID, supply.ClassId, supply.Amount)
   198  
   199  			// calculate the amount of minted tokens
   200  			burnt := k.GetBurnt(ctx, contractID, supply.ClassId)
   201  			minted := supply.Amount.Add(burnt)
   202  			k.setMinted(ctx, contractID, supply.ClassId, minted)
   203  		}
   204  
   205  		reporter.Tick()
   206  	}
   207  }
   208  
   209  // ExportGenesis returns a GenesisState for a given context.
   210  func (k Keeper) ExportGenesis(ctx sdk.Context) *collection.GenesisState {
   211  	contracts := k.getContracts(ctx)
   212  
   213  	return &collection.GenesisState{
   214  		Contracts:      contracts,
   215  		NextClassIds:   k.getAllNextClassIDs(ctx),
   216  		Classes:        k.getClasses(ctx, contracts),
   217  		NextTokenIds:   k.getNextTokenIDs(ctx, contracts),
   218  		Balances:       k.getBalances(ctx, contracts),
   219  		Nfts:           k.getNFTs(ctx, contracts),
   220  		Parents:        k.getParents(ctx, contracts),
   221  		Grants:         k.getGrants(ctx, contracts),
   222  		Authorizations: k.getAuthorizations(ctx, contracts),
   223  		Supplies:       k.getSupplies(ctx, contracts),
   224  		Burnts:         k.getBurnts(ctx, contracts),
   225  	}
   226  }
   227  
   228  func (k Keeper) getContracts(ctx sdk.Context) []collection.Contract {
   229  	var contracts []collection.Contract
   230  	k.iterateContracts(ctx, func(contract collection.Contract) (stop bool) {
   231  		contracts = append(contracts, contract)
   232  		return false
   233  	})
   234  
   235  	return contracts
   236  }
   237  
   238  func (k Keeper) getClasses(ctx sdk.Context, contracts []collection.Contract) []collection.ContractClasses {
   239  	var classes []collection.ContractClasses
   240  	for _, contract := range contracts {
   241  		contractID := contract.Id
   242  		contractClasses := collection.ContractClasses{
   243  			ContractId: contractID,
   244  		}
   245  
   246  		k.iterateContractClasses(ctx, contractID, func(class collection.TokenClass) (stop bool) {
   247  			any := collection.TokenClassToAny(class)
   248  			contractClasses.Classes = append(contractClasses.Classes, *any)
   249  			return false
   250  		})
   251  		if len(contractClasses.Classes) != 0 {
   252  			classes = append(classes, contractClasses)
   253  		}
   254  	}
   255  
   256  	return classes
   257  }
   258  
   259  func (k Keeper) getAllNextClassIDs(ctx sdk.Context) []collection.NextClassIDs {
   260  	var nextIDs []collection.NextClassIDs
   261  	k.iterateNextTokenClassIDs(ctx, func(ids collection.NextClassIDs) (stop bool) {
   262  		nextIDs = append(nextIDs, ids)
   263  		return false
   264  	})
   265  
   266  	return nextIDs
   267  }
   268  
   269  func (k Keeper) getNextTokenIDs(ctx sdk.Context, contracts []collection.Contract) []collection.ContractNextTokenIDs {
   270  	var nextIDs []collection.ContractNextTokenIDs
   271  	for _, contract := range contracts {
   272  		contractID := contract.Id
   273  		contractNextIDs := collection.ContractNextTokenIDs{
   274  			ContractId: contractID,
   275  		}
   276  
   277  		k.iterateContractNextTokenIDs(ctx, contractID, func(nextID collection.NextTokenID) (stop bool) {
   278  			contractNextIDs.TokenIds = append(contractNextIDs.TokenIds, nextID)
   279  			return false
   280  		})
   281  		if len(contractNextIDs.TokenIds) != 0 {
   282  			nextIDs = append(nextIDs, contractNextIDs)
   283  		}
   284  	}
   285  
   286  	return nextIDs
   287  }
   288  
   289  func (k Keeper) getBalances(ctx sdk.Context, contracts []collection.Contract) []collection.ContractBalances {
   290  	var balances []collection.ContractBalances
   291  	for _, contract := range contracts {
   292  		contractID := contract.Id
   293  		contractBalances := collection.ContractBalances{
   294  			ContractId: contractID,
   295  		}
   296  
   297  		contractBalances.Balances = k.getContractBalances(ctx, contractID)
   298  		if len(contractBalances.Balances) != 0 {
   299  			balances = append(balances, contractBalances)
   300  		}
   301  	}
   302  
   303  	return balances
   304  }
   305  
   306  func (k Keeper) getContractBalances(ctx sdk.Context, contractID string) []collection.Balance {
   307  	var balances []collection.Balance
   308  	addressToBalanceIndex := make(map[string]int)
   309  
   310  	k.iterateContractBalances(ctx, contractID, func(address sdk.AccAddress, balance collection.Coin) (stop bool) {
   311  		index, ok := addressToBalanceIndex[address.String()]
   312  		if ok {
   313  			balances[index].Amount = append(balances[index].Amount, balance)
   314  			return false
   315  		}
   316  
   317  		accountBalance := collection.Balance{
   318  			Address: address.String(),
   319  			Amount:  collection.Coins{balance},
   320  		}
   321  		balances = append(balances, accountBalance)
   322  		addressToBalanceIndex[address.String()] = len(balances) - 1
   323  		return false
   324  	})
   325  
   326  	return balances
   327  }
   328  
   329  func (k Keeper) getNFTs(ctx sdk.Context, contracts []collection.Contract) []collection.ContractNFTs {
   330  	var parents []collection.ContractNFTs
   331  	for _, contract := range contracts {
   332  		contractID := contract.Id
   333  		contractParents := collection.ContractNFTs{
   334  			ContractId: contractID,
   335  		}
   336  
   337  		k.iterateContractNFTs(ctx, contractID, func(nft collection.NFT) (stop bool) {
   338  			contractParents.Nfts = append(contractParents.Nfts, nft)
   339  			return false
   340  		})
   341  		if len(contractParents.Nfts) != 0 {
   342  			parents = append(parents, contractParents)
   343  		}
   344  	}
   345  
   346  	return parents
   347  }
   348  
   349  func (k Keeper) getParents(ctx sdk.Context, contracts []collection.Contract) []collection.ContractTokenRelations {
   350  	var parents []collection.ContractTokenRelations
   351  	for _, contract := range contracts {
   352  		contractID := contract.Id
   353  		contractParents := collection.ContractTokenRelations{
   354  			ContractId: contractID,
   355  		}
   356  
   357  		k.iterateContractParents(ctx, contractID, func(tokenID, parentID string) (stop bool) {
   358  			relation := collection.TokenRelation{
   359  				Self:  tokenID,
   360  				Other: parentID,
   361  			}
   362  			contractParents.Relations = append(contractParents.Relations, relation)
   363  			return false
   364  		})
   365  		if len(contractParents.Relations) != 0 {
   366  			parents = append(parents, contractParents)
   367  		}
   368  	}
   369  
   370  	return parents
   371  }
   372  
   373  func (k Keeper) getAuthorizations(ctx sdk.Context, contracts []collection.Contract) []collection.ContractAuthorizations {
   374  	var authorizations []collection.ContractAuthorizations
   375  	for _, contract := range contracts {
   376  		contractID := contract.Id
   377  		contractAuthorizations := collection.ContractAuthorizations{
   378  			ContractId: contractID,
   379  		}
   380  
   381  		k.iterateContractAuthorizations(ctx, contractID, func(authorization collection.Authorization) (stop bool) {
   382  			contractAuthorizations.Authorizations = append(contractAuthorizations.Authorizations, authorization)
   383  			return false
   384  		})
   385  		if len(contractAuthorizations.Authorizations) != 0 {
   386  			authorizations = append(authorizations, contractAuthorizations)
   387  		}
   388  	}
   389  
   390  	return authorizations
   391  }
   392  
   393  func (k Keeper) getGrants(ctx sdk.Context, contracts []collection.Contract) []collection.ContractGrants {
   394  	var grants []collection.ContractGrants
   395  	for _, contract := range contracts {
   396  		contractID := contract.Id
   397  		contractGrants := collection.ContractGrants{
   398  			ContractId: contractID,
   399  		}
   400  
   401  		k.iterateContractGrants(ctx, contractID, func(grant collection.Grant) (stop bool) {
   402  			contractGrants.Grants = append(contractGrants.Grants, grant)
   403  			return false
   404  		})
   405  		if len(contractGrants.Grants) != 0 {
   406  			grants = append(grants, contractGrants)
   407  		}
   408  	}
   409  
   410  	return grants
   411  }
   412  
   413  func (k Keeper) getSupplies(ctx sdk.Context, contracts []collection.Contract) []collection.ContractStatistics {
   414  	return k.getStatistics(ctx, contracts, k.iterateContractSupplies)
   415  }
   416  
   417  func (k Keeper) getBurnts(ctx sdk.Context, contracts []collection.Contract) []collection.ContractStatistics {
   418  	return k.getStatistics(ctx, contracts, k.iterateContractBurnts)
   419  }
   420  
   421  func (k Keeper) getStatistics(ctx sdk.Context, contracts []collection.Contract, iterator func(ctx sdk.Context, contractID string, cb func(classID string, amount sdk.Int) (stop bool))) []collection.ContractStatistics {
   422  	var statistics []collection.ContractStatistics
   423  	for _, contract := range contracts {
   424  		contractID := contract.Id
   425  		contractStatistics := collection.ContractStatistics{
   426  			ContractId: contractID,
   427  		}
   428  
   429  		iterator(ctx, contractID, func(classID string, amount sdk.Int) (stop bool) {
   430  			supply := collection.ClassStatistics{
   431  				ClassId: classID,
   432  				Amount:  amount,
   433  			}
   434  			contractStatistics.Statistics = append(contractStatistics.Statistics, supply)
   435  			return false
   436  		})
   437  		if len(contractStatistics.Statistics) != 0 {
   438  			statistics = append(statistics, contractStatistics)
   439  		}
   440  	}
   441  
   442  	return statistics
   443  }