# Simple Summary (概述)
droplet
批量发单是指基于 go-graphsplit (opens new window) 工具实现一个能够批量发离线订单的工具,并且 DC
订单符合 DC 发单要求
。
# Abstract (功能简介)
droplet-client
需要实现以下功能:
- 增加批量发布订单命令和接口
- 离线订单持久化存储,订单状态追踪
- 增加获取离线订单、订单分布情况接口
- 命令行可以输出离线订单信息和
DC
订单分布信息 - 批量导入订单及聚合抵押
- 支持 f+ 对 LDN 发单要求,简称:
DC 发单要求
关联:
- [x] 提案的issue (opens new window)
# 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
订单不能超过SP
总DC
订单的 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
需要位于不同地区)
- Storage provider should not exceed 25% of total datacap(
# 订单持久化
把离线订单存储到 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(实施)
# 查询离线订单
- 按 proposal cid 查询单个离线订单信息
- 列出所有离线订单信息
# 持久化订单数据
离线订单数据结构如下:
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 订单分布情况
- 统计
SP
DC
订单数据重复率,重复率 = 不重复DC
订单 /SP
所有DC
订单。
假如有两个 piece1,三个 piece3,则重复率 = 1 - (piece1+piece3) / (2 * piece1 + 3 * piece3)
- 统计发单地址分配给
SP
的DC
订单占比
# 获取 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
}