upload

package
v0.0.0-...-9fdd194 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 28, 2024 License: Apache-2.0, MIT Imports: 51 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var HostRepairResponseCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Host responds to repair jobs.",
		ShortDescription: `
This command enquires the repairer with the contract, if agrees with the contract after negotiation,
returns the repairer's signed contract to the invoker.`,
	},
	Arguments: []cmds.Argument{
		cmds.StringArg("file-hash", true, false, "File hash for the host prepares to repair."),
		cmds.StringArg("repair-shard-hash", true, false, "Shard hash for the host prepares to repair."),
		cmds.StringArg("file-size", true, false, "Size of the repair file."),
		cmds.StringArg("download-reward-amount", true, false, "Reward amount for download workload."),
		cmds.StringArg("repair-reward-amount", true, false, "Reward amount for repair workload."),
	},
	RunTimeout: 1 * time.Minute,
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
		err := utils.CheckSimpleMode(env)
		if err != nil {
			return err
		}

		ctxParams, err := uh.ExtractContextParams(req, env)
		repairId := ctxParams.N.Identity.Pretty()
		fileHash := req.Arguments[0]
		if requestFileHash == fileHash {
			return fmt.Errorf("file {%s} has been repairing on the host {%s}", fileHash, repairId)
		}
		requestFileHash = fileHash
		lostShardHashes := strings.Split(req.Arguments[1], ",")
		fileSize, err := strconv.ParseInt(req.Arguments[2], 10, 64)
		if err != nil {
			logger.Errorf("file size parse error: [%v]", err)
			return err
		}
		downloadRewardAmount, err := strconv.ParseInt(req.Arguments[3], 10, 64)
		if err != nil {
			logger.Errorf("download reward amount parse error: [%v]", err)
			return err
		}
		repairRewardAmount, err := strconv.ParseInt(req.Arguments[4], 10, 64)
		if err != nil {
			logger.Errorf("repair reward amount parse error: [%v]", err)
			return err
		}
		err = emptyCheck(fileHash, lostShardHashes, fileSize, downloadRewardAmount, repairRewardAmount)
		if err != nil {
			logger.Errorf("required field is empty: [%v]", err)
			return err
		}
		if !ctxParams.Cfg.Experimental.StorageHostEnabled {
			return fmt.Errorf("storage host api not enabled")
		}
		if !ctxParams.Cfg.Experimental.HostRepairEnabled {
			return fmt.Errorf("storage repair api not enabled")
		}
		sizeStat, err := corerepo.RepoSize(req.Context, ctxParams.N)
		if err != nil {
			return err
		}
		remainStorage := sizeStat.StorageMax - sizeStat.RepoSize
		if fileSize > int64(remainStorage) {
			errMsg := fmt.Sprintf("remaining storage space [%d] is less than required storage size [%d]", remainStorage, fileSize)
			logger.Errorf(errMsg)
			return fmt.Errorf(errMsg)
		}
		ns, err := helper.GetHostStorageConfig(ctxParams.Ctx, ctxParams.N)
		if err != nil {
			logger.Errorf("get host storage config error: [%v]", err)
			return err
		}
		var price uint64
		if ns.RepairCustomizedPricing {
			price = ns.RepairPriceCustomized
		} else {
			price = ns.RepairPriceDefault
		}
		totalPrice := uint64(float64(fileSize) / float64(units.GiB) * float64(price))
		if totalPrice <= 0 {
			totalPrice = 1
		}
		if totalPrice > uint64(repairRewardAmount) {
			errMsg := fmt.Sprintf("host desired price [%d] is greater than request price [%d]", totalPrice, repairRewardAmount)
			logger.Errorf(errMsg)
			return fmt.Errorf(errMsg)
		}
		err = doRepair(ctxParams, res, &RepairContractParams{
			FileHash:             fileHash,
			FileSize:             fileSize,
			RepairPid:            repairId,
			LostShardHashes:      lostShardHashes,
			RepairRewardAmount:   repairRewardAmount,
			DownloadRewardAmount: downloadRewardAmount,
		})

		if err != nil {
			logger.Errorf("repair job failed for peer id [%s]: [%v]", repairId, err)
			return err
		}

		logger.Info("repair lost shards done", zap.String("peerId", ctxParams.N.Identity.Pretty()))
		return nil
	},
}
View Source
var (
	ShardErrChanMap = cmap.New()
)
View Source
var StorageDcRepairRouterCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Interact with Host repair requests and responses for negotiation of decentralized shards repair.",
		ShortDescription: `
Guard broadcasts repair request to potential nodes, after negotiation, nodes prepare the contracts for 
such repair job, sign and send to the guard for confirmation `,
	},
	Subcommands: map[string]*cmds.Command{
		"request":  hostRepairRequestCmd,
		"response": HostRepairResponseCmd,
	},
}
View Source
var StorageUploadChequeCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline:          "receive upload cheque, do with cheque, and return it.",
		ShortDescription: `receive upload cheque, deal it and return it.`,
	},
	Arguments: []cmds.Argument{
		cmds.StringArg("encoded-cheque", true, false, "encoded-cheque from peer-id."),
		cmds.StringArg("amount", true, false, "amount"),
		cmds.StringArg("contract-id", false, false, "contract-id."),
		cmds.StringArg("token", false, false, "token."),
	},
	RunTimeout: 5 * time.Minute,
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
		err := utils.CheckSimpleMode(env)
		if err != nil {
			return err
		}

		fmt.Printf("receive cheque ...\n")

		ctxParams, err := uh.ExtractContextParams(req, env)
		if err != nil {
			return err
		}
		if !ctxParams.Cfg.Experimental.StorageHostEnabled {
			return fmt.Errorf("storage host api not enabled")
		}

		requestPid, ok := remote.GetStreamRequestRemotePeerID(req, ctxParams.N)
		if !ok {
			return fmt.Errorf("fail to get peer ID from request")
		}

		price, ok := new(big.Int).SetString(req.Arguments[1], 10)
		if !ok {
			return fmt.Errorf("exchangeRate:%s cannot be parsed, err:%s", req.Arguments[2], err)
		}

		encodedCheque := req.Arguments[0]
		contractId := req.Arguments[2]
		tokenHex := req.Arguments[3]
		fmt.Printf("receive cheque, requestPid:%s contractId:%+v,encodedCheque:%+v price:%v token:%+v\n",
			requestPid.String(), contractId, encodedCheque, price, tokenHex)

		token := common.HexToAddress(tokenHex)
		_, bl := tokencfg.MpTokenStr[token]
		if !bl {
			return errors.New("your input token is none. ")
		}

		priceStore, amountStore, rateStore, err := getInputPriceAmountRate(ctxParams, contractId)
		if err != nil {
			return err
		}
		if price.Int64() < priceStore {
			return errors.New(
				fmt.Sprintf("receive cheque, your input-price[%v] is less than store-price[%v]. ",
					price, priceStore),
			)
		}
		realAmount := new(big.Int).Mul(big.NewInt(amountStore), rateStore)
		fmt.Printf("receive cheque, price:%v amountStore:%v rateStore:%+v,realAmount:%+v \n",
			priceStore, amountStore, rateStore.String(), realAmount.String())

		err = swapprotocol.SwapProtocol.Handler(context.Background(), requestPid.String(), encodedCheque, realAmount, token)
		if err != nil {
			fmt.Println("receive cheque, swapprotocol.SwapProtocol.Handler, error:", err)
			return err
		}

		if len(contractId) > 0 {
			err := setPaidStatus(ctxParams, contractId)
			if err != nil {
				fmt.Println("receive cheque, setPaidStatus: contractId error:", contractId, err)
				return err
			}
		}

		return nil
	},
}
View Source
var StorageUploadCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Store files on BTFS network nodes through BTT payment.",
		ShortDescription: `
By default, BTFS selects hosts based on overall score according to the current client's environment.
To upload a file, <file-hash> must refer to a reed-solomon encoded file.

To create a reed-solomon encoded file from a normal file:

    $ btfs add --chunker=reed-solomon <file>
    added <file-hash> <file>

Run command to upload:

    $ btfs storage upload <file-hash>

To custom upload and storage a file on specific hosts:
    Use -m with 'custom' mode, and put host identifiers in -s, with multiple hosts separated by ','.

    # Upload a file to a set of hosts
    # Total # of hosts (N) must match # of shards in the first DAG level of root file hash
    $ btfs storage upload <file-hash> -m=custom -s=<host1-peer-id>,<host2-peer-id>,...,<hostN-peer-id>

    # Upload specific shards to a set of hosts
    # Total # of hosts (N) must match # of shards given
    $ btfs storage upload <shard-hash1> <shard-hash2> ... <shard-hashN> -l -m=custom -s=<host1-peer-id>,<host2-peer-id>,...,<hostN-peer-id>

Use status command to check for completion:
    $ btfs storage upload status <session-id> | jq`,
	},
	Subcommands: map[string]*cmds.Command{
		"init":              StorageUploadInitCmd,
		"supporttokens":     StorageUploadSupportTokensCmd,
		"cheque":            StorageUploadChequeCmd,
		"recvcontract":      StorageUploadRecvContractCmd,
		"status":            StorageUploadStatusCmd,
		"repair":            StorageUploadRepairCmd,
		"getcontractbatch":  offline.StorageUploadGetContractBatchCmd,
		"signcontractbatch": offline.StorageUploadSignContractBatchCmd,
		"getunsigned":       offline.StorageUploadGetUnsignedCmd,
		"sign":              offline.StorageUploadSignCmd,
	},
	Arguments: []cmds.Argument{
		cmds.StringArg("file-hash", true, false, "Hash of file to upload."),
		cmds.StringArg("upload-peer-id", false, false, "Peer id when upload upload."),
		cmds.StringArg("upload-nonce-ts", false, false, "Nounce timestamp when upload upload."),
		cmds.StringArg("upload-signature", false, false, "Session signature when upload upload."),
	},
	Options: []cmds.Option{
		cmds.Int64Option(uploadPriceOptionName, "p", "Max price per GiB per day of storage in µBTT (=0.000001BTT)."),
		cmds.IntOption(replicationFactorOptionName, "r", "Replication factor for the file with erasure coding built-in.").WithDefault(defaultRepFactor),
		cmds.StringOption(hostSelectModeOptionName, "m", "Based on this mode to select hosts and upload automatically. Default: mode set in config option Experimental.HostsSyncMode."),
		cmds.StringOption(hostSelectionOptionName, "s", "Use only these selected hosts in order on 'custom' mode. Use ',' as delimiter."),
		cmds.BoolOption(testOnlyOptionName, "t", "Enable host search under all domains 0.0.0.0 (useful for local test)."),
		cmds.IntOption(storageLengthOptionName, "len", "File storage period on hosts in days.").WithDefault(defaultStorageLength),
		cmds.BoolOption(customizedPayoutOptionName, "Enable file storage customized payout schedule.").WithDefault(false),
		cmds.IntOption(customizedPayoutPeriodOptionName, "Period of customized payout schedule.").WithDefault(1),
		cmds.IntOption(copyName, "copy num of file hash.").WithDefault(0),
		cmds.StringOption(tokencfg.TokenTypeName, "tk", "file storage with token type,default WBTT, other TRX/USDD/USDT.").WithDefault("WBTT"),
	},
	RunTimeout: 15 * time.Minute,
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
		nd, err := cmdenv.GetNode(env)
		if err != nil {
			return err
		}

		if !nd.IsOnline {
			return coreiface.ErrOffline
		}
		err = utils.CheckSimpleMode(env)
		if err != nil {
			return err
		}

		swapprotocol.Req = req
		swapprotocol.Env = env

		ssId := uuid.New().String()
		ctxParams, err := helper.ExtractContextParams(req, env)
		if err != nil {
			return err
		}
		renterId := ctxParams.N.Identity
		offlineSigning := false
		if len(req.Arguments) > 1 {
			if len(req.Arguments) < 4 {
				return fmt.Errorf("not enough arguments, expect: %v, actual:%v", 4, len(req.Arguments))
			}
			renterId, err = peer.Decode(req.Arguments[1])
			if err != nil {
				return err
			}
			offlineSigning = true
		}
		err = backoff.Retry(func() error {
			peersLen := len(ctxParams.N.PeerHost.Network().Peers())
			if peersLen <= 0 {
				err = errors.New("failed to find any peer in table")
				log.Error(err)
				return err
			}
			return nil
		}, helper.WaitingForPeersBo)

		var shardHashes []string
		var fileSize int64
		var shardSize int64

		tokenStr := req.Options[tokencfg.TokenTypeName].(string)
		token, bl := tokencfg.MpTokenAddr[tokenStr]
		if !bl {
			return errors.New("your input token is none. ")
		}
		fmt.Println("token =", token, tokenStr)

		fileHash := req.Arguments[0]
		shardHashes, fileSize, shardSize, err = helper.GetShardHashes(ctxParams, fileHash)
		if len(shardHashes) == 0 && fileSize == -1 && shardSize == -1 &&
			strings.HasPrefix(err.Error(), "invalid hash: file must be reed-solomon encoded") {
			if copyNum, ok := req.Options[copyName].(int); ok {
				shardHashes, fileSize, shardSize, err = helper.GetShardHashesCopy(ctxParams, fileHash, copyNum)
				fmt.Printf("copy get, shardHashes:%v fileSize:%v, shardSize:%v, copy:%v err:%v \n",
					shardHashes, fileSize, shardSize, copyNum, err)
			}
		}
		if err != nil {
			return err
		}
		_, storageLength, err := helper.GetPriceAndMinStorageLength(ctxParams)
		if err != nil {
			return err
		}

		priceObj, err := chain.SettleObject.OracleService.CurrentPrice(token)
		if err != nil {
			return err
		}
		price := priceObj.Int64()

		rate, err := chain.SettleObject.OracleService.CurrentRate(token)
		if err != nil {
			return err
		}
		_, err = helper.TotalPay(shardSize, price, storageLength, rate)
		if err != nil {
			fmt.Println(err.Error())
			return err
		}

		if !ctxParams.Cfg.Experimental.HostsSyncEnabled {
			_ = SyncHosts(ctxParams)
		}
		hp := helper.GetHostsProvider(ctxParams, make([]string, 0))
		if mode, ok := req.Options[hostSelectModeOptionName].(string); ok {
			var hostIDs []string
			if mode == "custom" {
				if hosts, ok := req.Options[hostSelectionOptionName].(string); ok {
					hostIDs = strings.Split(hosts, ",")
				}
				if len(hostIDs) != len(shardHashes) {
					return fmt.Errorf("custom mode hosts length must match shard hashes length")
				}
				hp = helper.GetCustomizedHostsProvider(ctxParams, hostIDs)
			}
		}
		rss, err := sessions.GetRenterSessionWithToken(ctxParams, ssId, fileHash, shardHashes, token)
		if err != nil {
			return err
		}
		if offlineSigning {
			offNonceTimestamp, err := strconv.ParseUint(req.Arguments[2], 10, 64)
			if err != nil {
				return err
			}
			err = rss.SaveOfflineMeta(&renterpb.OfflineMeta{
				OfflinePeerId:    req.Arguments[1],
				OfflineNonceTs:   offNonceTimestamp,
				OfflineSignature: req.Arguments[3],
			})
			if err != nil {
				return err
			}
		}
		shardIndexes := make([]int, 0)
		for i, _ := range rss.ShardHashes {
			shardIndexes = append(shardIndexes, i)
		}
		UploadShard(rss, hp, price, token, shardSize, storageLength, offlineSigning, renterId, fileSize, shardIndexes, nil)
		seRes := &Res{
			ID: ssId,
		}
		return res.Emit(seRes)
	},
	Type: Res{},
}
View Source
var StorageUploadInitCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Initialize storage handshake with inquiring client.",
		ShortDescription: `
Storage host opens this endpoint to accept incoming upload/storage requests,
If current host is interested and all validation checks out, host downloads
the shard and replies back to client for the next challenge step.`,
	},
	Arguments: []cmds.Argument{
		cmds.StringArg("session-id", true, false, "ID for the entire storage upload session."),
		cmds.StringArg("file-hash", true, false, "Root file storage node should fetch (the DAG)."),
		cmds.StringArg("shard-hash", true, false, "Shard the storage node should fetch."),
		cmds.StringArg("price", true, false, "Per GiB per day in µBTT (=0.000001BTT) for storing this shard offered by client."),
		cmds.StringArg("escrow-contract", true, false, "Client's initial escrow contract data."),
		cmds.StringArg("guard-contract-meta", true, false, "Client's initial guard contract meta."),
		cmds.StringArg("storage-length", true, false, "Store file for certain length in days."),
		cmds.StringArg("shard-size", true, false, "Size of each shard received in bytes."),
		cmds.StringArg("shard-index", true, false, "Index of shard within the encoding scheme."),
		cmds.StringArg("upload-peer-id", false, false, "Peer id when upload sign is used."),
	},
	RunTimeout: 5 * time.Minute,
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
		err := utils.CheckSimpleMode(env)
		if err != nil {
			return err
		}

		ctxParams, err := uh.ExtractContextParams(req, env)
		if err != nil {
			return err
		}
		if !ctxParams.Cfg.Experimental.StorageHostEnabled {
			return fmt.Errorf("storage host api not enabled")
		}
		requestPid, ok := remote.GetStreamRequestRemotePeerID(req, ctxParams.N)
		if !ok {
			return fmt.Errorf("fail to get peer ID from request")
		}

		myPeerId, err := peer.Decode(ctxParams.Cfg.Identity.PeerID)
		isVaultCompatible, err := chain.SettleObject.Factory.IsVaultCompatibleBetween(ctxParams.Ctx, myPeerId, requestPid)
		if err != nil {
			return err
		}
		if !isVaultCompatible {
			return fmt.Errorf("vault factory not compatible, please upgrade your node if possible")
		}

		hm := NewHostManager(ctxParams.Cfg)
		shardSize, err := strconv.ParseInt(req.Arguments[7], 10, 64)
		if err != nil {
			return err
		}
		accept, err := hm.AcceptContract(ctxParams.N.Repo.Datastore(), ctxParams.N.Identity.String(), shardSize)
		if err != nil {
			return err
		}
		if !accept {
			return errors.New("too many initialized contracts")
		}
		_, err = strconv.ParseInt(req.Arguments[3], 10, 64)
		if err != nil {
			return err
		}
		settings, err := helper.GetHostStorageConfig(ctxParams.Ctx, ctxParams.N)
		if err != nil {
			return err
		}

		storeLen, err := strconv.Atoi(req.Arguments[6])
		if err != nil {
			return err
		}
		if uint64(storeLen) < settings.StorageTimeMin {
			return fmt.Errorf("storage length invalid: want: >=%d, got: %d", settings.StorageTimeMin, storeLen)
		}
		ssId := req.Arguments[0]
		shardHash := req.Arguments[2]
		shardIndex, err := strconv.Atoi(req.Arguments[8])
		if err != nil {
			return err
		}

		fmt.Printf("--- upload init: start, shardSize:%v, requestPid:%v, shardIndex:%v . \n",
			shardSize, requestPid, shardIndex)

		halfSignedGuardContString := req.Arguments[5]

		var halfSignedGuardContBytes []byte
		halfSignedGuardContBytes = []byte(halfSignedGuardContString)
		halfSignedGuardContract := &guardpb.Contract{}
		err = proto.Unmarshal(halfSignedGuardContBytes, halfSignedGuardContract)
		if err != nil {
			return err
		}
		guardContractMeta := halfSignedGuardContract.ContractMeta

		pid, ok := remote.GetStreamRequestRemotePeerID(req, ctxParams.N)
		if !ok {
			return fmt.Errorf("fail to get peer ID from request")
		}
		var peerId string
		if peerId = pid.String(); len(req.Arguments) >= 10 {
			peerId = req.Arguments[9]
		}
		payerPubKey, err := crypto.GetPubKeyFromPeerId(peerId)
		if err != nil {
			return err
		}
		s := halfSignedGuardContract.GetRenterSignature()
		if s == nil {
			s = halfSignedGuardContract.GetPreparerSignature()
		}
		ok, err = crypto.Verify(payerPubKey, &guardContractMeta, s)
		if !ok || err != nil {
			return fmt.Errorf("can't verify guard contract: %v", err)
		}

		signedGuardContract, err := signGuardContract(&guardContractMeta, halfSignedGuardContract, ctxParams.N.PrivateKey)
		if err != nil {
			return err
		}
		signedGuardContractBytes, err := proto.Marshal(signedGuardContract)
		if err != nil {
			return err
		}

		var price int64
		var amount int64
		var rate *big.Int
		{

			token := common.HexToAddress(halfSignedGuardContract.Token)
			_, bl := tokencfg.MpTokenStr[token]
			if !bl {
				err = errors.New("receive upload init, your input token is not supported. " + token.String())
				return err
			}

			price = guardContractMeta.Price
			priceOnline, err := chain.SettleObject.OracleService.CurrentPrice(token)
			if err != nil {
				return err
			}
			fmt.Printf("receive init, token[%s] renter-price[%v], online-price[%v],  \n", token.String(), price, priceOnline)

			if price < priceOnline.Int64() {
				return errors.New(
					fmt.Sprintf("receive init, your renter-price[%v] is less than online-price[%v]. ",
						price, priceOnline),
				)
			}

			rate, err = chain.SettleObject.OracleService.CurrentRate(token)
			if err != nil {
				return err
			}
			amount = guardContractMeta.Amount
			amountCal, err := uh.TotalPay(guardContractMeta.ShardFileSize, price, storeLen, rate)
			if err != nil {
				return err
			}

			if amount < amountCal {
				return errors.New(
					fmt.Sprintf("receive init, your renter-amount[%v] is less than cal-amount[%v]. ",
						amount, amountCal),
				)
			}
		}

		go func() {
			tmp := func() error {
				shard, err := sessions.GetHostShard(ctxParams, signedGuardContract.ContractId, price, amount, rate)
				if err != nil {
					return err
				}

				_, err = remote.P2PCall(ctxParams.Ctx, ctxParams.N, ctxParams.Api, requestPid, "/storage/upload/recvcontract",
					ssId,
					shardHash,
					shardIndex,
					nil,
					signedGuardContractBytes,
				)
				if err != nil {
					return err
				}

				if err := shard.Contract(nil, signedGuardContract); err != nil {
					return err
				}

				fileHash := req.Arguments[1]
				err = downloadShardFromClient(ctxParams, halfSignedGuardContract, fileHash, shardHash, false)
				if err != nil {
					return err
				}

				err = challengeShard(ctxParams, fileHash, false, &guardContractMeta)
				if err != nil {
					return err
				}

				fmt.Printf("upload init: send /storage/upload/recvcontract ok, wait for pay status, requestPid:%v, shardIndex:%v. \n",
					requestPid, shardIndex)

				blPay := false
				var wg sync.WaitGroup
				wg.Add(1)
				go func() {

					tick := time.Tick(30 * time.Second)

					timeoutPay := time.NewTimer(10 * time.Minute)
					for true {
						select {
						case <-tick:
							if bl := shard.IsPayStatus(); bl {
								blPay = true
								wg.Done()
								return
							}
						case <-timeoutPay.C:
							return
						}
					}
				}()
				wg.Wait()

				if blPay == true {

					err = pinShard(ctxParams, halfSignedGuardContract, fileHash, shardHash)
					if err != nil {
						return err
					}
					fmt.Printf("upload init: pin shard ok, requestPid:%v, shardIndex:%v. \n", requestPid, shardIndex)
				} else {

					err = rmShard(ctxParams, req, env, shardHash)
					if err != nil {
						return err
					}
					fmt.Printf("upload init: timeout, remove Shard, requestPid:%v, shardIndex:%v. \n", requestPid, shardIndex)
				}

				fmt.Printf("upload init: Complete! requestPid:%v, shardIndex:%v. \n", requestPid, shardIndex)
				if err := shard.Complete(); err != nil {
					return err
				}

				return nil
			}()
			if tmp != nil {
				log.Debug(tmp)
			}
		}()
		return nil
	},
}
View Source
var StorageUploadRecvContractCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "For renter client to receive half signed contracts.",
	},
	Arguments: []cmds.Argument{
		cmds.StringArg("session-id", true, false, "Session ID which renter uses to storage all shards information."),
		cmds.StringArg("shard-hash", true, false, "Shard the storage node should fetch."),
		cmds.StringArg("shard-index", true, false, "Index of shard within the encoding scheme."),
		cmds.StringArg("escrow-contract", true, false, "Signed Escrow contract."),
		cmds.StringArg("guard-contract", true, false, "Signed Guard contract."),
	},
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
		err := utils.CheckSimpleMode(env)
		if err != nil {
			return err
		}

		contractId, err := doRecv(req, env)
		if contractId != "" {
			if ch, ok := ShardErrChanMap.Get(contractId); ok {
				go func() {
					ch.(chan error) <- err
				}()
			}
			if err != nil {
				return err
			}
		}
		return nil
	},
}
View Source
var StorageUploadRepairCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Repair specific shards of a file.",
		ShortDescription: `
This command repairs the given shards of a file.`,
	},
	Arguments: []cmds.Argument{
		cmds.StringArg("file-hash", true, false, "Hash of file to upload."),
		cmds.StringArg("repair-shards", true, false, "Shard hashes to repair."),
		cmds.StringArg("renter-pid", true, false, "Original renter peer ID."),
		cmds.StringArg("blacklist", true, false, "Blacklist of hosts during upload."),
	},
	RunTimeout: 5 * time.Minute,
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
		err := utils.CheckSimpleMode(env)
		if err != nil {
			return err
		}

		ctxParams, err := uh.ExtractContextParams(req, env)
		if err != nil {
			return err
		}
		fileHash := req.Arguments[0]
		metaReq := &guardpb.CheckFileStoreMetaRequest{
			FileHash:     fileHash,
			RenterPid:    ctxParams.N.Identity.String(),
			RequesterPid: ctxParams.N.Identity.String(),
			RequestTime:  time.Now().UTC(),
		}
		sig, err := crypto.Sign(ctxParams.N.PrivateKey, metaReq)
		if err != nil {
			return err
		}
		metaReq.Signature = sig
		ctx, _ := helper.NewGoContext(req.Context)
		var meta *guardpb.FileStoreStatus
		err = grpc.GuardClient(ctxParams.Cfg.Services.GuardDomain).WithContext(ctx, func(ctx context.Context,
			client guardpb.GuardServiceClient) error {
			meta, err = client.CheckFileStoreMeta(ctx, metaReq)
			if err != nil {
				return err
			}
			return nil
		})
		if err != nil {
			return err
		}
		contracts := meta.Contracts
		if len(contracts) <= 0 {
			return errors.New("length of contracts is 0")
		}
		ssId, _ := uh.SplitContractId(contracts[0].ContractId)
		shardIndexes := make([]int, 0)
		i := 0
		shardHashes := strings.Split(req.Arguments[1], ",")
		for _, contract := range contracts {
			if contract.ShardHash == shardHashes[i] {
				shardIndexes = append(shardIndexes, int(contract.ShardIndex))
				i++
			}
		}
		rss, err := sessions.GetRenterSession(ctxParams, ssId, fileHash, shardHashes)
		if err != nil {
			return err
		}
		hp := uh.GetHostsProvider(ctxParams, strings.Split(req.Arguments[3], ","))
		m := contracts[0].ContractMeta
		renterPid, err := peer.Decode(req.Arguments[2])
		if err != nil {
			return err
		}

		UploadShard(rss, hp, m.Price, tokencfg.GetWbttToken(), m.ShardFileSize, -1, false, renterPid, -1,
			shardIndexes, &RepairParams{
				RenterStart: m.RentStart,
				RenterEnd:   m.RentEnd,
			})
		seRes := &Res{
			ID: ssId,
		}
		return res.Emit(seRes)
	},
	Type: Res{},
}
View Source
var StorageUploadStatusCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Check storage upload and payment status (From client's perspective).",
		ShortDescription: `
This command print upload and payment status by the time queried.`,
	},
	Arguments: []cmds.Argument{
		cmds.StringArg("session-id", true, false, "ID for the entire storage upload session.").EnableStdin(),
	},
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
		err := utils.CheckSimpleMode(env)
		if err != nil {
			return err
		}

		status := &StatusRes{}

		ssId := req.Arguments[0]

		ctxParams, err := helper.ExtractContextParams(req, env)
		if err != nil {
			return err
		}

		if !ctxParams.Cfg.Experimental.StorageClientEnabled && !ctxParams.Cfg.Experimental.StorageHostEnabled {
			return fmt.Errorf("storage client/host api not enabled")
		}

		session, err := sessions.GetRenterSession(ctxParams, ssId, "", make([]string, 0))
		if err != nil {
			return err
		}
		sessionStatus, err := session.Status()
		if err != nil {
			return err
		}
		status.Status = sessionStatus.Status
		status.Message = sessionStatus.Message
		info, err := session.GetAdditionalInfo()
		if err == nil {
			status.AdditionalInfo = info.Info
		} else {

		}

		shards := make(map[string]*ShardStatus)
		status.FileHash = session.Hash
		fullyCompleted := true
		for i, h := range session.ShardHashes {
			shard, err := sessions.GetRenterShard(ctxParams, ssId, h, i)
			if err != nil {
				return err
			}
			st, err := shard.Status()
			if err != nil {
				return err
			}
			contracts, err := shard.Contracts()
			if err != nil {
				return err
			}
			additionalInfo, err := shard.GetAdditionalInfo()
			if err != nil && err != datastore.ErrNotFound {
				return err
			}
			switch additionalInfo.Info {
			case guardpb.Contract_UPLOADED.String(), guardpb.Contract_CANCELED.String(), guardpb.Contract_CLOSED.String():

			default:
				fullyCompleted = false
			}
			c := &ShardStatus{
				ContractID:     "",
				Price:          0,
				Host:           "",
				Status:         st.Status,
				Message:        st.Message,
				AdditionalInfo: additionalInfo.Info,
			}
			if contracts.SignedGuardContract != nil {
				c.ContractID = contracts.SignedGuardContract.ContractId
				c.Price = contracts.SignedGuardContract.Price
				c.Host = contracts.SignedGuardContract.HostPid
			}
			shards[sessions.GetShardId(ssId, h, i)] = c
		}
		if (status.Status == sessions.RssWaitUploadReqSignedStatus || status.Status == sessions.RssCompleteStatus) && !fullyCompleted {
			if err := grpc.GuardClient(ctxParams.Cfg.Services.GuardDomain).
				WithContext(req.Context, func(ctx context.Context, client guardpb.GuardServiceClient) error {
					req := &guardpb.CheckFileStoreMetaRequest{
						FileHash:     session.Hash,
						RenterPid:    session.PeerId,
						RequesterPid: session.CtxParams.N.Identity.String(),
						RequestTime:  time.Now(),
					}
					sig, err := crypto.Sign(ctxParams.N.PrivateKey, req)
					if err != nil {
						return err
					}
					req.Signature = sig
					meta, err := client.CheckFileStoreMeta(ctx, req)
					if err != nil {
						return err
					}
					for _, c := range meta.Contracts {
						shards[sessions.GetShardId(ssId, c.ShardHash, int(c.ShardIndex))].AdditionalInfo = c.State.String()
					}
					return nil
				}); err != nil {
				log.Debug(err)
			}
		}
		status.Shards = shards
		if len(status.Shards) == 0 && status.Status == sessions.RssInitStatus {
			status.Message = "session not found"
		}
		return res.Emit(status)
	},
	Type: StatusRes{},
}
View Source
var StorageUploadSupportTokensCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline:          "support cheque, return tokens.",
		ShortDescription: `support cheque, return tokens.`,
	},
	Arguments:  []cmds.Argument{},
	RunTimeout: 5 * time.Minute,
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
		err := utils.CheckSimpleMode(env)
		if err != nil {
			return err
		}

		ctxParams, err := uh.ExtractContextParams(req, env)
		if err != nil {
			return err
		}
		if !ctxParams.Cfg.Experimental.StorageHostEnabled {
			return fmt.Errorf("storage host api not enabled")
		}

		return cmds.EmitOnce(res, &tokencfg.MpTokenAddr)
	},
}

