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 }