github.com/0chain/gosdk@v1.17.11/zboxcore/sdk/sdk.go (about) 1 package sdk 2 3 import ( 4 "context" 5 "encoding/base64" 6 "encoding/json" 7 "fmt" 8 "io/ioutil" 9 "math" 10 "net/http" 11 "strconv" 12 13 "github.com/0chain/common/core/currency" 14 "github.com/0chain/errors" 15 "github.com/0chain/gosdk/core/conf" 16 "github.com/0chain/gosdk/core/logger" 17 "github.com/0chain/gosdk/core/node" 18 "gopkg.in/natefinch/lumberjack.v2" 19 20 "github.com/0chain/gosdk/core/common" 21 enc "github.com/0chain/gosdk/core/encryption" 22 "github.com/0chain/gosdk/core/transaction" 23 "github.com/0chain/gosdk/core/version" 24 "github.com/0chain/gosdk/zboxcore/blockchain" 25 "github.com/0chain/gosdk/zboxcore/client" 26 "github.com/0chain/gosdk/zboxcore/encryption" 27 l "github.com/0chain/gosdk/zboxcore/logger" 28 "github.com/0chain/gosdk/zboxcore/marker" 29 "github.com/0chain/gosdk/zboxcore/zboxutil" 30 ) 31 32 const STORAGE_SCADDRESS = "6dba10422e368813802877a85039d3985d96760ed844092319743fb3a76712d7" 33 const MINERSC_SCADDRESS = "6dba10422e368813802877a85039d3985d96760ed844092319743fb3a76712d9" 34 const ZCNSC_SCADDRESS = "6dba10422e368813802877a85039d3985d96760ed844092319743fb3a76712e0" 35 36 var sdkNotInitialized = errors.New("sdk_not_initialized", "SDK is not initialised") 37 var allocationNotFound = errors.New("couldnt_find_allocation", "Couldn't find the allocation required for update") 38 39 const ( 40 OpUpload int = 0 41 OpDownload int = 1 42 OpRepair int = 2 43 OpUpdate int = 3 44 opThumbnailDownload int = 4 45 ) 46 47 type StatusCallback interface { 48 Started(allocationId, filePath string, op int, totalBytes int) 49 InProgress(allocationId, filePath string, op int, completedBytes int, data []byte) 50 Error(allocationID string, filePath string, op int, err error) 51 Completed(allocationId, filePath string, filename string, mimetype string, size int, op int) 52 RepairCompleted(filesRepaired int) 53 } 54 55 var ( 56 numBlockDownloads = 100 57 sdkInitialized = false 58 networkWorkerTimerInHours = 1 59 singleClientMode = false 60 shouldVerifyHash = true 61 ) 62 63 func SetSingleClietnMode(mode bool) { 64 singleClientMode = mode 65 } 66 67 func SetShouldVerifyHash(verify bool) { 68 shouldVerifyHash = verify 69 } 70 71 func SetSaveProgress(save bool) { 72 shouldSaveProgress = save 73 } 74 75 // GetVersion - returns version string 76 func GetVersion() string { 77 return version.VERSIONSTR 78 } 79 80 // SetLogLevel set the log level. 81 // - lvl: 0 disabled; higher number (upto 4) more verbosity 82 func SetLogLevel(lvl int) { 83 l.Logger.SetLevel(lvl) 84 } 85 86 // SetLogFile set the log file and verbosity levels 87 // - logFile: Log file 88 // - verbose: true - console output; false - no console output 89 func SetLogFile(logFile string, verbose bool) { 90 var ioWriter = &lumberjack.Logger{ 91 Filename: logFile, 92 MaxSize: 100, // MB 93 MaxBackups: 5, // number of backups 94 MaxAge: 28, //days 95 LocalTime: false, 96 Compress: false, // disabled by default 97 } 98 99 l.Logger.SetLogFile(ioWriter, verbose) 100 l.Logger.Info("******* Storage SDK Version: ", version.VERSIONSTR, " *******") 101 } 102 103 // GetLogger retrieves logger instance 104 func GetLogger() *logger.Logger { 105 return &l.Logger 106 } 107 108 // InitStorageSDK Initialize the storage SDK 109 // 110 // - walletJSON: Client's wallet JSON 111 // - blockWorker: Block worker URL (block worker refers to 0DNS) 112 // - chainID: ID of the blokcchain network 113 // - signatureScheme: Signature scheme that will be used for signing transactions 114 // - preferredBlobbers: List of preferred blobbers to use when creating an allocation. This is usually configured by the client in the configuration files 115 // - nonce: Initial nonce value for the transactions 116 // - fee: Preferred value for the transaction fee, just the first value is taken 117 func InitStorageSDK(walletJSON string, 118 blockWorker, chainID, signatureScheme string, 119 preferredBlobbers []string, 120 nonce int64, 121 fee ...uint64) error { 122 err := client.PopulateClient(walletJSON, signatureScheme) 123 if err != nil { 124 return err 125 } 126 127 blockchain.SetChainID(chainID) 128 blockchain.SetBlockWorker(blockWorker) 129 130 err = InitNetworkDetails() 131 if err != nil { 132 return err 133 } 134 135 client.SetClientNonce(nonce) 136 if len(fee) > 0 { 137 client.SetTxnFee(fee[0]) 138 } 139 140 go UpdateNetworkDetailsWorker(context.Background()) 141 sdkInitialized = true 142 return nil 143 } 144 145 // GetNetwork retrieves the network details 146 func GetNetwork() *Network { 147 return &Network{ 148 Miners: blockchain.GetMiners(), 149 Sharders: blockchain.GetAllSharders(), 150 } 151 } 152 153 // SetMaxTxnQuery set the maximum number of transactions to query 154 func SetMaxTxnQuery(num int) { 155 blockchain.SetMaxTxnQuery(num) 156 157 cfg, _ := conf.GetClientConfig() 158 if cfg != nil { 159 cfg.MaxTxnQuery = num 160 } 161 162 } 163 164 // SetQuerySleepTime set the sleep time between queries 165 func SetQuerySleepTime(time int) { 166 blockchain.SetQuerySleepTime(time) 167 168 cfg, _ := conf.GetClientConfig() 169 if cfg != nil { 170 cfg.QuerySleepTime = time 171 } 172 173 } 174 175 // SetMinSubmit set the minimum number of miners to submit the transaction 176 func SetMinSubmit(num int) { 177 blockchain.SetMinSubmit(num) 178 } 179 180 // SetMinConfirmation set the minimum number of miners to confirm the transaction 181 func SetMinConfirmation(num int) { 182 blockchain.SetMinConfirmation(num) 183 } 184 185 // SetNetwork set the network details, given the miners and sharders urls 186 // - miners: list of miner urls 187 // - sharders: list of sharder urls 188 func SetNetwork(miners []string, sharders []string) { 189 blockchain.SetMiners(miners) 190 blockchain.SetSharders(sharders) 191 node.InitCache(blockchain.Sharders) 192 } 193 194 // CreateReadPool creates a read pool for the SDK client. 195 // Read pool is used to lock tokens for read operations. 196 // Currently, all read operations are free 🚀. 197 func CreateReadPool() (hash string, nonce int64, err error) { 198 if !sdkInitialized { 199 return "", 0, sdkNotInitialized 200 } 201 hash, _, nonce, _, err = storageSmartContractTxn(transaction.SmartContractTxnData{ 202 Name: transaction.STORAGESC_CREATE_READ_POOL, 203 }) 204 return 205 } 206 207 type BackPool struct { 208 ID string `json:"id"` 209 Balance common.Balance `json:"balance"` 210 } 211 212 // 213 // read pool 214 // 215 216 type ReadPool struct { 217 Balance common.Balance `json:"balance"` 218 } 219 220 // GetReadPoolInfo for given client, or, if the given clientID is empty, 221 // for current client of the sdk. 222 // - clientID: client ID 223 func GetReadPoolInfo(clientID string) (info *ReadPool, err error) { 224 if !sdkInitialized { 225 return nil, sdkNotInitialized 226 } 227 228 if clientID == "" { 229 clientID = client.GetClientID() 230 } 231 232 var b []byte 233 b, err = zboxutil.MakeSCRestAPICall(STORAGE_SCADDRESS, "/getReadPoolStat", 234 map[string]string{"client_id": clientID}, nil) 235 if err != nil { 236 return nil, errors.Wrap(err, "error requesting read pool info") 237 } 238 if len(b) == 0 { 239 return nil, errors.New("", "empty response") 240 } 241 242 info = new(ReadPool) 243 if err = json.Unmarshal(b, info); err != nil { 244 return nil, errors.Wrap(err, "error decoding response:") 245 } 246 247 return 248 } 249 250 // 251 // stake pool 252 // 253 254 // StakePoolOfferInfo represents stake pool offer information. 255 type StakePoolOfferInfo struct { 256 Lock common.Balance `json:"lock"` 257 Expire common.Timestamp `json:"expire"` 258 AllocationID common.Key `json:"allocation_id"` 259 IsExpired bool `json:"is_expired"` 260 } 261 262 // StakePoolRewardsInfo represents stake pool rewards. 263 type StakePoolRewardsInfo struct { 264 Charge common.Balance `json:"charge"` // total for all time 265 Blobber common.Balance `json:"blobber"` // total for all time 266 Validator common.Balance `json:"validator"` // total for all time 267 } 268 269 // StakePoolDelegatePoolInfo represents delegate pool of a stake pool info. 270 type StakePoolDelegatePoolInfo struct { 271 ID common.Key `json:"id"` // blobber ID 272 Balance common.Balance `json:"balance"` // current balance 273 DelegateID common.Key `json:"delegate_id"` // wallet 274 Rewards common.Balance `json:"rewards"` // current 275 UnStake bool `json:"unstake"` // want to unstake 276 277 TotalReward common.Balance `json:"total_reward"` 278 TotalPenalty common.Balance `json:"total_penalty"` 279 Status string `json:"status"` 280 RoundCreated int64 `json:"round_created"` 281 StakedAt common.Timestamp `json:"staked_at"` 282 } 283 284 // StakePool information of stake pool of a provider. 285 type StakePoolInfo struct { 286 ID common.Key `json:"pool_id"` // pool ID 287 Balance common.Balance `json:"balance"` // total balance 288 StakeTotal common.Balance `json:"stake_total"` 289 // delegate pools 290 Delegate []StakePoolDelegatePoolInfo `json:"delegate"` 291 // rewards 292 Rewards common.Balance `json:"rewards"` 293 // total rewards 294 TotalRewards common.Balance `json:"total_rewards"` 295 // Settings of the stake pool 296 Settings blockchain.StakePoolSettings `json:"settings"` 297 } 298 299 // GetStakePoolInfo retrieve stake pool info for the current client configured to the sdk, given provider type and provider ID. 300 // - providerType: provider type 301 // - providerID: provider ID 302 func GetStakePoolInfo(providerType ProviderType, providerID string) (info *StakePoolInfo, err error) { 303 if !sdkInitialized { 304 return nil, sdkNotInitialized 305 } 306 307 var b []byte 308 b, err = zboxutil.MakeSCRestAPICall(STORAGE_SCADDRESS, "/getStakePoolStat", 309 map[string]string{"provider_type": strconv.Itoa(int(providerType)), "provider_id": providerID}, nil) 310 if err != nil { 311 return nil, errors.Wrap(err, "error requesting stake pool info:") 312 } 313 if len(b) == 0 { 314 return nil, errors.New("", "empty response") 315 } 316 317 info = new(StakePoolInfo) 318 if err = json.Unmarshal(b, info); err != nil { 319 return nil, errors.Wrap(err, "error decoding response:") 320 } 321 322 return 323 } 324 325 // StakePoolUserInfo represents user stake pools statistic. 326 type StakePoolUserInfo struct { 327 Pools map[common.Key][]*StakePoolDelegatePoolInfo `json:"pools"` 328 } 329 330 // GetStakePoolUserInfo obtains blobbers/validators delegate pools statistic for a user. 331 // If given clientID is empty string, then current client used. 332 // - clientID: client ID 333 // - offset: offset 334 // - limit: limit 335 func GetStakePoolUserInfo(clientID string, offset, limit int) (info *StakePoolUserInfo, err error) { 336 if !sdkInitialized { 337 return nil, sdkNotInitialized 338 } 339 if clientID == "" { 340 clientID = client.GetClientID() 341 } 342 343 var b []byte 344 params := map[string]string{ 345 "client_id": clientID, 346 "offset": strconv.FormatInt(int64(offset), 10), 347 "limit": strconv.FormatInt(int64(limit), 10), 348 } 349 b, err = zboxutil.MakeSCRestAPICall(STORAGE_SCADDRESS, 350 "/getUserStakePoolStat", params, nil) 351 if err != nil { 352 return nil, errors.Wrap(err, "error requesting stake pool user info:") 353 } 354 if len(b) == 0 { 355 return nil, errors.New("", "empty response") 356 } 357 358 info = new(StakePoolUserInfo) 359 if err = json.Unmarshal(b, info); err != nil { 360 return nil, errors.Wrap(err, "error decoding response:") 361 } 362 363 return 364 } 365 366 type stakePoolRequest struct { 367 ProviderType ProviderType `json:"provider_type,omitempty"` 368 ProviderID string `json:"provider_id,omitempty"` 369 } 370 371 // stakePoolLock is stake pool unlock response in case where tokens 372 // can't be unlocked due to opened offers. 373 type stakePoolLock struct { 374 Client string `json:"client"` 375 ProviderId string `json:"provider_id"` 376 ProviderType ProviderType `json:"provider_type"` 377 Amount int64 `json:"amount"` 378 } 379 380 // 381 // challenge pool 382 // 383 384 // ChallengePoolInfo represents a challenge pool stat. 385 type ChallengePoolInfo struct { 386 ID string `json:"id"` 387 Balance common.Balance `json:"balance"` 388 StartTime common.Timestamp `json:"start_time"` 389 Expiration common.Timestamp `json:"expiration"` 390 Finalized bool `json:"finalized"` 391 } 392 393 // GetChallengePoolInfo retrieve challenge pool info for given allocation. 394 // - allocID: allocation ID 395 func GetChallengePoolInfo(allocID string) (info *ChallengePoolInfo, err error) { 396 if !sdkInitialized { 397 return nil, sdkNotInitialized 398 } 399 400 var b []byte 401 b, err = zboxutil.MakeSCRestAPICall(STORAGE_SCADDRESS, 402 "/getChallengePoolStat", map[string]string{"allocation_id": allocID}, 403 nil) 404 if err != nil { 405 return nil, errors.Wrap(err, "error requesting challenge pool info:") 406 } 407 if len(b) == 0 { 408 return nil, errors.New("", "empty response") 409 } 410 411 info = new(ChallengePoolInfo) 412 if err = json.Unmarshal(b, info); err != nil { 413 return nil, errors.Wrap(err, "error decoding response:") 414 } 415 416 return 417 } 418 419 // GetMptData retrieves mpt key data. 420 func GetMptData(key string) ([]byte, error) { 421 if !sdkInitialized { 422 return nil, sdkNotInitialized 423 } 424 425 var b []byte 426 b, err := zboxutil.MakeSCRestAPICall(STORAGE_SCADDRESS, 427 "/get_mpt_key", map[string]string{"key": key}, 428 nil, 429 ) 430 if err != nil { 431 return nil, errors.Wrap(err, "error requesting mpt key data:") 432 } 433 if len(b) == 0 { 434 return nil, errors.New("", "empty response") 435 } 436 437 return b, nil 438 } 439 440 // 441 // storage SC configurations and blobbers 442 // 443 444 type InputMap struct { 445 Fields map[string]interface{} `json:"fields"` 446 } 447 448 // GetStorageSCConfig retrieves storage SC configurations. 449 func GetStorageSCConfig() (conf *InputMap, err error) { 450 if !sdkInitialized { 451 return nil, sdkNotInitialized 452 } 453 454 var b []byte 455 b, err = zboxutil.MakeSCRestAPICall(STORAGE_SCADDRESS, "/storage-config", nil, 456 nil) 457 if err != nil { 458 return nil, errors.Wrap(err, "error requesting storage SC configs:") 459 } 460 if len(b) == 0 { 461 return nil, errors.New("", "empty response") 462 } 463 464 conf = new(InputMap) 465 conf.Fields = make(map[string]interface{}) 466 if err = json.Unmarshal(b, conf); err != nil { 467 return nil, errors.Wrap(err, "rror decoding response:") 468 } 469 470 return 471 } 472 473 // Blobber type represents blobber information. 474 type Blobber struct { 475 // ID of the blobber 476 ID common.Key `json:"id"` 477 478 // BaseURL of the blobber 479 BaseURL string `json:"url"` 480 481 // Terms of the blobber 482 Terms Terms `json:"terms"` 483 484 // Capacity of the blobber 485 Capacity common.Size `json:"capacity"` 486 487 // Allocated size of the blobber 488 Allocated common.Size `json:"allocated"` 489 490 // LastHealthCheck of the blobber 491 LastHealthCheck common.Timestamp `json:"last_health_check"` 492 493 // PublicKey of the blobber 494 PublicKey string `json:"-"` 495 496 // StakePoolSettings settings of the blobber staking 497 StakePoolSettings blockchain.StakePoolSettings `json:"stake_pool_settings"` 498 499 // TotalStake of the blobber in SAS 500 TotalStake int64 `json:"total_stake"` 501 502 // UsedAllocation of the blobber in SAS 503 UsedAllocation int64 `json:"used_allocation"` 504 505 // TotalOffers of the blobber in SAS 506 TotalOffers int64 `json:"total_offers"` 507 508 // TotalServiceCharge of the blobber in SAS 509 TotalServiceCharge int64 `json:"total_service_charge"` 510 511 // UncollectedServiceCharge of the blobber in SAS 512 UncollectedServiceCharge int64 `json:"uncollected_service_charge"` 513 514 // IsKilled flag of the blobber, if true then the blobber is killed 515 IsKilled bool `json:"is_killed"` 516 517 // IsShutdown flag of the blobber, if true then the blobber is shutdown 518 IsShutdown bool `json:"is_shutdown"` 519 520 // NotAvailable flag of the blobber, if true then the blobber is not available 521 NotAvailable bool `json:"not_available"` 522 523 // IsRestricted flag of the blobber, if true then the blobber is restricted 524 IsRestricted bool `json:"is_restricted"` 525 } 526 527 // UpdateBlobber is used during update blobber settings calls. 528 // Note the types are of pointer types with omitempty json property. 529 // This is done to correctly identify which properties are actually changing. 530 type UpdateBlobber struct { 531 ID common.Key `json:"id"` 532 BaseURL *string `json:"url,omitempty"` 533 Terms *UpdateTerms `json:"terms,omitempty"` 534 Capacity *common.Size `json:"capacity,omitempty"` 535 Allocated *common.Size `json:"allocated,omitempty"` 536 LastHealthCheck *common.Timestamp `json:"last_health_check,omitempty"` 537 StakePoolSettings *blockchain.UpdateStakePoolSettings `json:"stake_pool_settings,omitempty"` 538 TotalStake *int64 `json:"total_stake,omitempty"` 539 UsedAllocation *int64 `json:"used_allocation,omitempty"` 540 TotalOffers *int64 `json:"total_offers,omitempty"` 541 TotalServiceCharge *int64 `json:"total_service_charge,omitempty"` 542 UncollectedServiceCharge *int64 `json:"uncollected_service_charge,omitempty"` 543 IsKilled *bool `json:"is_killed,omitempty"` 544 IsShutdown *bool `json:"is_shutdown,omitempty"` 545 NotAvailable *bool `json:"not_available,omitempty"` 546 IsRestricted *bool `json:"is_restricted,omitempty"` 547 } 548 549 // ResetBlobberStatsDto represents blobber stats reset request. 550 type ResetBlobberStatsDto struct { 551 BlobberID string `json:"blobber_id"` 552 PrevAllocated int64 `json:"prev_allocated"` 553 PrevSavedData int64 `json:"prev_saved_data"` 554 NewAllocated int64 `json:"new_allocated"` 555 NewSavedData int64 `json:"new_saved_data"` 556 } 557 558 // Validator represents validator information. 559 type Validator struct { 560 ID common.Key `json:"validator_id"` 561 BaseURL string `json:"url"` 562 PublicKey string `json:"-"` 563 DelegateWallet string `json:"delegate_wallet"` 564 MinStake common.Balance `json:"min_stake"` 565 MaxStake common.Balance `json:"max_stake"` 566 NumDelegates int `json:"num_delegates"` 567 ServiceCharge float64 `json:"service_charge"` 568 StakeTotal int64 `json:"stake_total"` 569 TotalServiceCharge int64 `json:"total_service_charge"` 570 UncollectedServiceCharge int64 `json:"uncollected_service_charge"` 571 LastHealthCheck common.Timestamp `json:"last_health_check"` 572 IsKilled bool `json:"is_killed"` 573 IsShutdown bool `json:"is_shutdown"` 574 } 575 576 // UpdateValidator is used during update validator settings calls. 577 // Note the types are of pointer types with omitempty json property. 578 // This is done to correctly identify which properties are actually changing. 579 type UpdateValidator struct { 580 ID common.Key `json:"validator_id"` 581 BaseURL *string `json:"url,omitempty"` 582 DelegateWallet *string `json:"delegate_wallet,omitempty"` 583 MinStake *common.Balance `json:"min_stake,omitempty"` 584 MaxStake *common.Balance `json:"max_stake,omitempty"` 585 NumDelegates *int `json:"num_delegates,omitempty"` 586 ServiceCharge *float64 `json:"service_charge,omitempty"` 587 StakeTotal *int64 `json:"stake_total,omitempty"` 588 TotalServiceCharge *int64 `json:"total_service_charge,omitempty"` 589 UncollectedServiceCharge *int64 `json:"uncollected_service_charge,omitempty"` 590 LastHealthCheck *common.Timestamp `json:"last_health_check,omitempty"` 591 IsKilled *bool `json:"is_killed,omitempty"` 592 IsShutdown *bool `json:"is_shutdown,omitempty"` 593 } 594 595 // ConvertToValidationNode converts UpdateValidator request to blockchain.UpdateValidationNode. 596 func (v *UpdateValidator) ConvertToValidationNode() *blockchain.UpdateValidationNode { 597 blockValidator := &blockchain.UpdateValidationNode{ 598 ID: string(v.ID), 599 BaseURL: v.BaseURL, 600 } 601 602 sp := &blockchain.UpdateStakePoolSettings{ 603 DelegateWallet: v.DelegateWallet, 604 NumDelegates: v.NumDelegates, 605 ServiceCharge: v.ServiceCharge, 606 } 607 608 if v.DelegateWallet != nil || 609 v.MinStake != nil || 610 v.MaxStake != nil || 611 v.NumDelegates != nil || 612 v.ServiceCharge != nil { 613 blockValidator.StakePoolSettings = sp 614 } 615 616 return blockValidator 617 } 618 619 func getBlobbersInternal(active, stakable bool, limit, offset int) (bs []*Blobber, err error) { 620 type nodes struct { 621 Nodes []*Blobber 622 } 623 624 url := fmt.Sprintf("/getblobbers?active=%s&limit=%d&offset=%d&stakable=%s", 625 strconv.FormatBool(active), 626 limit, 627 offset, 628 strconv.FormatBool(stakable), 629 ) 630 b, err := zboxutil.MakeSCRestAPICall(STORAGE_SCADDRESS, url, nil, nil) 631 var wrap nodes 632 if err != nil { 633 return nil, errors.Wrap(err, "error requesting blobbers:") 634 } 635 if len(b) == 0 { 636 return nil, errors.New("", "empty response") 637 } 638 639 if err = json.Unmarshal(b, &wrap); err != nil { 640 return nil, errors.Wrap(err, "error decoding response:") 641 } 642 643 return wrap.Nodes, nil 644 } 645 646 // GetBlobbers returns list of blobbers. 647 // - active: if true then only active blobbers are returned 648 // - stakable: if true then only stakable blobbers are returned 649 func GetBlobbers(active, stakable bool) (bs []*Blobber, err error) { 650 if !sdkInitialized { 651 return nil, sdkNotInitialized 652 } 653 654 limit, offset := 20, 0 655 656 blobbers, err := getBlobbersInternal(active, stakable, limit, offset) 657 if err != nil { 658 return nil, err 659 } 660 661 var blobbersSl []*Blobber 662 blobbersSl = append(blobbersSl, blobbers...) 663 for { 664 // if the len of output returned is less than the limit it means this is the last round of pagination 665 if len(blobbers) < limit { 666 break 667 } 668 669 // get the next set of blobbers 670 offset += 20 671 blobbers, err = getBlobbersInternal(active, stakable, limit, offset) 672 if err != nil { 673 return blobbers, err 674 } 675 blobbersSl = append(blobbersSl, blobbers...) 676 677 } 678 return blobbersSl, nil 679 } 680 681 // GetBlobber retrieve blobber by id. 682 // - blobberID: the id of blobber 683 func GetBlobber(blobberID string) (blob *Blobber, err error) { 684 if !sdkInitialized { 685 return nil, sdkNotInitialized 686 } 687 var b []byte 688 b, err = zboxutil.MakeSCRestAPICall( 689 STORAGE_SCADDRESS, 690 "/getBlobber", 691 map[string]string{"blobber_id": blobberID}, 692 nil) 693 if err != nil { 694 return nil, errors.Wrap(err, "requesting blobber:") 695 } 696 if len(b) == 0 { 697 return nil, errors.New("", "empty response from sharders") 698 } 699 blob = new(Blobber) 700 if err = json.Unmarshal(b, blob); err != nil { 701 return nil, errors.Wrap(err, "decoding response:") 702 } 703 return 704 } 705 706 // GetValidator retrieve validator instance by id. 707 // - validatorID: the id of validator 708 func GetValidator(validatorID string) (validator *Validator, err error) { 709 if !sdkInitialized { 710 return nil, sdkNotInitialized 711 } 712 var b []byte 713 b, err = zboxutil.MakeSCRestAPICall( 714 STORAGE_SCADDRESS, 715 "/get_validator", 716 map[string]string{"validator_id": validatorID}, 717 nil) 718 if err != nil { 719 return nil, errors.Wrap(err, "requesting validator:") 720 } 721 if len(b) == 0 { 722 return nil, errors.New("", "empty response from sharders") 723 } 724 validator = new(Validator) 725 if err = json.Unmarshal(b, validator); err != nil { 726 return nil, errors.Wrap(err, "decoding response:") 727 } 728 return 729 } 730 731 // GetValidators returns list of validators. 732 // - stakable: if true then only stakable validators are returned 733 func GetValidators(stakable bool) (validators []*Validator, err error) { 734 if !sdkInitialized { 735 return nil, sdkNotInitialized 736 } 737 var b []byte 738 b, err = zboxutil.MakeSCRestAPICall( 739 STORAGE_SCADDRESS, 740 "/validators", 741 map[string]string{ 742 "stakable": strconv.FormatBool(stakable), 743 }, 744 nil) 745 if err != nil { 746 return nil, errors.Wrap(err, "requesting validator list") 747 } 748 if len(b) == 0 { 749 return nil, errors.New("", "empty response from sharders") 750 } 751 if err = json.Unmarshal(b, &validators); err != nil { 752 return nil, errors.Wrap(err, "decoding response:") 753 } 754 return 755 } 756 757 // GetClientEncryptedPublicKey - get the client's public key 758 func GetClientEncryptedPublicKey() (string, error) { 759 if !sdkInitialized { 760 return "", sdkNotInitialized 761 } 762 encScheme := encryption.NewEncryptionScheme() 763 _, err := encScheme.Initialize(client.GetClient().Mnemonic) 764 if err != nil { 765 return "", err 766 } 767 return encScheme.GetPublicKey() 768 } 769 770 // GetAllocationFromAuthTicket - get allocation from given auth ticket hash. 771 // AuthTicket is used to access free allocations, and it's generated by the Free Storage Assigner. 772 // - authTicket: the auth ticket hash 773 // 774 // returns the allocation instance and error if any 775 func GetAllocationFromAuthTicket(authTicket string) (*Allocation, error) { 776 if !sdkInitialized { 777 return nil, sdkNotInitialized 778 } 779 sEnc, err := base64.StdEncoding.DecodeString(authTicket) 780 if err != nil { 781 return nil, errors.New("auth_ticket_decode_error", "Error decoding the auth ticket."+err.Error()) 782 } 783 at := &marker.AuthTicket{} 784 err = json.Unmarshal(sEnc, at) 785 if err != nil { 786 return nil, errors.New("auth_ticket_decode_error", "Error unmarshaling the auth ticket."+err.Error()) 787 } 788 return GetAllocation(at.AllocationID) 789 } 790 791 // GetAllocation - get allocation from given allocation id 792 // 793 // - allocationID: the allocation id 794 // 795 // returns the allocation instance and error if any 796 func GetAllocation(allocationID string) (*Allocation, error) { 797 if !sdkInitialized { 798 return nil, sdkNotInitialized 799 } 800 params := make(map[string]string) 801 params["allocation"] = allocationID 802 allocationBytes, err := zboxutil.MakeSCRestAPICall(STORAGE_SCADDRESS, "/allocation", params, nil) 803 if err != nil { 804 return nil, errors.New("allocation_fetch_error", "Error fetching the allocation."+err.Error()) 805 } 806 allocationObj := &Allocation{} 807 err = json.Unmarshal(allocationBytes, allocationObj) 808 if err != nil { 809 return nil, errors.New("allocation_decode_error", "Error decoding the allocation: "+err.Error()+" "+string(allocationBytes)) 810 } 811 hashdata := allocationObj.Tx 812 sig, ok := zboxutil.SignCache.Get(hashdata) 813 if !ok { 814 sig, err = client.Sign(enc.Hash(hashdata)) 815 zboxutil.SignCache.Add(hashdata, sig) 816 if err != nil { 817 return nil, err 818 } 819 } 820 821 allocationObj.sig = sig 822 allocationObj.numBlockDownloads = numBlockDownloads 823 allocationObj.InitAllocation() 824 return allocationObj, nil 825 } 826 827 func GetAllocationUpdates(allocation *Allocation) error { 828 if allocation == nil { 829 return errors.New("allocation_not_initialized", "") 830 } 831 832 params := make(map[string]string) 833 params["allocation"] = allocation.ID 834 allocationBytes, err := zboxutil.MakeSCRestAPICall(STORAGE_SCADDRESS, "/allocation", params, nil) 835 if err != nil { 836 return errors.New("allocation_fetch_error", "Error fetching the allocation."+err.Error()) 837 } 838 839 updatedAllocationObj := new(Allocation) 840 if err := json.Unmarshal(allocationBytes, updatedAllocationObj); err != nil { 841 return errors.New("allocation_decode_error", "Error decoding the allocation."+err.Error()) 842 } 843 844 allocation.DataShards = updatedAllocationObj.DataShards 845 allocation.ParityShards = updatedAllocationObj.ParityShards 846 allocation.Size = updatedAllocationObj.Size 847 allocation.Expiration = updatedAllocationObj.Expiration 848 allocation.Payer = updatedAllocationObj.Payer 849 allocation.Blobbers = updatedAllocationObj.Blobbers 850 allocation.Stats = updatedAllocationObj.Stats 851 allocation.TimeUnit = updatedAllocationObj.TimeUnit 852 allocation.BlobberDetails = updatedAllocationObj.BlobberDetails 853 allocation.ReadPriceRange = updatedAllocationObj.ReadPriceRange 854 allocation.WritePriceRange = updatedAllocationObj.WritePriceRange 855 allocation.ChallengeCompletionTime = updatedAllocationObj.ChallengeCompletionTime 856 allocation.StartTime = updatedAllocationObj.StartTime 857 allocation.Finalized = updatedAllocationObj.Finalized 858 allocation.Canceled = updatedAllocationObj.Canceled 859 allocation.MovedToChallenge = updatedAllocationObj.MovedToChallenge 860 allocation.MovedBack = updatedAllocationObj.MovedBack 861 allocation.MovedToValidators = updatedAllocationObj.MovedToValidators 862 allocation.FileOptions = updatedAllocationObj.FileOptions 863 allocation.IsEnterprise = updatedAllocationObj.IsEnterprise 864 return nil 865 } 866 867 // SetNumBlockDownloads - set the number of block downloads, needs to be between 1 and 500 (inclusive). Default is 20. 868 // - num: the number of block downloads 869 func SetNumBlockDownloads(num int) { 870 if num > 0 && num <= 500 { 871 numBlockDownloads = num 872 } 873 } 874 875 // GetAllocations - get all allocations for the current client 876 // 877 // returns the list of allocations and error if any 878 func GetAllocations() ([]*Allocation, error) { 879 return GetAllocationsForClient(client.GetClientID()) 880 } 881 882 func getAllocationsInternal(clientID string, limit, offset int) ([]*Allocation, error) { 883 params := make(map[string]string) 884 params["client"] = clientID 885 params["limit"] = fmt.Sprint(limit) 886 params["offset"] = fmt.Sprint(offset) 887 allocationsBytes, err := zboxutil.MakeSCRestAPICall(STORAGE_SCADDRESS, "/allocations", params, nil) 888 if err != nil { 889 return nil, errors.New("allocations_fetch_error", "Error fetching the allocations."+err.Error()) 890 } 891 allocations := make([]*Allocation, 0) 892 err = json.Unmarshal(allocationsBytes, &allocations) 893 if err != nil { 894 return nil, errors.New("allocations_decode_error", "Error decoding the allocations."+err.Error()) 895 } 896 return allocations, nil 897 } 898 899 // GetAllocationsForClient - get all allocations for given client id 900 // 901 // - clientID: the client id 902 // 903 // returns the list of allocations and error if any 904 func GetAllocationsForClient(clientID string) ([]*Allocation, error) { 905 if !sdkInitialized { 906 return nil, sdkNotInitialized 907 } 908 limit, offset := 20, 0 909 910 allocations, err := getAllocationsInternal(clientID, limit, offset) 911 if err != nil { 912 return nil, err 913 } 914 915 var allocationsFin []*Allocation 916 allocationsFin = append(allocationsFin, allocations...) 917 for { 918 // if the len of output returned is less than the limit it means this is the last round of pagination 919 if len(allocations) < limit { 920 break 921 } 922 923 // get the next set of blobbers 924 offset += 20 925 allocations, err = getAllocationsInternal(clientID, limit, offset) 926 if err != nil { 927 return allocations, err 928 } 929 allocationsFin = append(allocationsFin, allocations...) 930 931 } 932 return allocationsFin, nil 933 } 934 935 type FileOptionParam struct { 936 Changed bool 937 Value bool 938 } 939 940 // FileOptionsParameters is used to specify the file options parameters for an allocation, which control the usage permissions of the files in the allocation. 941 type FileOptionsParameters struct { 942 ForbidUpload FileOptionParam 943 ForbidDelete FileOptionParam 944 ForbidUpdate FileOptionParam 945 ForbidMove FileOptionParam 946 ForbidCopy FileOptionParam 947 ForbidRename FileOptionParam 948 } 949 950 // CreateAllocationOptions is used to specify the options for creating a new allocation. 951 type CreateAllocationOptions struct { 952 DataShards int 953 ParityShards int 954 Size int64 955 ReadPrice PriceRange 956 WritePrice PriceRange 957 Lock uint64 958 BlobberIds []string 959 BlobberAuthTickets []string 960 ThirdPartyExtendable bool 961 IsEnterprise bool 962 FileOptionsParams *FileOptionsParameters 963 Force bool 964 } 965 966 // CreateAllocationWith creates a new allocation with the given options for the current client using the SDK. 967 // Similar ro CreateAllocationForOwner but uses an options struct instead of individual parameters. 968 // - options is the options struct instance for creating the allocation. 969 // 970 // returns the hash of the new_allocation_request transaction, the nonce of the transaction, the transaction object and an error if any. 971 func CreateAllocationWith(options CreateAllocationOptions) ( 972 string, int64, *transaction.Transaction, error) { 973 974 return CreateAllocationForOwner(client.GetClientID(), 975 client.GetClientPublicKey(), options.DataShards, options.ParityShards, 976 options.Size, options.ReadPrice, options.WritePrice, options.Lock, 977 options.BlobberIds, options.BlobberAuthTickets, options.ThirdPartyExtendable, options.IsEnterprise, options.Force, options.FileOptionsParams) 978 } 979 980 // GetAllocationBlobbers returns a list of blobber ids that can be used for a new allocation. 981 // 982 // - datashards is the number of data shards for the allocation. 983 // - parityshards is the number of parity shards for the allocation. 984 // - size is the size of the allocation. 985 // - readPrice is the read price range for the allocation (Reads in Züs are free!). 986 // - writePrice is the write price range for the allocation. 987 // - force is a flag indicating whether to force the allocation to be created. 988 // 989 // returns the list of blobber ids and an error if any. 990 func GetAllocationBlobbers( 991 datashards, parityshards int, 992 size int64, 993 isRestricted int, 994 readPrice, writePrice PriceRange, 995 force ...bool, 996 ) ([]string, error) { 997 var allocationRequest = map[string]interface{}{ 998 "data_shards": datashards, 999 "parity_shards": parityshards, 1000 "size": size, 1001 "read_price_range": readPrice, 1002 "write_price_range": writePrice, 1003 "is_restricted": isRestricted, 1004 } 1005 1006 allocationData, _ := json.Marshal(allocationRequest) 1007 1008 params := make(map[string]string) 1009 params["allocation_data"] = string(allocationData) 1010 if len(force) > 0 && force[0] { 1011 params["force"] = strconv.FormatBool(force[0]) 1012 } 1013 1014 allocBlobber, err := zboxutil.MakeSCRestAPICall(STORAGE_SCADDRESS, "/alloc_blobbers", params, nil) 1015 if err != nil { 1016 return nil, err 1017 } 1018 var allocBlobberIDs []string 1019 1020 err = json.Unmarshal(allocBlobber, &allocBlobberIDs) 1021 if err != nil { 1022 return nil, errors.Wrap(err, "failed to unmarshal blobber IDs") 1023 } 1024 1025 return allocBlobberIDs, nil 1026 } 1027 1028 func getNewAllocationBlobbers( 1029 datashards, parityshards int, 1030 size int64, 1031 readPrice, writePrice PriceRange, 1032 preferredBlobberIds, blobberAuthTickets []string, force bool, 1033 ) (map[string]interface{}, error) { 1034 for _, authTicket := range blobberAuthTickets { 1035 if len(authTicket) > 0 { 1036 return map[string]interface{}{ 1037 "data_shards": datashards, 1038 "parity_shards": parityshards, 1039 "size": size, 1040 "blobbers": preferredBlobberIds, 1041 "blobber_auth_tickets": blobberAuthTickets, 1042 "read_price_range": readPrice, 1043 "write_price_range": writePrice, 1044 }, nil 1045 } 1046 } 1047 1048 allocBlobberIDs, err := GetAllocationBlobbers( 1049 datashards, parityshards, size, 2, readPrice, writePrice, force, 1050 ) 1051 if err != nil { 1052 return nil, err 1053 } 1054 1055 blobbers := append(preferredBlobberIds, allocBlobberIDs...) 1056 1057 // filter duplicates 1058 ids := make(map[string]bool) 1059 uniqueBlobbers := []string{} 1060 uniqueBlobberAuthTickets := []string{} 1061 1062 for _, b := range blobbers { 1063 if !ids[b] { 1064 uniqueBlobbers = append(uniqueBlobbers, b) 1065 uniqueBlobberAuthTickets = append(uniqueBlobberAuthTickets, "") 1066 ids[b] = true 1067 } 1068 } 1069 1070 return map[string]interface{}{ 1071 "data_shards": datashards, 1072 "parity_shards": parityshards, 1073 "size": size, 1074 "blobbers": uniqueBlobbers, 1075 "blobber_auth_tickets": uniqueBlobberAuthTickets, 1076 "read_price_range": readPrice, 1077 "write_price_range": writePrice, 1078 }, nil 1079 } 1080 1081 // GetBlobberIds returns a list of blobber ids that can be used for a new allocation. 1082 // 1083 // - blobberUrls is a list of blobber urls. 1084 // 1085 // returns a list of blobber ids that can be used for the new allocation and an error if any. 1086 func GetBlobberIds(blobberUrls []string) ([]string, error) { 1087 1088 if len(blobberUrls) == 0 { 1089 return nil, nil 1090 } 1091 1092 urlsStr, err := json.Marshal(blobberUrls) 1093 if err != nil { 1094 return nil, err 1095 } 1096 1097 params := make(map[string]string) 1098 params["blobber_urls"] = string(urlsStr) 1099 idsStr, err := zboxutil.MakeSCRestAPICall(STORAGE_SCADDRESS, "/blobber_ids", params, nil) 1100 if err != nil { 1101 return nil, err 1102 } 1103 1104 var blobberIDs []string 1105 err = json.Unmarshal(idsStr, &blobberIDs) 1106 if err != nil { 1107 return nil, errors.Wrap(err, "failed to unmarshal preferred blobber IDs") 1108 } 1109 1110 return blobberIDs, nil 1111 } 1112 1113 // GetFreeAllocationBlobbers returns a list of blobber ids that can be used for a new free allocation. 1114 // 1115 // - request is the request data for the free allocation. 1116 // 1117 // returns a list of blobber ids that can be used for the new free allocation and an error if any. 1118 func GetFreeAllocationBlobbers(request map[string]interface{}) ([]string, error) { 1119 data, _ := json.Marshal(request) 1120 1121 params := make(map[string]string) 1122 params["free_allocation_data"] = string(data) 1123 1124 allocBlobber, err := zboxutil.MakeSCRestAPICall(STORAGE_SCADDRESS, "/free_alloc_blobbers", params, nil) 1125 if err != nil { 1126 return nil, err 1127 } 1128 var allocBlobberIDs []string 1129 1130 err = json.Unmarshal(allocBlobber, &allocBlobberIDs) 1131 if err != nil { 1132 return nil, errors.Wrap(err, "failed to unmarshal blobber IDs") 1133 } 1134 1135 return allocBlobberIDs, nil 1136 } 1137 1138 // AddFreeStorageAssigner adds a new free storage assigner (txn: `storagesc.add_free_allocation_assigner`). 1139 // The free storage assigner is used to create free allocations. Can only be called by chain owner. 1140 // 1141 // - name is the name of the assigner. 1142 // - publicKey is the public key of the assigner. 1143 // - individualLimit is the individual limit of the assigner for a single free allocation request 1144 // - totalLimit is the total limit of the assigner for all free allocation requests. 1145 // 1146 // returns the hash of the transaction, the nonce of the transaction and an error if any. 1147 func AddFreeStorageAssigner(name, publicKey string, individualLimit, totalLimit float64) (string, int64, error) { 1148 if !sdkInitialized { 1149 return "", 0, sdkNotInitialized 1150 } 1151 1152 var input = map[string]interface{}{ 1153 "name": name, 1154 "public_key": publicKey, 1155 "individual_limit": individualLimit, 1156 "total_limit": totalLimit, 1157 } 1158 1159 var sn = transaction.SmartContractTxnData{ 1160 Name: transaction.ADD_FREE_ALLOCATION_ASSIGNER, 1161 InputArgs: input, 1162 } 1163 hash, _, n, _, err := storageSmartContractTxn(sn) 1164 1165 return hash, n, err 1166 } 1167 1168 // FinalizeAllocation sends a finalize request for an allocation (txn: `storagesc.finalize_allocation`) 1169 // 1170 // - allocID is the id of the allocation. 1171 // 1172 // returns the hash of the transaction, the nonce of the transaction and an error if any. 1173 func FinalizeAllocation(allocID string) (hash string, nonce int64, err error) { 1174 if !sdkInitialized { 1175 return "", 0, sdkNotInitialized 1176 } 1177 var sn = transaction.SmartContractTxnData{ 1178 Name: transaction.STORAGESC_FINALIZE_ALLOCATION, 1179 InputArgs: map[string]interface{}{"allocation_id": allocID}, 1180 } 1181 hash, _, nonce, _, err = storageSmartContractTxn(sn) 1182 return 1183 } 1184 1185 // CancelAllocation sends a cancel request for an allocation (txn: `storagesc.cancel_allocation`) 1186 // 1187 // - allocID is the id of the allocation. 1188 // 1189 // returns the hash of the transaction, the nonce of the transaction and an error if any. 1190 func CancelAllocation(allocID string) (hash string, nonce int64, err error) { 1191 if !sdkInitialized { 1192 return "", 0, sdkNotInitialized 1193 } 1194 var sn = transaction.SmartContractTxnData{ 1195 Name: transaction.STORAGESC_CANCEL_ALLOCATION, 1196 InputArgs: map[string]interface{}{"allocation_id": allocID}, 1197 } 1198 hash, _, nonce, _, err = storageSmartContractTxn(sn) 1199 return 1200 } 1201 1202 // ProviderType is the type of the provider. 1203 type ProviderType int 1204 1205 const ( 1206 ProviderMiner ProviderType = iota + 1 1207 ProviderSharder 1208 ProviderBlobber 1209 ProviderValidator 1210 ProviderAuthorizer 1211 ) 1212 1213 // KillProvider kills a blobber or a validator (txn: `storagesc.kill_blobber` or `storagesc.kill_validator`) 1214 // - providerId is the id of the provider. 1215 // - providerType` is the type of the provider, either 3 for `ProviderBlobber` or 4 for `ProviderValidator. 1216 func KillProvider(providerId string, providerType ProviderType) (string, int64, error) { 1217 if !sdkInitialized { 1218 return "", 0, sdkNotInitialized 1219 } 1220 1221 var input = map[string]interface{}{ 1222 "provider_id": providerId, 1223 } 1224 var sn = transaction.SmartContractTxnData{ 1225 InputArgs: input, 1226 } 1227 switch providerType { 1228 case ProviderBlobber: 1229 sn.Name = transaction.STORAGESC_KILL_BLOBBER 1230 case ProviderValidator: 1231 sn.Name = transaction.STORAGESC_KILL_VALIDATOR 1232 default: 1233 return "", 0, fmt.Errorf("kill provider type %v not implimented", providerType) 1234 } 1235 hash, _, n, _, err := storageSmartContractTxn(sn) 1236 return hash, n, err 1237 } 1238 1239 // ShutdownProvider shuts down a blobber or a validator (txn: `storagesc.shutdown_blobber` or `storagesc.shutdown_validator`) 1240 // - providerId is the id of the provider. 1241 // - providerType` is the type of the provider, either 3 for `ProviderBlobber` or 4 for `ProviderValidator. 1242 func ShutdownProvider(providerType ProviderType, providerID string) (string, int64, error) { 1243 if !sdkInitialized { 1244 return "", 0, sdkNotInitialized 1245 } 1246 1247 var input = map[string]interface{}{ 1248 "provider_id": providerID, 1249 } 1250 1251 var sn = transaction.SmartContractTxnData{ 1252 InputArgs: input, 1253 } 1254 switch providerType { 1255 case ProviderBlobber: 1256 sn.Name = transaction.STORAGESC_SHUTDOWN_BLOBBER 1257 case ProviderValidator: 1258 sn.Name = transaction.STORAGESC_SHUTDOWN_VALIDATOR 1259 default: 1260 return "", 0, fmt.Errorf("shutdown provider type %v not implimented", providerType) 1261 } 1262 hash, _, n, _, err := storageSmartContractTxn(sn) 1263 return hash, n, err 1264 } 1265 1266 // CollectRewards collects the rewards for a provider (txn: `storagesc.collect_reward`) 1267 // - providerId is the id of the provider. 1268 // - providerType is the type of the provider. 1269 func CollectRewards(providerId string, providerType ProviderType) (string, int64, error) { 1270 if !sdkInitialized { 1271 return "", 0, sdkNotInitialized 1272 } 1273 1274 var input = map[string]interface{}{ 1275 "provider_id": providerId, 1276 "provider_type": providerType, 1277 } 1278 1279 var sn = transaction.SmartContractTxnData{ 1280 InputArgs: input, 1281 } 1282 1283 var scAddress string 1284 switch providerType { 1285 case ProviderBlobber, ProviderValidator: 1286 scAddress = STORAGE_SCADDRESS 1287 sn.Name = transaction.STORAGESC_COLLECT_REWARD 1288 case ProviderMiner, ProviderSharder: 1289 scAddress = MINERSC_SCADDRESS 1290 sn.Name = transaction.MINERSC_COLLECT_REWARD 1291 // case ProviderAuthorizer: 1292 // scAddress = ZCNSC_SCADDRESS 1293 // sn.Name = transaction.ZCNSC_COLLECT_REWARD 1294 default: 1295 return "", 0, fmt.Errorf("collect rewards provider type %v not implimented", providerType) 1296 } 1297 1298 hash, _, n, _, err := smartContractTxn(scAddress, sn) 1299 return hash, n, err 1300 } 1301 1302 // TransferAllocation transfers the ownership of an allocation to a new owner. (txn: `storagesc.update_allocation_request`) 1303 // 1304 // - allocationId is the id of the allocation. 1305 // - newOwner is the client id of the new owner. 1306 // - newOwnerPublicKey is the public key of the new owner. 1307 // 1308 // returns the hash of the transaction, the nonce of the transaction and an error if any. 1309 func TransferAllocation(allocationId, newOwner, newOwnerPublicKey string) (string, int64, error) { 1310 if !sdkInitialized { 1311 return "", 0, sdkNotInitialized 1312 } 1313 1314 alloc, err := GetAllocation(allocationId) 1315 if err != nil { 1316 return "", 0, allocationNotFound 1317 } 1318 1319 var allocationRequest = map[string]interface{}{ 1320 "id": allocationId, 1321 "owner_id": newOwner, 1322 "owner_public_key": newOwnerPublicKey, 1323 "size": 0, 1324 "expiration_date": 0, 1325 "update_terms": false, 1326 "add_blobber_id": "", 1327 "remove_blobber_id": "", 1328 "set_third_party_extendable": alloc.ThirdPartyExtendable, 1329 "file_options_changed": false, 1330 "file_options": alloc.FileOptions, 1331 } 1332 var sn = transaction.SmartContractTxnData{ 1333 Name: transaction.STORAGESC_UPDATE_ALLOCATION, 1334 InputArgs: allocationRequest, 1335 } 1336 hash, _, n, _, err := storageSmartContractTxn(sn) 1337 return hash, n, err 1338 } 1339 1340 // UpdateBlobberSettings updates the settings of a blobber (txn: `storagesc.update_blobber_settings`) 1341 // - blob is the update blobber request inputs. 1342 func UpdateBlobberSettings(blob *UpdateBlobber) (resp string, nonce int64, err error) { 1343 if !sdkInitialized { 1344 return "", 0, sdkNotInitialized 1345 } 1346 var sn = transaction.SmartContractTxnData{ 1347 Name: transaction.STORAGESC_UPDATE_BLOBBER_SETTINGS, 1348 InputArgs: blob, 1349 } 1350 resp, _, nonce, _, err = storageSmartContractTxn(sn) 1351 return 1352 } 1353 1354 // UpdateValidatorSettings updates the settings of a validator (txn: `storagesc.update_validator_settings`) 1355 // - v is the update validator request inputs. 1356 func UpdateValidatorSettings(v *UpdateValidator) (resp string, nonce int64, err error) { 1357 if !sdkInitialized { 1358 return "", 0, sdkNotInitialized 1359 } 1360 1361 var sn = transaction.SmartContractTxnData{ 1362 Name: transaction.STORAGESC_UPDATE_VALIDATOR_SETTINGS, 1363 InputArgs: v.ConvertToValidationNode(), 1364 } 1365 resp, _, nonce, _, err = storageSmartContractTxn(sn) 1366 return 1367 } 1368 1369 // ResetBlobberStats resets the stats of a blobber (txn: `storagesc.reset_blobber_stats`) 1370 // - rbs is the reset blobber stats dto, contains the blobber id and its stats. 1371 func ResetBlobberStats(rbs *ResetBlobberStatsDto) (string, int64, error) { 1372 if !sdkInitialized { 1373 return "", 0, sdkNotInitialized 1374 } 1375 1376 var sn = transaction.SmartContractTxnData{ 1377 Name: transaction.STORAGESC_RESET_BLOBBER_STATS, 1378 InputArgs: rbs, 1379 } 1380 hash, _, n, _, err := storageSmartContractTxn(sn) 1381 return hash, n, err 1382 } 1383 1384 func ResetAllocationStats(allocationId string) (string, int64, error) { 1385 if !sdkInitialized { 1386 return "", 0, sdkNotInitialized 1387 } 1388 1389 var sn = transaction.SmartContractTxnData{ 1390 Name: transaction.STORAGESC_RESET_ALLOCATION_STATS, 1391 InputArgs: allocationId, 1392 } 1393 hash, _, n, _, err := storageSmartContractTxn(sn) 1394 return hash, n, err 1395 } 1396 1397 func CommitToFabric(metaTxnData, fabricConfigJSON string) (string, error) { 1398 if !sdkInitialized { 1399 return "", sdkNotInitialized 1400 } 1401 var fabricConfig struct { 1402 URL string `json:"url"` 1403 Body struct { 1404 Channel string `json:"channel"` 1405 ChaincodeName string `json:"chaincode_name"` 1406 ChaincodeVersion string `json:"chaincode_version"` 1407 Method string `json:"method"` 1408 Args []string `json:"args"` 1409 } `json:"body"` 1410 Auth struct { 1411 Username string `json:"username"` 1412 Password string `json:"password"` 1413 } `json:"auth"` 1414 } 1415 1416 err := json.Unmarshal([]byte(fabricConfigJSON), &fabricConfig) 1417 if err != nil { 1418 return "", errors.New("fabric_config_decode_error", "Unable to decode fabric config json") 1419 } 1420 1421 // Clear if any existing args passed 1422 fabricConfig.Body.Args = fabricConfig.Body.Args[:0] 1423 1424 fabricConfig.Body.Args = append(fabricConfig.Body.Args, metaTxnData) 1425 1426 fabricData, err := json.Marshal(fabricConfig.Body) 1427 if err != nil { 1428 return "", errors.New("fabric_config_encode_error", "Unable to encode fabric config body") 1429 } 1430 1431 req, ctx, cncl, err := zboxutil.NewHTTPRequest(http.MethodPost, fabricConfig.URL, fabricData) 1432 if err != nil { 1433 return "", errors.New("fabric_commit_error", "Unable to create new http request with error "+err.Error()) 1434 } 1435 1436 // Set basic auth 1437 req.SetBasicAuth(fabricConfig.Auth.Username, fabricConfig.Auth.Password) 1438 1439 var fabricResponse string 1440 err = zboxutil.HttpDo(ctx, cncl, req, func(resp *http.Response, err error) error { 1441 if err != nil { 1442 l.Logger.Error("Fabric commit error : ", err) 1443 return err 1444 } 1445 defer resp.Body.Close() 1446 respBody, err := ioutil.ReadAll(resp.Body) 1447 if err != nil { 1448 return errors.Wrap(err, "Error reading response :") 1449 } 1450 l.Logger.Debug("Fabric commit result:", string(respBody)) 1451 if resp.StatusCode == http.StatusOK { 1452 fabricResponse = string(respBody) 1453 return nil 1454 } 1455 return errors.New(strconv.Itoa(resp.StatusCode), "Fabric commit status not OK!") 1456 }) 1457 return fabricResponse, err 1458 } 1459 1460 // GetAllocationMinLock calculates and returns the minimum lock demand for creating a new allocation, which represents the cost of the creation process. 1461 // - datashards is the number of data shards for the allocation. 1462 // - parityshards is the number of parity shards for the allocation. 1463 // - size is the size of the allocation. 1464 // - writePrice is the write price range for the allocation. 1465 // 1466 // returns the minimum lock demand for the creation process and an error if any. 1467 func GetAllocationMinLock( 1468 datashards, parityshards int, 1469 size int64, 1470 writePrice PriceRange, 1471 ) (int64, error) { 1472 baSize := int64(math.Ceil(float64(size) / float64(datashards))) 1473 totalSize := baSize * int64(datashards+parityshards) 1474 1475 sizeInGB := float64(totalSize) / GB 1476 1477 cost := sizeInGB * float64(writePrice.Max) 1478 coin, err := currency.Float64ToCoin(cost) 1479 if err != nil { 1480 return 0, err 1481 } 1482 i, err := coin.Int64() 1483 if err != nil { 1484 return 0, err 1485 } 1486 return i, nil 1487 } 1488 1489 // GetUpdateAllocationMinLock returns the minimum lock demand for updating an allocation, which represents the cost of the update operation. 1490 // 1491 // - allocationID is the id of the allocation. 1492 // - size is the new size of the allocation. 1493 // - extend is a flag indicating whether to extend the expiry of the allocation. 1494 // - addBlobberId is the id of the blobber to add to the allocation. 1495 // - removeBlobberId is the id of the blobber to remove from the allocation. 1496 // 1497 // returns the minimum lock demand for the update operation and an error if any. 1498 func GetUpdateAllocationMinLock( 1499 allocationID string, 1500 size int64, 1501 extend bool, 1502 addBlobberId, 1503 removeBlobberId string) (int64, error) { 1504 updateAllocationRequest := make(map[string]interface{}) 1505 updateAllocationRequest["owner_id"] = client.GetClientID() 1506 updateAllocationRequest["owner_public_key"] = "" 1507 updateAllocationRequest["id"] = allocationID 1508 updateAllocationRequest["size"] = size 1509 updateAllocationRequest["extend"] = extend 1510 updateAllocationRequest["add_blobber_id"] = addBlobberId 1511 updateAllocationRequest["remove_blobber_id"] = removeBlobberId 1512 1513 data, err := json.Marshal(updateAllocationRequest) 1514 if err != nil { 1515 return 0, errors.Wrap(err, "failed to encode request into json") 1516 } 1517 1518 params := make(map[string]string) 1519 params["data"] = string(data) 1520 1521 responseBytes, err := zboxutil.MakeSCRestAPICall(STORAGE_SCADDRESS, "/allocation-update-min-lock", params, nil) 1522 if err != nil { 1523 return 0, errors.Wrap(err, "failed to request allocation update min lock") 1524 } 1525 1526 var response = make(map[string]int64) 1527 if err = json.Unmarshal(responseBytes, &response); err != nil { 1528 return 0, errors.Wrap(err, fmt.Sprintf("failed to decode response: %s", string(responseBytes))) 1529 } 1530 1531 v, ok := response["min_lock_demand"] 1532 if !ok { 1533 return 0, errors.New("", "min_lock_demand not found in response") 1534 } 1535 return v, nil 1536 } 1537 1538 // calculateAllocationFileOptions calculates the FileOptions 16-bit mask given the user input 1539 func calculateAllocationFileOptions(initial uint16, fop *FileOptionsParameters) (bool, uint16) { 1540 if fop == nil { 1541 return false, initial 1542 } 1543 1544 mask := initial 1545 1546 if fop.ForbidUpload.Changed { 1547 mask = updateMaskBit(mask, 0, !fop.ForbidUpload.Value) 1548 } 1549 1550 if fop.ForbidDelete.Changed { 1551 mask = updateMaskBit(mask, 1, !fop.ForbidDelete.Value) 1552 } 1553 1554 if fop.ForbidUpdate.Changed { 1555 mask = updateMaskBit(mask, 2, !fop.ForbidUpdate.Value) 1556 } 1557 1558 if fop.ForbidMove.Changed { 1559 mask = updateMaskBit(mask, 3, !fop.ForbidMove.Value) 1560 } 1561 1562 if fop.ForbidCopy.Changed { 1563 mask = updateMaskBit(mask, 4, !fop.ForbidCopy.Value) 1564 } 1565 1566 if fop.ForbidRename.Changed { 1567 mask = updateMaskBit(mask, 5, !fop.ForbidRename.Value) 1568 } 1569 1570 return mask != initial, mask 1571 } 1572 1573 // updateMaskBit Set/Clear (based on `value`) bit value of the bit of `mask` at `index` (starting with LSB as 0) and return the updated mask 1574 func updateMaskBit(mask uint16, index uint8, value bool) uint16 { 1575 if value { 1576 return mask | uint16(1<<index) 1577 } else { 1578 return mask & ^uint16(1<<index) 1579 } 1580 }