# Simple Summary (概述)

droplet 批量发单是指基于 go-graphsplit (opens new window) 工具实现一个能够批量发离线订单的工具,并且 DC 订单符合 DC 发单要求

# Abstract (功能简介)

droplet-client 需要实现以下功能:

  • 增加批量发布订单命令和接口
  • 离线订单持久化存储,订单状态追踪
  • 增加获取离线订单、订单分布情况接口
  • 命令行可以输出离线订单信息和 DC 订单分布信息
  • 批量导入订单及聚合抵押
  • 支持 f+ 对 LDN 发单要求,简称:DC 发单要求

关联:

# Motivation (来源/背景)

目前 droplet-client 一次只能发布一个订单,当有大量订单需要发布时,需要一个一个发,发单的效率并不高。批量发单可以一次对多个 SP 发布多个订单,可以提高效率。

# Specification (feature Spec)

# 名词解释

  • 批量发单:指批量发布离线订单
  • 订单:分普通订单和 DC 订单,DC 订单是被分配了 datacap 的订单
  • SP:存储提供者
  • 发单地址:发单时使用的地址,可以是具有 datacap 的地址
  • go-graphsplit:一种用于将数据集切分成固定大小的 car 文件的工具
  • datacap 发单要求:
    • Storage provider should not exceed 25% of total datacap(client 给一个 SP 发的 DC 订单不能超过 SPDC 订单的 25%)
    • Storage provider should not be storing duplicate data for more than 20%(SP 不能超过 20% 的重复数据)
    • Storage provider should have published its public IP address(SP 需要公开公告 IP 地址)
    • All storage providers should be located in different regions(SP 需要位于不同地区)

# 订单持久化

把离线订单存储到 badger 数据库,以 proposal cid 作为 key,把订单 JSON marshal 后的结果作为 value。

# 接口

droplet-client 新增接口

# 批量导入订单
ClientBatchDeal(ctx context.Context, params *client.DealsParams) (*client.DealResults, error)
# 获取 DC 订单分布情况
ClientGetVerifiedDealDistribution(ctx context.Context, providers []address.Address, client address.Address) (*client.DealDistribution, error)
# 查询所有离线订单
ClientListOfflineDeals(ctx context.Context) ([]client.DealInfo, error)    

droplet 新增接口

# 批量导入离线订单数据
DealsBatchImportData(ctx context.Context, refs market.ImportDataRefs) ([]*market.ImportDataResult, error)

# 新增命令

  • droplet-client 批量发单:支持对多 SP 发布多个离线订单,
  • droplet-client 查询离线订单:能够查询单个订单和列出所有离线订单
  • droplet-client 查询订单分布情况:可以按 SP 和 发单地址查询
  • droplet-client 导出离线订单:当订单状态为 StorageDealWaitingForData 时,导出订单 proposalcid 和 piececid
  • droplet 批量导入订单:支持输入多个 proposalcid 和 car 文件组合,也支持根据文件导入

# Design Rationale (设计思路)

存储离线订单使用 JSON marshal 是为了方便以后加字段

根据用户使用 go-graphsplit 生成的 manifest.csv 文件内容来批量生成离线订单。

# Backwards Compatibility(兼容性)

需要兼容已有的发单逻辑

# Test Cases (测试用例)

# Security Considerations (安全考量)

# Implementation(实施)

# 查询离线订单

  1. 按 proposal cid 查询单个离线订单信息
  2. 列出所有离线订单信息

# 持久化订单数据

离线订单数据结构如下:

ClientDealProposal (opens new window)

  types.ClientDealProposal
  ProposalCID    cid.Cid
	DataRef        *storagemarket.DataRef
	Message        string
	State          uint64
	DealID         uint64
	AddFundsCid    *cid.Cid
	PublishMessage *cid.Cid
	FastRetrieval  bool
	SlashEpoch     abi.ChainEpoch
	CreatedAt      time.Time
	UpdatedAt      time.Time

接口:

type ClientOfflineDealRepo interface {
	SaveDeal(ctx context.Context, deal *ClientOfflineDeal) error
	GetDeal(ctx context.Context, proposalCid cid.Cid) (*ClientOfflineDeal, error)
	ListDeal(ctx context.Context) ([]*ClientOfflineDeal, error)
  ListDeal(ctx context.Context) ([]*types2.ClientOfflineDeal, error)
}

# 离线订单状态追踪

粗略的把订单分成 active 订单和 inactive 订单,循序检查订单状态,如果订单状态是 StorageDealActive 则为 active 订单,反之是 inactive 订单。

  • active 订单:间隔一段较长时间去链上查询订单是否 slash
  • inactive 订单:间隔较短时间使用 libp2p 去获取订单状态

# 批量发布订单接口

DealsParams (opens new window)

ClientBatchDeal(ctx context.Context, params *client.DealsParams) (*client.DealResults, error)
type DealResults struct {
	Results []*DealResult
}
type DealResult struct {
	ProposalCID cid.Cid
	// Create deal failed
	Message string
}
type DealsParams struct {
	Params []*DealParams
}

# 统计 DC 订单分布情况

  1. 统计 SP DC 订单数据重复率,重复率 = 不重复 DC 订单 / SP 所有 DC 订单。
假如有两个 piece1,三个 piece3,则重复率 = 1 - (piece1+piece3) / (2 * piece1 + 3 * piece3)
  1. 统计发单地址分配给 SPDC 订单占比
# 获取 DC 订单分布情况
ClientGetVerifiedDealDistribution(ctx context.Context) (*PieceDistribution, error) 
type ProviderDistribution struct {
	Provider address.Address
	// Total deal
	Total uint64
	// Uniq deal
	Uniq uint64
	// May be too large
	UniqPieces map[string]uint64
	// (Total-Uniq) / Total
	DuplicationPercentage float64
}
type ReplicaDistribution struct {
	// Datacap address
	Client address.Address
	// Total deal
	Total uint64
	// Uniq deal
	Uniq uint64
	// (Total-Uniq) / Uniq
	DuplicationPercentage float64
	// ProviderTotalDeal / Total
	ReplicasPercentage   map[string]float64
	ReplicasDistribution []*ProviderDistribution
}
type DealDistribution struct {
	ProvidersDistribution []*ProviderDistribution
	ReplicasDistribution  []*ReplicaDistribution
}