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 }