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 }