Functions

func NewFileStatus

func NewFileStatus(contracts []*guardpb.Contract, configuration *config.Config,
	renterId string, fileHash string, fileSize int64) (*guardpb.FileStoreStatus, error)

func RenterSignGuardContract

func RenterSignGuardContract(rss *sessions.RenterSession, params *ContractParams, offlineSigning bool,
	rp *RepairParams, token string) ([]byte,
	error)

func ResumeWaitUploadOnSigning

func ResumeWaitUploadOnSigning(rss *sessions.RenterSession) error

func Submit

func Submit(rss *sessions.RenterSession, fileSize int64, offlineSigning bool) error

func SyncHosts

func SyncHosts(ctxParams *helper.ContextParams) error

func UploadShard

func UploadShard(rss *sessions.RenterSession, hp helper.IHostsProvider, price int64, token common.Address, shardSize int64,
	storageLength int,
	offlineSigning bool, renterId peer.ID, fileSize int64, shardIndexes []int, rp *RepairParams) error

Types

type ContractParams

type ContractParams struct {
	ContractId    string
	RenterPid     string
	HostPid       string
	ShardIndex    int32
	ShardHash     string
	ShardSize     int64
	FileHash      string
	StartTime     time.Time
	StorageLength int64
	Price         int64
	TotalPay      int64
}

