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  }