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

     1  //go:build mobile
     2  // +build mobile
     3  
     4  package sdk
     5  
     6  import (
     7  	"encoding/base64"
     8  	"encoding/json"
     9  	"fmt"
    10  	"math"
    11  	"strconv"
    12  	"strings"
    13  
    14  	"github.com/0chain/gosdk/core/sys"
    15  	"github.com/pkg/errors"
    16  
    17  	"github.com/0chain/gosdk/core/util"
    18  	"github.com/0chain/gosdk/core/version"
    19  	"github.com/0chain/gosdk/zboxcore/client"
    20  	l "github.com/0chain/gosdk/zboxcore/logger"
    21  	"github.com/0chain/gosdk/zboxcore/sdk"
    22  
    23  	"github.com/0chain/gosdk/mobilesdk/zbox"
    24  	"github.com/0chain/gosdk/mobilesdk/zboxapi"
    25  	"github.com/0chain/gosdk/zcncore"
    26  )
    27  
    28  var nonce = int64(0)
    29  
    30  type Autorizer interface {
    31  	Auth(msg string) (string, error)
    32  }
    33  
    34  // ChainConfig - blockchain config
    35  type ChainConfig struct {
    36  	ChainID           string   `json:"chain_id,omitempty"`
    37  	PreferredBlobbers []string `json:"preferred_blobbers"`
    38  	BlockWorker       string   `json:"block_worker"`
    39  	SignatureScheme   string   `json:"signature_scheme"`
    40  	// ZboxHost 0box api host host: "https://0box.dev.0chain.net"
    41  	ZboxHost string `json:"zbox_host"`
    42  	// ZboxAppType app type name
    43  	ZboxAppType string `json:"zbox_app_type"`
    44  }
    45  
    46  // StorageSDK - storage SDK config
    47  type StorageSDK struct {
    48  	chainconfig *ChainConfig
    49  	client      *client.Client
    50  }
    51  
    52  // SetLogFile setup log level for core libraries
    53  //   - logFile: the output file of logs
    54  //   - verbose: output detail logs
    55  func SetLogFile(logFile string, verbose bool) {
    56  	zcncore.SetLogFile(logFile, verbose)
    57  	sdk.SetLogFile(logFile, verbose)
    58  }
    59  
    60  // SetLogLevel set the log level.
    61  //
    62  //	`lvl` - 0 disabled; higher number (upto 4) more verbosity
    63  func SetLogLevel(logLevel int) {
    64  	sdk.SetLogLevel(logLevel)
    65  }
    66  
    67  // Init init the sdk with chain config
    68  //   - chainConfigJson: chain config json string
    69  func Init(chainConfigJson string) error {
    70  	return zcncore.Init(chainConfigJson)
    71  }
    72  
    73  // InitStorageSDK init storage sdk from config
    74  //   - clientJson example
    75  //     {
    76  //     "client_id":"8f6ce6457fc04cfb4eb67b5ce3162fe2b85f66ef81db9d1a9eaa4ffe1d2359e0",
    77  //     "client_key":"c8c88854822a1039c5a74bdb8c025081a64b17f52edd463fbecb9d4a42d15608f93b5434e926d67a828b88e63293b6aedbaf0042c7020d0a96d2e2f17d3779a4",
    78  //     "keys":[
    79  //     {
    80  //     "public_key":"c8c88854822a1039c5a74bdb8c025081a64b17f52edd463fbecb9d4a42d15608f93b5434e926d67a828b88e63293b6aedbaf0042c7020d0a96d2e2f17d3779a4",
    81  //     "private_key":"72f480d4b1e7fb76e04327b7c2348a99a64f0ff2c5ebc3334a002aa2e66e8506"
    82  //     }],
    83  //     "mnemonics":"abandon mercy into make powder fashion butter ignore blade vanish plastic shock learn nephew matrix indoor surge document motor group barely offer pottery antenna",
    84  //     "version":"1.0",
    85  //     "date_created":"1668667145",
    86  //     "nonce":0
    87  //     }
    88  //   - configJson example
    89  //     {
    90  //     "block_worker": "https://dev.0chain.net/dns",
    91  //     "signature_scheme": "bls0chain",
    92  //     "min_submit": 50,
    93  //     "min_confirmation": 50,
    94  //     "confirmation_chain_length": 3,
    95  //     "max_txn_query": 5,
    96  //     "query_sleep_time": 5,
    97  //     "preferred_blobbers": ["https://dev.0chain.net/blobber02","https://dev.0chain.net/blobber03"],
    98  //     "chain_id":"0afc093ffb509f059c55478bc1a60351cef7b4e9c008a53a6cc8241ca8617dfe",
    99  //     "ethereum_node":"https://ropsten.infura.io/v3/xxxxxxxxxxxxxxx",
   100  //     "zbox_host":"https://0box.dev.0chain.net",
   101  //     "zbox_app_type":"vult",
   102  //     }
   103  func InitStorageSDK(clientJson string, configJson string) (*StorageSDK, error) {
   104  	l.Logger.Info("Start InitStorageSDK")
   105  	configObj := &ChainConfig{}
   106  	err := json.Unmarshal([]byte(configJson), configObj)
   107  	if err != nil {
   108  		l.Logger.Error(err)
   109  		return nil, err
   110  	}
   111  	err = zcncore.InitZCNSDK(configObj.BlockWorker, configObj.SignatureScheme)
   112  	if err != nil {
   113  		l.Logger.Error(err)
   114  		return nil, err
   115  	}
   116  	l.Logger.Info("InitZCNSDK success")
   117  	l.Logger.Info(configObj.BlockWorker)
   118  	l.Logger.Info(configObj.ChainID)
   119  	l.Logger.Info(configObj.SignatureScheme)
   120  	l.Logger.Info(configObj.PreferredBlobbers)
   121  	if err = sdk.InitStorageSDK(clientJson,
   122  		configObj.BlockWorker,
   123  		configObj.ChainID,
   124  		configObj.SignatureScheme,
   125  		configObj.PreferredBlobbers,
   126  		0); err != nil {
   127  		l.Logger.Error(err)
   128  		return nil, err
   129  	}
   130  
   131  	l.Logger.Info("InitStorageSDK success")
   132  
   133  	if configObj.ZboxHost != "" && configObj.ZboxAppType != "" {
   134  		zboxapi.Init(configObj.ZboxHost, configObj.ZboxAppType)
   135  		l.Logger.Info("InitZboxApi success")
   136  	} else {
   137  		l.Logger.Info("InitZboxApi skipped")
   138  	}
   139  
   140  	l.Logger.Info("Init successful")
   141  
   142  	return &StorageSDK{client: client.GetClient(), chainconfig: configObj}, nil
   143  }
   144  
   145  // CreateAllocation creating new allocation
   146  //   - datashards: number of data shards, effects upload and download speeds
   147  //   - parityshards: number of parity shards, effects availability
   148  //   - size: size of space reserved on blobbers
   149  //   - expiration: duration to allocation expiration
   150  //   - lock: lock write pool with given number of tokens
   151  //   - blobberAuthTickets: list of blobber auth tickets needed for the restricted blobbers
   152  func (s *StorageSDK) CreateAllocation(datashards, parityshards int, size, expiration int64, lock string, blobberAuthTickets []string) (*zbox.Allocation, error) {
   153  	readPrice := sdk.PriceRange{Min: 0, Max: math.MaxInt64}
   154  	writePrice := sdk.PriceRange{Min: 0, Max: math.MaxInt64}
   155  
   156  	l, err := util.ParseCoinStr(lock)
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  
   161  	options := sdk.CreateAllocationOptions{
   162  		DataShards:         datashards,
   163  		ParityShards:       parityshards,
   164  		Size:               size,
   165  		ReadPrice:          readPrice,
   166  		WritePrice:         writePrice,
   167  		Lock:               uint64(l),
   168  		BlobberIds:         []string{},
   169  		FileOptionsParams:  &sdk.FileOptionsParameters{},
   170  		BlobberAuthTickets: blobberAuthTickets,
   171  	}
   172  
   173  	sdkAllocationID, _, _, err := sdk.CreateAllocationWith(options)
   174  	if err != nil {
   175  		return nil, err
   176  	}
   177  	sdkAllocation, err := sdk.GetAllocation(sdkAllocationID)
   178  	if err != nil {
   179  		return nil, err
   180  	}
   181  	return zbox.ToAllocation(sdkAllocation), nil
   182  }
   183  
   184  // CreateAllocationWithBlobbers - creating new allocation with list of blobbers
   185  //   - name: allocation name
   186  //   - datashards: number of data shards, effects upload and download speeds
   187  //   - parityshards: number of parity shards, effects availability
   188  //   - size: size of space reserved on blobbers
   189  //   - expiration: duration to allocation expiration
   190  //   - lock: lock write pool with given number of tokens
   191  //   - blobberUrls: concat blobber urls with comma. leave it as empty if you don't have any preferred blobbers
   192  //   - blobberIds: concat blobber ids with comma. leave it as empty if you don't have any preferred blobbers
   193  func (s *StorageSDK) CreateAllocationWithBlobbers(name string, datashards, parityshards int, size int64, lock string, blobberUrls, blobberIds string, blobberAuthTickets []string) (*zbox.Allocation, error) {
   194  	readPrice := sdk.PriceRange{Min: 0, Max: math.MaxInt64}
   195  	writePrice := sdk.PriceRange{Min: 0, Max: math.MaxInt64}
   196  
   197  	l, err := util.ParseCoinStr(lock)
   198  	if err != nil {
   199  		return nil, err
   200  	}
   201  
   202  	options := sdk.CreateAllocationOptions{
   203  		DataShards:         datashards,
   204  		ParityShards:       parityshards,
   205  		Size:               size,
   206  		Lock:               l,
   207  		WritePrice:         writePrice,
   208  		ReadPrice:          readPrice,
   209  		BlobberAuthTickets: blobberAuthTickets,
   210  	}
   211  
   212  	if blobberUrls != "" {
   213  		urls := strings.Split(blobberUrls, ",")
   214  		if len(urls) > 0 {
   215  			ids, err := sdk.GetBlobberIds(urls)
   216  			if err != nil {
   217  				return nil, err
   218  			}
   219  			options.BlobberIds = ids
   220  		}
   221  	}
   222  
   223  	if blobberIds != "" {
   224  		ids := strings.Split(blobberIds, ",")
   225  		if len(ids) > 0 {
   226  			options.BlobberIds = ids
   227  		}
   228  	}
   229  
   230  	sdkAllocationID, _, _, err := sdk.CreateAllocationWith(options)
   231  	if err != nil {
   232  		return nil, err
   233  	}
   234  
   235  	sdkAllocation, err := sdk.GetAllocation(sdkAllocationID)
   236  	if err != nil {
   237  		return nil, err
   238  	}
   239  
   240  	return zbox.ToAllocation(sdkAllocation), nil
   241  }
   242  
   243  // GetAllocation retrieve allocation from ID
   244  //   - allocationID: allocation ID
   245  func (s *StorageSDK) GetAllocation(allocationID string) (*zbox.Allocation, error) {
   246  	sdkAllocation, err := sdk.GetAllocation(allocationID)
   247  	if err != nil {
   248  		return nil, err
   249  	}
   250  
   251  	stats := sdkAllocation.GetStats()
   252  	retBytes, err := json.Marshal(stats)
   253  	if err != nil {
   254  		return nil, err
   255  	}
   256  
   257  	alloc := zbox.ToAllocation(sdkAllocation)
   258  	alloc.Stats = string(retBytes)
   259  
   260  	return alloc, nil
   261  }
   262  
   263  // GetAllocations retrieve list of allocations owned by the wallet
   264  func (s *StorageSDK) GetAllocations() (string, error) {
   265  	sdkAllocations, err := sdk.GetAllocations()
   266  	if err != nil {
   267  		return "", err
   268  	}
   269  	result := make([]*zbox.Allocation, len(sdkAllocations))
   270  	for i, sdkAllocation := range sdkAllocations {
   271  		allocationObj := zbox.ToAllocation(sdkAllocation)
   272  		result[i] = allocationObj
   273  	}
   274  	retBytes, err := json.Marshal(result)
   275  	if err != nil {
   276  		return "", err
   277  	}
   278  	return string(retBytes), nil
   279  }
   280  
   281  // GetAllocationFromAuthTicket retrieve allocation from Auth ticket
   282  // AuthTicket is a signed message from the blobber authorizing the client to access the allocation.
   283  // It's issued by the allocation owner and can be used by a non-owner to access the allocation.
   284  //   - authTicket: auth ticket
   285  func (s *StorageSDK) GetAllocationFromAuthTicket(authTicket string) (*zbox.Allocation, error) {
   286  	sdkAllocation, err := sdk.GetAllocationFromAuthTicket(authTicket)
   287  	if err != nil {
   288  		return nil, err
   289  	}
   290  	return zbox.ToAllocation(sdkAllocation), nil
   291  }
   292  
   293  // GetAllocationStats retrieve allocation stats by allocation ID
   294  //   - allocationID: allocation ID
   295  func (s *StorageSDK) GetAllocationStats(allocationID string) (string, error) {
   296  	allocationObj, err := sdk.GetAllocation(allocationID)
   297  	if err != nil {
   298  		return "", err
   299  	}
   300  	stats := allocationObj.GetStats()
   301  	retBytes, err := json.Marshal(stats)
   302  	if err != nil {
   303  		return "", err
   304  	}
   305  	return string(retBytes), nil
   306  }
   307  
   308  // FinalizeAllocation finalize allocation
   309  //   - allocationID: allocation ID
   310  func (s *StorageSDK) FinalizeAllocation(allocationID string) (string, error) {
   311  	hash, _, err := sdk.FinalizeAllocation(allocationID)
   312  	return hash, err
   313  }
   314  
   315  // CancelAllocation cancel allocation by ID
   316  //   - allocationID: allocation ID
   317  func (s *StorageSDK) CancelAllocation(allocationID string) (string, error) {
   318  	hash, _, err := sdk.CancelAllocation(allocationID)
   319  	return hash, err
   320  }
   321  
   322  // GetReadPoolInfo is to get information about the read pool for the allocation
   323  //   - clientID: client ID
   324  func (s *StorageSDK) GetReadPoolInfo(clientID string) (string, error) {
   325  	readPool, err := sdk.GetReadPoolInfo(clientID)
   326  	if err != nil {
   327  		return "", err
   328  	}
   329  
   330  	retBytes, err := json.Marshal(readPool)
   331  	if err != nil {
   332  		return "", err
   333  	}
   334  	return string(retBytes), nil
   335  }
   336  
   337  // WRITE POOL METHODS
   338  // WritePoolLock lock write pool with given number of tokens
   339  //   - durInSeconds: duration in seconds
   340  //   - tokens: number of tokens
   341  //   - fee: fee of the transaction
   342  //   - allocID: allocation ID
   343  func (s *StorageSDK) WritePoolLock(durInSeconds int64, tokens, fee float64, allocID string) error {
   344  	_, _, err := sdk.WritePoolLock(
   345  		allocID,
   346  		strconv.FormatUint(zcncore.ConvertTokenToSAS(tokens), 10),
   347  		strconv.FormatUint(zcncore.ConvertTokenToSAS(fee), 10))
   348  	return err
   349  }
   350  
   351  // GetVersion getting current version for gomobile lib
   352  func (s *StorageSDK) GetVersion() string {
   353  	return version.VERSIONSTR
   354  }
   355  
   356  // UpdateAllocation update allocation settings with new expiry and size
   357  //   - size: size of space reserved on blobbers
   358  //   - extend: extend allocation
   359  //   - allocationID: allocation ID
   360  //   - lock: Number of tokens to lock to the allocation after the update
   361  func (s *StorageSDK) UpdateAllocation(size int64, extend bool, allocationID string, lock uint64) (hash string, err error) {
   362  	if lock > math.MaxInt64 {
   363  		return "", errors.Errorf("int64 overflow in lock")
   364  	}
   365  
   366  	hash, _, err = sdk.UpdateAllocation(size, extend, allocationID, lock, "", "", "", false, &sdk.FileOptionsParameters{})
   367  	return hash, err
   368  }
   369  
   370  // GetBlobbersList get list of active blobbers, and format them as array json string
   371  func (s *StorageSDK) GetBlobbersList() (string, error) {
   372  	blobbs, err := sdk.GetBlobbers(true, false)
   373  	if err != nil {
   374  		return "", err
   375  	}
   376  	retBytes, err := json.Marshal(blobbs)
   377  	if err != nil {
   378  		return "", err
   379  	}
   380  	return string(retBytes), nil
   381  }
   382  
   383  // GetAllocations return back list of allocations for the wallet
   384  // Extracted from main method, bcz of class fields
   385  func GetAllocations() (string, error) {
   386  	allocs, err := sdk.GetAllocations()
   387  	if err != nil {
   388  		return "", err
   389  	}
   390  	retBytes, err := json.Marshal(allocs)
   391  	if err != nil {
   392  		return "", err
   393  	}
   394  	return string(retBytes), nil
   395  }
   396  
   397  // RedeeemFreeStorage given a free storage ticket, create a new free allocation
   398  //   - ticket: free storage ticket
   399  func (s *StorageSDK) RedeemFreeStorage(ticket string) (string, error) {
   400  	recipientPublicKey, marker, lock, err := decodeTicket(ticket)
   401  	if err != nil {
   402  		return "", err
   403  	}
   404  
   405  	if recipientPublicKey != client.GetClientPublicKey() {
   406  		return "", fmt.Errorf("invalid_free_marker: free marker is not assigned to your wallet")
   407  	}
   408  
   409  	hash, _, err := sdk.CreateFreeAllocation(marker, strconv.FormatUint(lock, 10))
   410  	return hash, err
   411  }
   412  
   413  func decodeTicket(ticket string) (string, string, uint64, error) {
   414  	decoded, err := base64.StdEncoding.DecodeString(ticket)
   415  	if err != nil {
   416  		return "", "", 0, err
   417  	}
   418  
   419  	input := make(map[string]interface{})
   420  	if err = json.Unmarshal(decoded, &input); err != nil {
   421  		return "", "", 0, err
   422  	}
   423  
   424  	str := fmt.Sprintf("%v", input["marker"])
   425  	decodedMarker, _ := base64.StdEncoding.DecodeString(str)
   426  	markerInput := make(map[string]interface{})
   427  	if err = json.Unmarshal(decodedMarker, &markerInput); err != nil {
   428  		return "", "", 0, err
   429  	}
   430  
   431  	recipientPublicKey, ok := input["recipient_public_key"].(string)
   432  	if !ok {
   433  		return "", "", 0, fmt.Errorf("recipient_public_key is required")
   434  	}
   435  
   436  	lock := markerInput["free_tokens"]
   437  	markerStr, _ := json.Marshal(markerInput)
   438  
   439  	s, _ := strconv.ParseFloat(string(fmt.Sprintf("%v", lock)), 64)
   440  	return string(recipientPublicKey), string(markerStr), zcncore.ConvertTokenToSAS(s), nil
   441  }
   442  
   443  // RegisterAuthorizer Client can extend interface and FaSS implementation to this register like this:
   444  //
   445  //	public class Autorizer extends Pkg.Autorizer {
   446  //		public void Auth() {
   447  //			// do something here
   448  //		}
   449  //	}
   450  func RegisterAuthorizer(auth Autorizer) {
   451  	sys.Authorize = auth.Auth
   452  }