github.com/Finschia/finschia-sdk@v0.49.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  		Params:         k.GetParams(ctx),
   215  		Contracts:      contracts,
   216  		NextClassIds:   k.getAllNextClassIDs(ctx),
   217  		Classes:        k.getClasses(ctx, contracts),
   218  		NextTokenIds:   k.getNextTokenIDs(ctx, contracts),
   219  		Balances:       k.getBalances(ctx, contracts),
   220  		Nfts:           k.getNFTs(ctx, contracts),
   221  		Parents:        k.getParents(ctx, contracts),
   222  		Grants:         k.getGrants(ctx, contracts),
   223  		Authorizations: k.getAuthorizations(ctx, contracts),
   224  		Supplies:       k.getSupplies(ctx, contracts),
   225  		Burnts:         k.getBurnts(ctx, contracts),
   226  	}
   227  }
   228  
   229  func (k Keeper) getContracts(ctx sdk.Context) []collection.Contract {
   230  	var contracts []collection.Contract
   231  	k.iterateContracts(ctx, func(contract collection.Contract) (stop bool) {
   232  		contracts = append(contracts, contract)
   233  		return false
   234  	})
   235  
   236  	return contracts
   237  }
   238  
   239  func (k Keeper) getClasses(ctx sdk.Context, contracts []collection.Contract) []collection.ContractClasses {
   240  	var classes []collection.ContractClasses
   241  	for _, contract := range contracts {
   242  		contractID := contract.Id
   243  		contractClasses := collection.ContractClasses{
   244  			ContractId: contractID,
   245  		}
   246  
   247  		k.iterateContractClasses(ctx, contractID, func(class collection.TokenClass) (stop bool) {
   248  			any := collection.TokenClassToAny(class)
   249  			contractClasses.Classes = append(contractClasses.Classes, *any)
   250  			return false
   251  		})
   252  		if len(contractClasses.Classes) != 0 {
   253  			classes = append(classes, contractClasses)
   254  		}
   255  	}
   256  
   257  	return classes
   258  }
   259  
   260  func (k Keeper) getAllNextClassIDs(ctx sdk.Context) []collection.NextClassIDs {
   261  	var nextIDs []collection.NextClassIDs
   262  	k.iterateNextTokenClassIDs(ctx, func(ids collection.NextClassIDs) (stop bool) {
   263  		nextIDs = append(nextIDs, ids)
   264  		return false
   265  	})
   266  
   267  	return nextIDs
   268  }
   269  
   270  func (k Keeper) getNextTokenIDs(ctx sdk.Context, contracts []collection.Contract) []collection.ContractNextTokenIDs {
   271  	var nextIDs []collection.ContractNextTokenIDs
   272  	for _, contract := range contracts {
   273  		contractID := contract.Id
   274  		contractNextIDs := collection.ContractNextTokenIDs{
   275  			ContractId: contractID,
   276  		}
   277  
   278  		k.iterateContractNextTokenIDs(ctx, contractID, func(nextID collection.NextTokenID) (stop bool) {
   279  			contractNextIDs.TokenIds = append(contractNextIDs.TokenIds, nextID)
   280  			return false
   281  		})
   282  		if len(contractNextIDs.TokenIds) != 0 {
   283  			nextIDs = append(nextIDs, contractNextIDs)
   284  		}
   285  	}
   286  
   287  	return nextIDs
   288  }
   289  
   290  func (k Keeper) getBalances(ctx sdk.Context, contracts []collection.Contract) []collection.ContractBalances {
   291  	var balances []collection.ContractBalances
   292  	for _, contract := range contracts {
   293  		contractID := contract.Id
   294  		contractBalances := collection.ContractBalances{
   295  			ContractId: contractID,
   296  		}
   297  
   298  		contractBalances.Balances = k.getContractBalances(ctx, contractID)
   299  		if len(contractBalances.Balances) != 0 {
   300  			balances = append(balances, contractBalances)
   301  		}
   302  	}
   303  
   304  	return balances
   305  }
   306  
   307  func (k Keeper) getContractBalances(ctx sdk.Context, contractID string) []collection.Balance {
   308  	var balances []collection.Balance
   309  	addressToBalanceIndex := make(map[string]int)
   310  
   311  	k.iterateContractBalances(ctx, contractID, func(address sdk.AccAddress, balance collection.Coin) (stop bool) {
   312  		index, ok := addressToBalanceIndex[address.String()]
   313  		if ok {
   314  			balances[index].Amount = append(balances[index].Amount, balance)
   315  			return false
   316  		}
   317  
   318  		accountBalance := collection.Balance{
   319  			Address: address.String(),
   320  			Amount:  collection.Coins{balance},
   321  		}
   322  		balances = append(balances, accountBalance)
   323  		addressToBalanceIndex[address.String()] = len(balances) - 1
   324  		return false
   325  	})
   326  
   327  	return balances
   328  }
   329  
   330  func (k Keeper) getNFTs(ctx sdk.Context, contracts []collection.Contract) []collection.ContractNFTs {
   331  	var parents []collection.ContractNFTs
   332  	for _, contract := range contracts {
   333  		contractID := contract.Id
   334  		contractParents := collection.ContractNFTs{
   335  			ContractId: contractID,
   336  		}
   337  
   338  		k.iterateContractNFTs(ctx, contractID, func(nft collection.NFT) (stop bool) {
   339  			contractParents.Nfts = append(contractParents.Nfts, nft)
   340  			return false
   341  		})
   342  		if len(contractParents.Nfts) != 0 {
   343  			parents = append(parents, contractParents)
   344  		}
   345  	}
   346  
   347  	return parents
   348  }
   349  
   350  func (k Keeper) getParents(ctx sdk.Context, contracts []collection.Contract) []collection.ContractTokenRelations {
   351  	var parents []collection.ContractTokenRelations
   352  	for _, contract := range contracts {
   353  		contractID := contract.Id
   354  		contractParents := collection.ContractTokenRelations{
   355  			ContractId: contractID,
   356  		}
   357  
   358  		k.iterateContractParents(ctx, contractID, func(tokenID, parentID string) (stop bool) {
   359  			relation := collection.TokenRelation{
   360  				Self:  tokenID,
   361  				Other: parentID,
   362  			}
   363  			contractParents.Relations = append(contractParents.Relations, relation)
   364  			return false
   365  		})
   366  		if len(contractParents.Relations) != 0 {
   367  			parents = append(parents, contractParents)
   368  		}
   369  	}
   370  
   371  	return parents
   372  }
   373  
   374  func (k Keeper) getAuthorizations(ctx sdk.Context, contracts []collection.Contract) []collection.ContractAuthorizations {
   375  	var authorizations []collection.ContractAuthorizations
   376  	for _, contract := range contracts {
   377  		contractID := contract.Id
   378  		contractAuthorizations := collection.ContractAuthorizations{
   379  			ContractId: contractID,
   380  		}
   381  
   382  		k.iterateContractAuthorizations(ctx, contractID, func(authorization collection.Authorization) (stop bool) {
   383  			contractAuthorizations.Authorizations = append(contractAuthorizations.Authorizations, authorization)
   384  			return false
   385  		})
   386  		if len(contractAuthorizations.Authorizations) != 0 {
   387  			authorizations = append(authorizations, contractAuthorizations)
   388  		}
   389  	}
   390  
   391  	return authorizations
   392  }
   393  
   394  func (k Keeper) getGrants(ctx sdk.Context, contracts []collection.Contract) []collection.ContractGrants {
   395  	var grants []collection.ContractGrants
   396  	for _, contract := range contracts {
   397  		contractID := contract.Id
   398  		contractGrants := collection.ContractGrants{
   399  			ContractId: contractID,
   400  		}
   401  
   402  		k.iterateContractGrants(ctx, contractID, func(grant collection.Grant) (stop bool) {
   403  			contractGrants.Grants = append(contractGrants.Grants, grant)
   404  			return false
   405  		})
   406  		if len(contractGrants.Grants) != 0 {
   407  			grants = append(grants, contractGrants)
   408  		}
   409  	}
   410  
   411  	return grants
   412  }
   413  
   414  func (k Keeper) getSupplies(ctx sdk.Context, contracts []collection.Contract) []collection.ContractStatistics {
   415  	return k.getStatistics(ctx, contracts, k.iterateContractSupplies)
   416  }
   417  
   418  func (k Keeper) getBurnts(ctx sdk.Context, contracts []collection.Contract) []collection.ContractStatistics {
   419  	return k.getStatistics(ctx, contracts, k.iterateContractBurnts)
   420  }
   421  
   422  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 {
   423  	var statistics []collection.ContractStatistics
   424  	for _, contract := range contracts {
   425  		contractID := contract.Id
   426  		contractStatistics := collection.ContractStatistics{
   427  			ContractId: contractID,
   428  		}
   429  
   430  		iterator(ctx, contractID, func(classID string, amount sdk.Int) (stop bool) {
   431  			supply := collection.ClassStatistics{
   432  				ClassId: classID,
   433  				Amount:  amount,
   434  			}
   435  			contractStatistics.Statistics = append(contractStatistics.Statistics, supply)
   436  			return false
   437  		})
   438  		if len(contractStatistics.Statistics) != 0 {
   439  			statistics = append(statistics, contractStatistics)
   440  		}
   441  	}
   442  
   443  	return statistics
   444  }