github.com/0chain/gosdk@v1.17.11/zboxcore/sdk/blobber_operations.go (about)

     1  //go:build !mobile
     2  // +build !mobile
     3  
     4  package sdk
     5  
     6  import (
     7  	"encoding/json"
     8  	"math"
     9  	"strings"
    10  
    11  	"github.com/0chain/errors"
    12  	"github.com/0chain/gosdk/core/transaction"
    13  	"github.com/0chain/gosdk/zboxcore/client"
    14  )
    15  
    16  // CreateAllocationForOwner creates a new allocation with the given options (txn: `storagesc.new_allocation_request`).
    17  //
    18  //   - owner is the client id of the owner of the allocation.
    19  //   - ownerpublickey is the public key of the owner of the allocation.
    20  //   - datashards is the number of data shards for the allocation.
    21  //   - parityshards is the number of parity shards for the allocation.
    22  //   - size is the size of the allocation.
    23  //   - readPrice is the read price range for the allocation (Reads in Züs are free!).
    24  //   - writePrice is the write price range for the allocation.
    25  //   - lock is the lock value for the transaction (how much tokens to lock to the allocation, in SAS).
    26  //   - preferredBlobberIds is a list of preferred blobber ids for the allocation.
    27  //   - thirdPartyExtendable is a flag indicating whether the allocation can be extended by a third party.
    28  //   - fileOptionsParams is the file options parameters for the allocation, which control the usage permissions of the files in the allocation.
    29  //
    30  // returns the hash of the transaction, the nonce of the transaction, the transaction object and an error if any.
    31  func CreateAllocationForOwner(
    32  	owner, ownerpublickey string,
    33  	datashards, parityshards int, size int64,
    34  	readPrice, writePrice PriceRange,
    35  	lock uint64, preferredBlobberIds, blobberAuthTickets []string, thirdPartyExtendable, IsEnterprise, force bool, fileOptionsParams *FileOptionsParameters,
    36  ) (hash string, nonce int64, txn *transaction.Transaction, err error) {
    37  
    38  	if lock > math.MaxInt64 {
    39  		return "", 0, nil, errors.New("invalid_lock", "int64 overflow on lock value")
    40  	}
    41  
    42  	if datashards < 1 || parityshards < 1 {
    43  		return "", 0, nil, errors.New("allocation_validation_failed", "atleast 1 data and 1 parity shards are required")
    44  	}
    45  
    46  	allocationRequest, err := getNewAllocationBlobbers(
    47  		datashards, parityshards, size, readPrice, writePrice, preferredBlobberIds, blobberAuthTickets, force)
    48  	if err != nil {
    49  		return "", 0, nil, errors.New("failed_get_allocation_blobbers", "failed to get blobbers for allocation: "+err.Error())
    50  	}
    51  
    52  	if !sdkInitialized {
    53  		return "", 0, nil, sdkNotInitialized
    54  	}
    55  
    56  	allocationRequest["owner_id"] = owner
    57  	allocationRequest["owner_public_key"] = ownerpublickey
    58  	allocationRequest["third_party_extendable"] = thirdPartyExtendable
    59  	allocationRequest["file_options_changed"], allocationRequest["file_options"] = calculateAllocationFileOptions(63 /*0011 1111*/, fileOptionsParams)
    60  	allocationRequest["is_enterprise"] = IsEnterprise
    61  
    62  	var sn = transaction.SmartContractTxnData{
    63  		Name:      transaction.NEW_ALLOCATION_REQUEST,
    64  		InputArgs: allocationRequest,
    65  	}
    66  	hash, _, nonce, txn, err = storageSmartContractTxnValue(sn, lock)
    67  	return
    68  }
    69  
    70  // CreateFreeAllocation creates a new free allocation (txn: `storagesc.free_allocation_request`).
    71  //   - marker is the marker for the free allocation.
    72  //   - value is the value of the free allocation.
    73  //
    74  // returns the hash of the transaction, the nonce of the transaction and an error if any.
    75  func CreateFreeAllocation(marker string, value uint64) (string, int64, error) {
    76  	if !sdkInitialized {
    77  		return "", 0, sdkNotInitialized
    78  	}
    79  
    80  	recipientPublicKey := client.GetClientPublicKey()
    81  
    82  	var input = map[string]interface{}{
    83  		"recipient_public_key": recipientPublicKey,
    84  		"marker":               marker,
    85  	}
    86  
    87  	blobbers, err := GetFreeAllocationBlobbers(input)
    88  	if err != nil {
    89  		return "", 0, err
    90  	}
    91  
    92  	input["blobbers"] = blobbers
    93  
    94  	var sn = transaction.SmartContractTxnData{
    95  		Name:      transaction.NEW_FREE_ALLOCATION,
    96  		InputArgs: input,
    97  	}
    98  	hash, _, n, _, err := storageSmartContractTxnValue(sn, value)
    99  	return hash, n, err
   100  }
   101  
   102  // UpdateAllocation sends an update request for an allocation (txn: `storagesc.update_allocation_request`)
   103  //
   104  //   - size is the size of the allocation.
   105  //   - extend is a flag indicating whether to extend the allocation.
   106  //   - allocationID is the id of the allocation.
   107  //   - lock is the lock value for the transaction (how much tokens to lock to the allocation, in SAS).
   108  //   - addBlobberId is the id of the blobber to add to the allocation.
   109  //   - addBlobberAuthTicket is the auth ticket of the blobber to add to the allocation, in case the blobber is restricted.
   110  //   - removeBlobberId is the id of the blobber to remove from the allocation.
   111  //   - setThirdPartyExtendable is a flag indicating whether the allocation can be extended by a third party.
   112  //   - fileOptionsParams is the file options parameters for the allocation, which control the usage permissions of the files in the allocation.
   113  //
   114  // returns the hash of the transaction, the nonce of the transaction and an error if any.
   115  func UpdateAllocation(
   116  	size int64,
   117  	extend bool,
   118  	allocationID string,
   119  	lock uint64,
   120  	addBlobberId, addBlobberAuthTicket, removeBlobberId string,
   121  	setThirdPartyExtendable bool, fileOptionsParams *FileOptionsParameters,
   122  ) (hash string, nonce int64, err error) {
   123  
   124  	if lock > math.MaxInt64 {
   125  		return "", 0, errors.New("invalid_lock", "int64 overflow on lock value")
   126  	}
   127  
   128  	if !sdkInitialized {
   129  		return "", 0, sdkNotInitialized
   130  	}
   131  
   132  	alloc, err := GetAllocation(allocationID)
   133  	if err != nil {
   134  		return "", 0, allocationNotFound
   135  	}
   136  
   137  	updateAllocationRequest := make(map[string]interface{})
   138  	updateAllocationRequest["owner_id"] = client.GetClientID()
   139  	updateAllocationRequest["owner_public_key"] = ""
   140  	updateAllocationRequest["id"] = allocationID
   141  	updateAllocationRequest["size"] = size
   142  	updateAllocationRequest["extend"] = extend
   143  	updateAllocationRequest["add_blobber_id"] = addBlobberId
   144  	updateAllocationRequest["add_blobber_auth_ticket"] = addBlobberAuthTicket
   145  	updateAllocationRequest["remove_blobber_id"] = removeBlobberId
   146  	updateAllocationRequest["set_third_party_extendable"] = setThirdPartyExtendable
   147  	updateAllocationRequest["file_options_changed"], updateAllocationRequest["file_options"] = calculateAllocationFileOptions(alloc.FileOptions, fileOptionsParams)
   148  
   149  	sn := transaction.SmartContractTxnData{
   150  		Name:      transaction.STORAGESC_UPDATE_ALLOCATION,
   151  		InputArgs: updateAllocationRequest,
   152  	}
   153  	hash, _, nonce, _, err = storageSmartContractTxnValue(sn, lock)
   154  	return
   155  }
   156  
   157  // StakePoolLock locks tokens in a stake pool.
   158  // This function is the entry point for the staking operation.
   159  // Provided the provider type and provider ID, the value is locked in the stake pool between the SDK client and the provider.
   160  // Based on the locked amount, the client will get rewards as share of the provider's rewards.
   161  //   - providerType: provider type
   162  //   - providerID: provider ID
   163  //   - value: value to lock
   164  //   - fee: transaction fee
   165  func StakePoolLock(providerType ProviderType, providerID string, value, fee uint64) (hash string, nonce int64, err error) {
   166  	if !sdkInitialized {
   167  		return "", 0, sdkNotInitialized
   168  	}
   169  
   170  	if providerType == 0 {
   171  		return "", 0, errors.New("stake_pool_lock", "provider is required")
   172  	}
   173  
   174  	if providerID == "" {
   175  		return "", 0, errors.New("stake_pool_lock", "provider_id is required")
   176  	}
   177  
   178  	spr := stakePoolRequest{
   179  		ProviderType: providerType,
   180  		ProviderID:   providerID,
   181  	}
   182  
   183  	var sn = transaction.SmartContractTxnData{
   184  		InputArgs: &spr,
   185  	}
   186  
   187  	var scAddress string
   188  	switch providerType {
   189  	case ProviderBlobber, ProviderValidator:
   190  		scAddress = STORAGE_SCADDRESS
   191  		sn.Name = transaction.STORAGESC_STAKE_POOL_LOCK
   192  	case ProviderMiner, ProviderSharder:
   193  		scAddress = MINERSC_SCADDRESS
   194  		sn.Name = transaction.MINERSC_LOCK
   195  	case ProviderAuthorizer:
   196  		scAddress = ZCNSC_SCADDRESS
   197  		sn.Name = transaction.ZCNSC_LOCK
   198  	default:
   199  		return "", 0, errors.Newf("stake_pool_lock", "unsupported provider type: %v", providerType)
   200  	}
   201  
   202  	hash, _, nonce, _, err = smartContractTxnValueFeeWithRetry(scAddress, sn, value, fee)
   203  	return
   204  }
   205  
   206  // StakePoolUnlock unlocks a stake pool tokens. If tokens can't be unlocked due
   207  // to opened offers, then it returns time where the tokens can be unlocked,
   208  // marking the pool as 'want to unlock' to avoid its usage in offers in the
   209  // future. The time is maximal time that can be lesser in some cases. To
   210  // unlock tokens can't be unlocked now, wait the time and unlock them (call
   211  // this function again).
   212  //   - providerType: provider type
   213  //   - providerID: provider ID
   214  //   - fee: transaction fee
   215  func StakePoolUnlock(providerType ProviderType, providerID string, fee uint64) (unstake int64, nonce int64, err error) {
   216  	if !sdkInitialized {
   217  		return 0, 0, sdkNotInitialized
   218  	}
   219  
   220  	if providerType == 0 {
   221  		return 0, 0, errors.New("stake_pool_lock", "provider is required")
   222  	}
   223  
   224  	if providerID == "" {
   225  		return 0, 0, errors.New("stake_pool_lock", "provider_id is required")
   226  	}
   227  
   228  	spr := stakePoolRequest{
   229  		ProviderType: providerType,
   230  		ProviderID:   providerID,
   231  	}
   232  
   233  	var sn = transaction.SmartContractTxnData{
   234  		InputArgs: &spr,
   235  	}
   236  
   237  	var scAddress string
   238  	switch providerType {
   239  	case ProviderBlobber, ProviderValidator:
   240  		scAddress = STORAGE_SCADDRESS
   241  		sn.Name = transaction.STORAGESC_STAKE_POOL_UNLOCK
   242  	case ProviderMiner, ProviderSharder:
   243  		scAddress = MINERSC_SCADDRESS
   244  		sn.Name = transaction.MINERSC_UNLOCK
   245  	case ProviderAuthorizer:
   246  		scAddress = ZCNSC_SCADDRESS
   247  		sn.Name = transaction.ZCNSC_UNLOCK
   248  	default:
   249  		return 0, 0, errors.Newf("stake_pool_unlock", "unsupported provider type: %v", providerType)
   250  	}
   251  
   252  	var out string
   253  	if _, out, nonce, _, err = smartContractTxnValueFeeWithRetry(scAddress, sn, 0, fee); err != nil {
   254  		return // an error
   255  	}
   256  
   257  	var spuu stakePoolLock
   258  	if err = json.Unmarshal([]byte(out), &spuu); err != nil {
   259  		return
   260  	}
   261  
   262  	return spuu.Amount, nonce, nil
   263  }
   264  
   265  // ReadPoolLock locks given number of tokes for given duration in read pool.
   266  //   - tokens: number of tokens to lock
   267  //   - fee: transaction fee
   268  func ReadPoolLock(tokens, fee uint64) (hash string, nonce int64, err error) {
   269  	if !sdkInitialized {
   270  		return "", 0, sdkNotInitialized
   271  	}
   272  
   273  	var sn = transaction.SmartContractTxnData{
   274  		Name:      transaction.STORAGESC_READ_POOL_LOCK,
   275  		InputArgs: nil,
   276  	}
   277  	hash, _, nonce, _, err = smartContractTxnValueFeeWithRetry(STORAGE_SCADDRESS, sn, tokens, fee)
   278  	return
   279  }
   280  
   281  // ReadPoolUnlock unlocks tokens in expired read pool
   282  //   - fee: transaction fee
   283  func ReadPoolUnlock(fee uint64) (hash string, nonce int64, err error) {
   284  	if !sdkInitialized {
   285  		return "", 0, sdkNotInitialized
   286  	}
   287  
   288  	var sn = transaction.SmartContractTxnData{
   289  		Name:      transaction.STORAGESC_READ_POOL_UNLOCK,
   290  		InputArgs: nil,
   291  	}
   292  	hash, _, nonce, _, err = smartContractTxnValueFeeWithRetry(STORAGE_SCADDRESS, sn, 0, fee)
   293  	return
   294  }
   295  
   296  //
   297  // write pool
   298  //
   299  
   300  // WritePoolLock locks given number of tokes for given duration in read pool.
   301  //   - allocID: allocation ID
   302  //   - tokens: number of tokens to lock
   303  //   - fee: transaction fee
   304  func WritePoolLock(allocID string, tokens, fee uint64) (hash string, nonce int64, err error) {
   305  	if !sdkInitialized {
   306  		return "", 0, sdkNotInitialized
   307  	}
   308  
   309  	type lockRequest struct {
   310  		AllocationID string `json:"allocation_id"`
   311  	}
   312  
   313  	var req lockRequest
   314  	req.AllocationID = allocID
   315  
   316  	var sn = transaction.SmartContractTxnData{
   317  		Name:      transaction.STORAGESC_WRITE_POOL_LOCK,
   318  		InputArgs: &req,
   319  	}
   320  
   321  	hash, _, nonce, _, err = smartContractTxnValueFeeWithRetry(STORAGE_SCADDRESS, sn, tokens, fee)
   322  	return
   323  }
   324  
   325  // WritePoolUnlock unlocks ALL tokens of a write pool. Needs to be cancelled first.
   326  //   - allocID: allocation ID
   327  //   - fee: transaction fee
   328  func WritePoolUnlock(allocID string, fee uint64) (hash string, nonce int64, err error) {
   329  	if !sdkInitialized {
   330  		return "", 0, sdkNotInitialized
   331  	}
   332  
   333  	type unlockRequest struct {
   334  		AllocationID string `json:"allocation_id"`
   335  	}
   336  
   337  	var req unlockRequest
   338  	req.AllocationID = allocID
   339  
   340  	var sn = transaction.SmartContractTxnData{
   341  		Name:      transaction.STORAGESC_WRITE_POOL_UNLOCK,
   342  		InputArgs: &req,
   343  	}
   344  	hash, _, nonce, _, err = smartContractTxnValueFeeWithRetry(STORAGE_SCADDRESS, sn, 0, fee)
   345  	return
   346  }
   347  
   348  func smartContractTxn(scAddress string, sn transaction.SmartContractTxnData) (
   349  	hash, out string, nonce int64, txn *transaction.Transaction, err error) {
   350  	return smartContractTxnValue(scAddress, sn, 0)
   351  }
   352  
   353  func StorageSmartContractTxn(sn transaction.SmartContractTxnData) (
   354  	hash, out string, nonce int64, txn *transaction.Transaction, err error) {
   355  
   356  	return storageSmartContractTxnValue(sn, 0)
   357  }
   358  
   359  func storageSmartContractTxn(sn transaction.SmartContractTxnData) (
   360  	hash, out string, nonce int64, txn *transaction.Transaction, err error) {
   361  
   362  	return storageSmartContractTxnValue(sn, 0)
   363  }
   364  
   365  func smartContractTxnValue(scAddress string, sn transaction.SmartContractTxnData, value uint64) (
   366  	hash, out string, nonce int64, txn *transaction.Transaction, err error) {
   367  
   368  	return smartContractTxnValueFeeWithRetry(scAddress, sn, value, client.TxnFee())
   369  }
   370  
   371  func storageSmartContractTxnValue(sn transaction.SmartContractTxnData, value uint64) (
   372  	hash, out string, nonce int64, txn *transaction.Transaction, err error) {
   373  
   374  	// Fee is set during sdk initialization.
   375  	return smartContractTxnValueFeeWithRetry(STORAGE_SCADDRESS, sn, value, client.TxnFee())
   376  }
   377  
   378  func smartContractTxnValueFeeWithRetry(scAddress string, sn transaction.SmartContractTxnData,
   379  	value, fee uint64) (hash, out string, nonce int64, t *transaction.Transaction, err error) {
   380  	hash, out, nonce, t, err = smartContractTxnValueFee(scAddress, sn, value, fee)
   381  
   382  	if err != nil && strings.Contains(err.Error(), "invalid transaction nonce") {
   383  		return smartContractTxnValueFee(scAddress, sn, value, fee)
   384  	}
   385  	return
   386  }
   387  
   388  func smartContractTxnValueFee(scAddress string, sn transaction.SmartContractTxnData,
   389  	value, fee uint64) (hash, out string, nonce int64, t *transaction.Transaction, err error) {
   390  	t, err = ExecuteSmartContract(scAddress, sn, value, fee)
   391  	if err != nil {
   392  		if t != nil {
   393  			return "", "", t.TransactionNonce, nil, err
   394  		}
   395  
   396  		return "", "", 0, nil, err
   397  	}
   398  
   399  	return t.Hash, t.TransactionOutput, t.TransactionNonce, t, nil
   400  }