deals: Price per epoch

This commit is contained in:
Łukasz Magiera 2019-10-29 11:01:18 +01:00
parent 5ace5cdbc2
commit 72af55d067
8 changed files with 43 additions and 41 deletions

View File

@ -102,7 +102,7 @@ type FullNode interface {
// ClientImport imports file under the specified path into filestore
ClientImport(ctx context.Context, path string) (cid.Cid, error)
ClientStartDeal(ctx context.Context, data cid.Cid, miner address.Address, price types.BigInt, blocksDuration uint64) (*cid.Cid, error)
ClientStartDeal(ctx context.Context, data cid.Cid, miner address.Address, epochPrice types.BigInt, blocksDuration uint64) (*cid.Cid, error)
ClientListDeals(ctx context.Context) ([]DealInfo, error)
ClientHasLocal(ctx context.Context, root cid.Cid) (bool, error)
ClientFindData(ctx context.Context, root cid.Cid) ([]QueryOffer, error) // TODO: specify serialization mode we want (defaults to unixfs for now)
@ -206,8 +206,8 @@ type DealInfo struct {
PieceRef []byte // cid bytes
Size uint64
TotalPrice types.BigInt
Duration uint64
PricePerEpoch types.BigInt
Duration uint64
}
type MsgWait struct {

View File

@ -85,12 +85,16 @@ type StorageDealProposal struct {
// Changing to duration makes sure that the price-per-block is defined, and the miner
// doesn't get paid when not storing the sector
StoragePrice types.BigInt
StorageCollateral types.BigInt
StoragePricePerEpoch types.BigInt
StorageCollateral types.BigInt
ProposerSignature *types.Signature
}
func (sdp *StorageDealProposal) TotalStoragePrice() types.BigInt {
return types.BigMul(sdp.StoragePricePerEpoch, types.NewInt(sdp.Duration))
}
type SignFunc = func(context.Context, []byte) (*types.Signature, error)
func (sdp *StorageDealProposal) Sign(ctx context.Context, sign SignFunc) error {
@ -392,11 +396,13 @@ func (st *StorageMarketState) validateDeal(vmctx types.VMContext, deal StorageDe
clientBalance := b[0]
providerBalance := b[1]
if clientBalance.Available.LessThan(deal.Proposal.StoragePrice) {
return aerrors.Newf(5, "client doesn't have enough available funds to cover StoragePrice; %d < %d", clientBalance.Available, deal.Proposal.StoragePrice)
totalPrice := deal.Proposal.TotalStoragePrice()
if clientBalance.Available.LessThan(totalPrice) {
return aerrors.Newf(5, "client doesn't have enough available funds to cover storage price; %d < %d", clientBalance.Available, totalPrice)
}
clientBalance = lockFunds(clientBalance, deal.Proposal.StoragePrice)
clientBalance = lockFunds(clientBalance, totalPrice)
// TODO: REVIEW: Not clear who pays for this
if providerBalance.Available.LessThan(deal.Proposal.StorageCollateral) {
@ -539,7 +545,7 @@ func (sma StorageMarketActor) ProcessStorageDealsPayment(act *types.Actor, vmctx
// todo: check math (written on a plane, also tired)
// TODO: division is hard, this more than likely has some off-by-one issue
toPay := types.BigDiv(types.BigMul(dealInfo.Deal.Proposal.StoragePrice, types.NewInt(build.ProvingPeriodDuration)), types.NewInt(dealInfo.Deal.Proposal.Duration))
toPay := types.BigMul(dealInfo.Deal.Proposal.StoragePricePerEpoch, types.NewInt(build.ProvingPeriodDuration))
b, bnd, aerr := GetMarketBalances(vmctx.Context(), vmctx.Ipld(), self.Balances, dealInfo.Deal.Proposal.Client, providerWorker)
if aerr != nil {

View File

@ -3051,8 +3051,8 @@ func (t *StorageDealProposal) MarshalCBOR(w io.Writer) error {
return err
}
// t.t.StoragePrice (types.BigInt)
if err := t.StoragePrice.MarshalCBOR(w); err != nil {
// t.t.StoragePricePerEpoch (types.BigInt)
if err := t.StoragePricePerEpoch.MarshalCBOR(w); err != nil {
return err
}
@ -3158,11 +3158,11 @@ func (t *StorageDealProposal) UnmarshalCBOR(r io.Reader) error {
return fmt.Errorf("wrong type for uint64 field")
}
t.Duration = extra
// t.t.StoragePrice (types.BigInt)
// t.t.StoragePricePerEpoch (types.BigInt)
{
if err := t.StoragePrice.UnmarshalCBOR(br); err != nil {
if err := t.StoragePricePerEpoch.UnmarshalCBOR(br); err != nil {
return err
}

View File

@ -419,8 +419,8 @@ func (t *ClientDealProposal) MarshalCBOR(w io.Writer) error {
return xerrors.Errorf("failed to write cid field t.Data: %w", err)
}
// t.t.TotalPrice (types.BigInt)
if err := t.TotalPrice.MarshalCBOR(w); err != nil {
// t.t.PricePerEpoch (types.BigInt)
if err := t.PricePerEpoch.MarshalCBOR(w); err != nil {
return err
}
@ -481,11 +481,11 @@ func (t *ClientDealProposal) UnmarshalCBOR(r io.Reader) error {
t.Data = c
}
// t.t.TotalPrice (types.BigInt)
// t.t.PricePerEpoch (types.BigInt)
{
if err := t.TotalPrice.UnmarshalCBOR(br); err != nil {
if err := t.PricePerEpoch.UnmarshalCBOR(br); err != nil {
return err
}

View File

@ -159,7 +159,7 @@ func (c *Client) onUpdated(ctx context.Context, update clientDealUpdate) {
type ClientDealProposal struct {
Data cid.Cid
TotalPrice types.BigInt
PricePerEpoch types.BigInt
ProposalExpiration uint64
Duration uint64
@ -175,13 +175,13 @@ func (c *Client) Start(ctx context.Context, p ClientDealProposal) (cid.Cid, erro
return cid.Undef, xerrors.Errorf("getting client market balance failed: %w", err)
}
if clientMarketBalance.Available.LessThan(p.TotalPrice) {
if clientMarketBalance.Available.LessThan(types.BigMul(p.PricePerEpoch, types.NewInt(p.Duration))) {
// TODO: move to a smarter market funds manager
smsg, err := c.mpool.MpoolPushMessage(ctx, &types.Message{
To: actors.StorageMarketAddress,
From: p.Client,
Value: p.TotalPrice,
Value: types.BigMul(p.PricePerEpoch, types.NewInt(p.Duration)),
GasPrice: types.NewInt(0),
GasLimit: types.NewInt(1000000),
Method: actors.SMAMethods.AddBalance,
@ -203,15 +203,15 @@ func (c *Client) Start(ctx context.Context, p ClientDealProposal) (cid.Cid, erro
dataSize, err := c.dataSize(ctx, p.Data)
proposal := &actors.StorageDealProposal{
PieceRef: p.Data.Bytes(),
PieceSize: uint64(dataSize),
PieceSerialization: actors.SerializationUnixFSv0,
Client: p.Client,
Provider: p.ProviderAddress,
ProposalExpiration: p.ProposalExpiration,
Duration: p.Duration,
StoragePrice: p.TotalPrice,
StorageCollateral: types.NewInt(uint64(dataSize)), // TODO: real calc
PieceRef: p.Data.Bytes(),
PieceSize: uint64(dataSize),
PieceSerialization: actors.SerializationUnixFSv0,
Client: p.Client,
Provider: p.ProviderAddress,
ProposalExpiration: p.ProposalExpiration,
Duration: p.Duration,
StoragePricePerEpoch: p.PricePerEpoch,
StorageCollateral: types.NewInt(uint64(dataSize)), // TODO: real calc
}
if err := api.SignWith(ctx, c.w.Sign, p.Client, proposal); err != nil {

View File

@ -88,9 +88,9 @@ func (p *Provider) accept(ctx context.Context, deal MinerDeal) (func(*MinerDeal)
// TODO: check StorageCollateral
// TODO:
minPrice := types.BigMul(p.ask.Ask.Price, types.BigMul(types.NewInt(deal.Proposal.Duration), types.NewInt(deal.Proposal.PieceSize)))
if deal.Proposal.StoragePrice.LessThan(minPrice) {
return nil, xerrors.Errorf("storage price less than asking price: %s < %s", deal.Proposal.StoragePrice, minPrice)
minPrice := types.BigMul(p.ask.Ask.Price, types.NewInt(deal.Proposal.PieceSize))
if deal.Proposal.StoragePricePerEpoch.LessThan(minPrice) {
return nil, xerrors.Errorf("storage price per epoch less than asking price: %s < %s", deal.Proposal.StoragePricePerEpoch, minPrice)
}
if deal.Proposal.PieceSize < p.ask.Ask.MinPieceSize {
@ -105,7 +105,7 @@ func (p *Provider) accept(ctx context.Context, deal MinerDeal) (func(*MinerDeal)
// This doesn't guarantee that the client won't withdraw / lock those funds
// but it's a decent first filter
if clientMarketBalance.Available.LessThan(deal.Proposal.StoragePrice) {
if clientMarketBalance.Available.LessThan(deal.Proposal.TotalStoragePrice()) {
return nil, xerrors.New("clientMarketBalance.Available too small")
}

View File

@ -488,7 +488,6 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
return nil, xerrors.Errorf("getting block miner actor (%s) failed: %w", vm.blockMiner, err)
}
// TODO: support multiple blocks in a tipset
// TODO: actually wire this up (miner is undef for now)
gasReward := types.BigMul(msg.GasPrice, gasUsed)

View File

@ -53,7 +53,7 @@ type API struct {
Filestore dtypes.ClientFilestore `optional:"true"`
}
func (a *API) ClientStartDeal(ctx context.Context, data cid.Cid, miner address.Address, price types.BigInt, blocksDuration uint64) (*cid.Cid, error) {
func (a *API) ClientStartDeal(ctx context.Context, data cid.Cid, miner address.Address, epochPrice types.BigInt, blocksDuration uint64) (*cid.Cid, error) {
// TODO: make this a param
self, err := a.WalletDefaultAddress(ctx)
if err != nil {
@ -76,12 +76,9 @@ func (a *API) ClientStartDeal(ctx context.Context, data cid.Cid, miner address.A
return nil, err
}
// setup payments
total := types.BigMul(price, types.NewInt(blocksDuration))
proposal := deals.ClientDealProposal{
Data: data,
TotalPrice: total,
PricePerEpoch: epochPrice,
ProposalExpiration: math.MaxUint64, // TODO: set something reasonable
Duration: blocksDuration,
ProviderAddress: miner,
@ -110,8 +107,8 @@ func (a *API) ClientListDeals(ctx context.Context) ([]api.DealInfo, error) {
PieceRef: v.Proposal.PieceRef,
Size: v.Proposal.PieceSize,
TotalPrice: v.Proposal.StoragePrice,
Duration: v.Proposal.Duration,
PricePerEpoch: v.Proposal.StoragePricePerEpoch,
Duration: v.Proposal.Duration,
}
}