github.com/0chain/gosdk@v1.17.11/wasmsdk/allocation.go (about) 1 //go:build js && wasm 2 // +build js,wasm 3 4 package main 5 6 import ( 7 "encoding/base64" 8 "encoding/json" 9 "errors" 10 "fmt" 11 "strconv" 12 "strings" 13 "sync" 14 "syscall/js" 15 16 "github.com/0chain/gosdk/core/transaction" 17 "github.com/0chain/gosdk/wasmsdk/jsbridge" 18 "github.com/0chain/gosdk/zboxcore/sdk" 19 ) 20 21 const TOKEN_UNIT int64 = 1e10 22 23 type fileResp struct { 24 sdk.FileInfo 25 Name string `json:"name"` 26 Path string `json:"path"` 27 } 28 29 type decodeAuthTokenResp struct { 30 RecipientPublicKey string `json:"recipient_public_key"` 31 Marker string `json:"marker"` 32 Tokens uint64 `json:"tokens"` 33 } 34 35 // getBlobberIds retrieves blobber ids from the given blobber urls 36 // - blobberUrls is the list of blobber urls 37 func getBlobberIds(blobberUrls []string) ([]string, error) { 38 return sdk.GetBlobberIds(blobberUrls) 39 } 40 41 // createfreeallocation creates a free allocation 42 // - freeStorageMarker is the free storage marker 43 func createfreeallocation(freeStorageMarker string) (string, error) { 44 allocationID, _, err := sdk.CreateFreeAllocation(freeStorageMarker, 0) 45 if err != nil { 46 sdkLogger.Error("Error creating free allocation: ", err) 47 return "", err 48 } 49 return allocationID, err 50 } 51 52 // getAllocationBlobbers retrieves allocation blobbers 53 // - preferredBlobberURLs is the list of preferred blobber urls 54 // - dataShards is the number of data shards 55 // - parityShards is the number of parity shards 56 // - size is the size of the allocation 57 // - minReadPrice is the minimum read price 58 // - maxReadPrice is the maximum read price 59 // - minWritePrice is the minimum write price 60 // - maxWritePrice is the maximum write price 61 // - isRestricted is the restricted flag 62 // - force is the force flag 63 func getAllocationBlobbers(preferredBlobberURLs []string, 64 dataShards, parityShards int, size int64, 65 minReadPrice, maxReadPrice, minWritePrice, maxWritePrice int64, isRestricted int, force bool) ([]string, error) { 66 67 if len(preferredBlobberURLs) > 0 { 68 return sdk.GetBlobberIds(preferredBlobberURLs) 69 } 70 71 return sdk.GetAllocationBlobbers(dataShards, parityShards, size, isRestricted, sdk.PriceRange{ 72 Min: uint64(minReadPrice), 73 Max: uint64(maxReadPrice), 74 }, sdk.PriceRange{ 75 Min: uint64(minWritePrice), 76 Max: uint64(maxWritePrice), 77 }, force) 78 } 79 80 // createAllocation creates an allocation given allocation creation parameters 81 // - datashards is the number of data shards. Data uploaded to the allocation will be split and distributed across these shards. 82 // - parityshards is the number of parity shards. Parity shards are used to replicate datashards for redundancy. 83 // - size is the size of the allocation in bytes. 84 // - minReadPrice is the minimum read price set by the client. 85 // - maxReadPrice is the maximum read price set by the client. 86 // - minWritePrice is the minimum write price set by the client. 87 // - maxWritePrice is the maximum write price set by the client. 88 // - lock is the lock value to add to the allocation. 89 // - blobberIds is the list of blobber ids. 90 // - blobberAuthTickets is the list of blobber auth tickets in case of using restricted blobbers. 91 func createAllocation(datashards, parityshards int, size int64, 92 minReadPrice, maxReadPrice, minWritePrice, maxWritePrice int64, lock int64, blobberIds, blobberAuthTickets []string, setThirdPartyExtendable, IsEnterprise, force bool) ( 93 *transaction.Transaction, error) { 94 95 options := sdk.CreateAllocationOptions{ 96 DataShards: datashards, 97 ParityShards: parityshards, 98 Size: size, 99 ReadPrice: sdk.PriceRange{ 100 Min: uint64(minReadPrice), 101 Max: uint64(maxReadPrice), 102 }, 103 WritePrice: sdk.PriceRange{ 104 Min: uint64(minWritePrice), 105 Max: uint64(maxWritePrice), 106 }, 107 Lock: uint64(lock), 108 BlobberIds: blobberIds, 109 ThirdPartyExtendable: setThirdPartyExtendable, 110 IsEnterprise: IsEnterprise, 111 BlobberAuthTickets: blobberAuthTickets, 112 Force: force, 113 } 114 115 sdkLogger.Info(options) 116 _, _, txn, err := sdk.CreateAllocationWith(options) 117 118 return txn, err 119 } 120 121 // listAllocations retrieves the list of allocations owned by the client 122 func listAllocations() ([]*sdk.Allocation, error) { 123 return sdk.GetAllocations() 124 } 125 126 // transferAllocation transfers the ownership of an allocation to a new owner 127 // - allocationID is the allocation id 128 // - newOwnerId is the new owner id 129 // - newOwnerPublicKey is the new owner public key 130 func transferAllocation(allocationID, newOwnerId, newOwnerPublicKey string) error { 131 if allocationID == "" { 132 return RequiredArg("allocationID") 133 } 134 135 if newOwnerId == "" { 136 return RequiredArg("newOwnerId") 137 } 138 139 if newOwnerPublicKey == "" { 140 return RequiredArg("newOwnerPublicKey") 141 } 142 143 _, _, err := sdk.TransferAllocation(allocationID, newOwnerId, newOwnerPublicKey) 144 145 if err == nil { 146 clearAllocation(allocationID) 147 } 148 149 return err 150 } 151 152 // UpdateForbidAllocation updates the permissions of an allocation, given the permission parameters in a forbid-first manner. 153 // - allocationID: allocation ID 154 // - forbidupload: forbid upload flag, if true, uploading files to the allocation is forbidden 155 // - forbiddelete: forbid delete flag, if true, deleting files from the allocation is forbidden 156 // - forbidupdate: forbid update flag, if true, updating files in the allocation is forbidden 157 // - forbidmove: forbid move flag, if true, moving files in the allocation is forbidden 158 // - forbidcopy: forbid copy flag, if true, copying files in the allocation is forbidden 159 // - forbidrename: forbid rename flag, if true, renaming files in the allocation is forbidden 160 func UpdateForbidAllocation(allocationID string, forbidupload, forbiddelete, forbidupdate, forbidmove, forbidcopy, forbidrename bool) (string, error) { 161 162 hash, _, err := sdk.UpdateAllocation( 163 0, //size, 164 false, //extend, 165 allocationID, // allocID, 166 0, //lock, 167 "", //addBlobberId, 168 "", //addBlobberAuthTicket 169 "", //removeBlobberId, 170 false, //thirdPartyExtendable, 171 &sdk.FileOptionsParameters{ 172 ForbidUpload: sdk.FileOptionParam{Changed: forbidupload, Value: forbidupload}, 173 ForbidDelete: sdk.FileOptionParam{Changed: forbiddelete, Value: forbiddelete}, 174 ForbidUpdate: sdk.FileOptionParam{Changed: forbidupdate, Value: forbidupdate}, 175 ForbidMove: sdk.FileOptionParam{Changed: forbidmove, Value: forbidmove}, 176 ForbidCopy: sdk.FileOptionParam{Changed: forbidcopy, Value: forbidcopy}, 177 ForbidRename: sdk.FileOptionParam{Changed: forbidrename, Value: forbidrename}, 178 }, 179 ) 180 181 return hash, err 182 183 } 184 185 // freezeAllocation freezes one of the client's allocations, given its ID 186 // Freezing the allocation means to forbid all the operations on the files in the allocation. 187 // - allocationID: allocation ID 188 func freezeAllocation(allocationID string) (string, error) { 189 190 hash, _, err := sdk.UpdateAllocation( 191 0, //size, 192 false, //extend, 193 allocationID, // allocID, 194 0, //lock, 195 "", //addBlobberId, 196 "", //addBlobberAuthTicket 197 "", //removeBlobberId, 198 false, //thirdPartyExtendable, 199 &sdk.FileOptionsParameters{ 200 ForbidUpload: sdk.FileOptionParam{Changed: true, Value: true}, 201 ForbidDelete: sdk.FileOptionParam{Changed: true, Value: true}, 202 ForbidUpdate: sdk.FileOptionParam{Changed: true, Value: true}, 203 ForbidMove: sdk.FileOptionParam{Changed: true, Value: true}, 204 ForbidCopy: sdk.FileOptionParam{Changed: true, Value: true}, 205 ForbidRename: sdk.FileOptionParam{Changed: true, Value: true}, 206 }, 207 ) 208 209 if err == nil { 210 clearAllocation(allocationID) 211 } 212 213 return hash, err 214 215 } 216 217 // cancelAllocation cancels one of the client's allocations, given its ID 218 // - allocationID: allocation ID 219 func cancelAllocation(allocationID string) (string, error) { 220 hash, _, err := sdk.CancelAllocation(allocationID) 221 222 if err == nil { 223 clearAllocation(allocationID) 224 } 225 226 return hash, err 227 } 228 229 // updateAllocationWithRepair updates the allocation settings and repairs it if necessary. 230 // Repair means to sync the user's data under the allocation on all the blobbers 231 // and fill the missing data on the blobbers that have missing data. 232 // Check the system documentation for more information about the repoair process. 233 // - allocationID: allocation ID 234 // - size: size of the allocation 235 // - extend: extend flag 236 // - lock: lock value to add to the allocation 237 // - addBlobberId: blobber ID to add to the allocation 238 // - addBlobberAuthTicket: blobber auth ticket to add to the allocation, in case of restricted blobbers 239 // - removeBlobberId: blobber ID to remove from the allocation 240 func updateAllocationWithRepair(allocationID string, 241 size int64, 242 extend bool, 243 lock int64, 244 addBlobberId, addBlobberAuthTicket, removeBlobberId, callbackFuncName string) (string, error) { 245 sdk.SetWasm() 246 allocationObj, err := sdk.GetAllocation(allocationID) 247 if err != nil { 248 return "", err 249 } 250 251 wg := &sync.WaitGroup{} 252 statusBar := &StatusBar{wg: wg, isRepair: true, totalBytesMap: make(map[string]int)} 253 wg.Add(1) 254 if callbackFuncName != "" { 255 callback := js.Global().Get(callbackFuncName) 256 statusBar.callback = func(totalBytes, completedBytes int, filename, objURL, err string) { 257 callback.Invoke(totalBytes, completedBytes, filename, objURL, err) 258 } 259 } 260 261 alloc, hash, isRepairRequired, err := allocationObj.UpdateWithStatus(size, extend, uint64(lock), addBlobberId, addBlobberAuthTicket, removeBlobberId, false, &sdk.FileOptionsParameters{}, statusBar) 262 if err != nil { 263 return hash, err 264 } 265 clearAllocation(allocationID) 266 267 if isRepairRequired { 268 addWebWorkers(alloc) 269 if removeBlobberId != "" { 270 jsbridge.RemoveWorker(removeBlobberId) 271 } 272 err := alloc.RepairAlloc(statusBar) 273 if err != nil { 274 return "", err 275 } 276 wg.Wait() 277 if statusBar.err != nil { 278 return "", statusBar.err 279 } 280 } 281 282 return hash, err 283 } 284 285 // updateAllocation updates the allocation settings 286 // - allocationID: allocation ID 287 // - size: new size of the allocation 288 // - extend: extend flag, whether to extend the allocation's expiration date 289 // - lock: lock value to add to the allocation 290 // - addBlobberId: blobber ID to add to the allocation 291 // - addBlobberAuthTicket: blobber auth ticket to add to the allocation, in case of restricted blobbers 292 // - removeBlobberId: blobber ID to remove from the allocation 293 // - setThirdPartyExtendable: third party extendable flag, if true, the allocation can be extended (in terms of size) by a non-owner client 294 func updateAllocation(allocationID string, 295 size int64, extend bool, 296 lock int64, 297 addBlobberId, addBlobberAuthTicket, removeBlobberId string, setThirdPartyExtendable bool) (string, error) { 298 hash, _, err := sdk.UpdateAllocation(size, extend, allocationID, uint64(lock), addBlobberId, addBlobberAuthTicket, removeBlobberId, setThirdPartyExtendable, &sdk.FileOptionsParameters{}) 299 300 if err == nil { 301 clearAllocation(allocationID) 302 } 303 304 return hash, err 305 } 306 307 // getAllocationMinLock retrieves the minimum lock value for the allocation creation, as calculated by the network. 308 // Lock value is the amount of tokens that the client needs to lock in the allocation's write pool 309 // to be able to pay for the write operations. 310 // - datashards: number of data shards 311 // - parityshards: number of parity shards. 312 // - size: size of the allocation. 313 // - maxwritePrice: maximum write price set by the client. 314 func getAllocationMinLock(datashards, parityshards int, 315 size int64, 316 maxwritePrice uint64, 317 ) (int64, error) { 318 writePrice := sdk.PriceRange{Min: 0, Max: maxwritePrice} 319 320 value, err := sdk.GetAllocationMinLock(datashards, parityshards, size, writePrice) 321 if err != nil { 322 sdkLogger.Error(err) 323 return 0, err 324 } 325 sdkLogger.Info("allocation Minlock value", value) 326 return value, nil 327 } 328 329 // getUpdateAllocationMinLock retrieves the minimum lock value for the allocation after update, as calculated by the network based on the update parameters. 330 // Lock value is the amount of tokens that the client needs to lock in the allocation's write pool 331 // to be able to pay for the write operations. 332 // - allocationID: allocation ID 333 // - size: new size of the allocation 334 // - extend: extend flag, whether to extend the allocation's expiration date 335 // - addBlobberId: blobber ID to add to the allocation 336 // - removeBlobberId: blobber ID to remove from the allocation 337 func getUpdateAllocationMinLock( 338 allocationID string, 339 size int64, 340 extend bool, 341 addBlobberId, removeBlobberId string) (int64, error) { 342 return sdk.GetUpdateAllocationMinLock(allocationID, size, extend, addBlobberId, removeBlobberId) 343 } 344 345 // getRemoteFileMap list all files in an allocation from the blobbers. 346 // - allocationID: allocation ID 347 func getRemoteFileMap(allocationID string) ([]*fileResp, error) { 348 if len(allocationID) == 0 { 349 return nil, RequiredArg("allocationID") 350 } 351 allocationObj, err := sdk.GetAllocation(allocationID) 352 if err != nil { 353 return nil, err 354 } 355 356 ref, err := allocationObj.GetRemoteFileMap(nil, "/") 357 if err != nil { 358 sdkLogger.Error(err) 359 return nil, err 360 } 361 362 fileResps := make([]*fileResp, 0) 363 for path, data := range ref { 364 paths := strings.SplitAfter(path, "/") 365 var resp = fileResp{ 366 Name: paths[len(paths)-1], 367 Path: path, 368 FileInfo: data, 369 } 370 fileResps = append(fileResps, &resp) 371 } 372 373 return fileResps, nil 374 } 375 376 // lockWritePool locks given number of tokes for given duration in write pool. 377 // - allocID: allocation id 378 // - tokens: sas tokens 379 // - fee: sas tokens 380 func lockWritePool(allocID string, tokens, fee uint64) (string, error) { 381 hash, _, err := sdk.WritePoolLock(allocID, tokens, fee) 382 return hash, err 383 } 384 385 // lockStakePool stake number of tokens for a given provider given its type and id 386 // - providerType: provider type (1: miner, 2:sharder, 3:blobber, 4:validator, 5:authorizer) 387 // - tokens: amount of tokens to lock (in SAS) 388 // - fee: transaction fees (in SAS) 389 // - providerID: provider id 390 func lockStakePool(providerType, tokens, fee uint64, providerID string) (string, error) { 391 392 hash, _, err := sdk.StakePoolLock(sdk.ProviderType(providerType), providerID, 393 tokens, fee) 394 return hash, err 395 } 396 397 // unlockWritePool unlocks the read pool 398 // - tokens: amount of tokens to lock (in SAS) 399 // - fee: transaction fees (in SAS) 400 func lockReadPool(tokens, fee uint64) (string, error) { 401 hash, _, err := sdk.ReadPoolLock(tokens, fee) 402 return hash, err 403 } 404 405 // unLockWritePool unlocks the write pool 406 // - fee: transaction fees (in SAS) 407 func unLockReadPool(fee uint64) (string, error) { 408 hash, _, err := sdk.ReadPoolUnlock(fee) 409 return hash, err 410 } 411 412 // unlockWritePool unlocks the write pool 413 // - providerType: provider type (1: miner, 2:sharder, 3:blobber, 4:validator, 5:authorizer) 414 // - fee: transaction fees (in SAS) 415 // - providerID: provider id 416 func unlockStakePool(providerType, fee uint64, providerID string) (int64, error) { 417 unstake, _, err := sdk.StakePoolUnlock(sdk.ProviderType(providerType), providerID, fee) 418 return unstake, err 419 } 420 421 func collectRewards(providerType int, providerID string) (string, error) { 422 hash, _, err := sdk.CollectRewards(providerID, sdk.ProviderType(providerType)) 423 return hash, err 424 } 425 426 // getSkatePoolInfo is to get information about the stake pool for the allocation 427 // - providerType: provider type (1: miner, 2:sharder, 3:blobber, 4:validator, 5:authorizer) 428 // - providerID: provider id 429 func getSkatePoolInfo(providerType int, providerID string) (*sdk.StakePoolInfo, error) { 430 431 info, err := sdk.GetStakePoolInfo(sdk.ProviderType(providerType), providerID) 432 433 if err != nil { 434 return nil, err 435 } 436 return info, err 437 } 438 439 // getReadPoolInfo is to get information about the read pool for the allocation 440 // - clientID: client id 441 func getReadPoolInfo(clientID string) (*sdk.ReadPool, error) { 442 readPool, err := sdk.GetReadPoolInfo(clientID) 443 if err != nil { 444 return nil, err 445 } 446 447 return readPool, nil 448 } 449 450 // getAllocationWith retrieves the information of a free or a shared allocation object given the auth ticket. 451 // A free allocation is an allocation that is created to the user using Vult app for the first time with no fees. 452 // A shared allocation is an allocation that has some shared files. The user who needs 453 // to access those files needs first to read the information of this allocation. 454 // - authTicket: auth ticket usually used by a non-owner to access a shared allocation 455 func getAllocationWith(authTicket string) (*sdk.Allocation, error) { 456 sdk.SetWasm() 457 sdkAllocation, err := sdk.GetAllocationFromAuthTicket(authTicket) 458 if err != nil { 459 return nil, err 460 } 461 return sdkAllocation, err 462 } 463 464 // decodeAuthTicket decodes the auth ticket and returns the recipient public key and the tokens 465 // - ticket: auth ticket 466 func decodeAuthTicket(ticket string) (*decodeAuthTokenResp, error) { 467 resp := &decodeAuthTokenResp{} 468 469 decoded, err := base64.StdEncoding.DecodeString(ticket) 470 if err != nil { 471 sdkLogger.Error("error decoding", err.Error()) 472 return resp, err 473 } 474 475 input := make(map[string]interface{}) 476 if err = json.Unmarshal(decoded, &input); err != nil { 477 sdkLogger.Error("error unmarshalling json", err.Error()) 478 return resp, err 479 } 480 481 if marker, ok := input["marker"]; ok { 482 str := fmt.Sprintf("%v", marker) 483 decodedMarker, _ := base64.StdEncoding.DecodeString(str) 484 markerInput := make(map[string]interface{}) 485 if err = json.Unmarshal(decodedMarker, &markerInput); err != nil { 486 sdkLogger.Error("error unmarshaling markerInput", err.Error()) 487 return resp, err 488 } 489 lock := markerInput["free_tokens"] 490 markerStr, _ := json.Marshal(markerInput) 491 resp.Marker = string(markerStr) 492 s, _ := strconv.ParseFloat(string(fmt.Sprintf("%v", lock)), 64) 493 resp.Tokens = convertTokenToSAS(s) 494 } 495 496 if public_key, ok := input["recipient_public_key"]; ok { 497 recipientPublicKey, ok := public_key.(string) 498 if !ok { 499 return resp, fmt.Errorf("recipient_public_key is required") 500 } 501 resp.RecipientPublicKey = string(recipientPublicKey) 502 } 503 504 return resp, nil 505 } 506 507 // convertTokenToSAS converts tokens in ZCN to SAS. 508 // 1 ZCN = 1e10 SAS 509 // - token: token value in ZCN 510 func convertTokenToSAS(token float64) uint64 { 511 return uint64(token * float64(TOKEN_UNIT)) 512 } 513 514 // allocationRepair issue repair process for an allocation, starting from a specific path. 515 // Repair means to sync the user's data under the allocation on all the blobbers 516 // and fill the missing data on the blobbers that have missing data. 517 // Check the system documentation for more information about the repoair process. 518 // - allocationID: allocation ID 519 // - remotePath: remote path 520 func allocationRepair(allocationID, remotePath string) error { 521 if len(allocationID) == 0 { 522 return RequiredArg("allocationID") 523 } 524 allocationObj, err := sdk.GetAllocation(allocationID) 525 if err != nil { 526 return err 527 } 528 sdk.SetWasm() 529 wg := &sync.WaitGroup{} 530 statusBar := &StatusBar{wg: wg, isRepair: true, totalBytesMap: make(map[string]int)} 531 wg.Add(1) 532 533 err = allocationObj.StartRepair("/tmp", remotePath, statusBar) 534 if err != nil { 535 PrintError("Upload failed.", err) 536 return err 537 } 538 wg.Wait() 539 if !statusBar.success { 540 return errors.New("upload failed: unknown") 541 } 542 return nil 543 } 544 545 // repairSize retrieves the repair size for a specific path in an allocation. 546 // Repair size is the size of the data that needs to be repaired in the allocation. 547 // - allocationID: allocation ID 548 // - remotePath: remote path 549 func repairSize(allocationID, remotePath string) (sdk.RepairSize, error) { 550 alloc, err := sdk.GetAllocation(allocationID) 551 if err != nil { 552 return sdk.RepairSize{}, err 553 } 554 return alloc.RepairSize(remotePath) 555 }