type Count

type Count struct{}

func (*Count) Count

func (h *Count) Count(ds datastore.Datastore, peerId string, status guardpb.Contract_ContractState) (int, error)

type HostManager

type HostManager struct {
	// contains filtered or unexported fields
}

func NewHostManager

func NewHostManager(cfg *config.Config) *HostManager

func (*HostManager) AcceptContract

func (h *HostManager) AcceptContract(ds datastore.Datastore, peerId string, shardSize int64) (bool, error)

type ICount

type ICount interface {
	Count(ds datastore.Datastore, peerId string, status guardpb.Contract_ContractState) (int, error)
}

type RepairContractParams

type RepairContractParams struct {
	FileHash             string
	FileSize             int64
	RepairPid            string
	LostShardHashes      []string
	RepairRewardAmount   int64
	DownloadRewardAmount int64
}

type RepairParams

type RepairParams struct {
	RenterStart time.Time
	RenterEnd   time.Time
}

type Res

type Res struct {
	ID string
}

type ShardStatus

type ShardStatus struct {
	ContractID     string
	Price          int64
	Host           string
	Status         string
	Message        string
	AdditionalInfo string
}

type StatusRes

type StatusRes struct {
	Status         string
	Message        string
	AdditionalInfo string
	FileHash       string
	Shards         map[string]*ShardStatus
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL