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 imports file under the specified path into filestore
ClientImport(ctx context.Context, path string) (cid.Cid, error) 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) ClientListDeals(ctx context.Context) ([]DealInfo, error)
ClientHasLocal(ctx context.Context, root cid.Cid) (bool, 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) 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 PieceRef []byte // cid bytes
Size uint64 Size uint64
TotalPrice types.BigInt PricePerEpoch types.BigInt
Duration uint64 Duration uint64
} }
type MsgWait struct { 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 // Changing to duration makes sure that the price-per-block is defined, and the miner
// doesn't get paid when not storing the sector // doesn't get paid when not storing the sector
StoragePrice types.BigInt StoragePricePerEpoch types.BigInt
StorageCollateral types.BigInt StorageCollateral types.BigInt
ProposerSignature *types.Signature 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) type SignFunc = func(context.Context, []byte) (*types.Signature, error)
func (sdp *StorageDealProposal) Sign(ctx context.Context, sign SignFunc) 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] clientBalance := b[0]
providerBalance := b[1] providerBalance := b[1]
if clientBalance.Available.LessThan(deal.Proposal.StoragePrice) { totalPrice := deal.Proposal.TotalStoragePrice()
return aerrors.Newf(5, "client doesn't have enough available funds to cover StoragePrice; %d < %d", clientBalance.Available, deal.Proposal.StoragePrice)
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 // TODO: REVIEW: Not clear who pays for this
if providerBalance.Available.LessThan(deal.Proposal.StorageCollateral) { 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: check math (written on a plane, also tired)
// TODO: division is hard, this more than likely has some off-by-one issue // 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) b, bnd, aerr := GetMarketBalances(vmctx.Context(), vmctx.Ipld(), self.Balances, dealInfo.Deal.Proposal.Client, providerWorker)
if aerr != nil { if aerr != nil {

View File

@ -3051,8 +3051,8 @@ func (t *StorageDealProposal) MarshalCBOR(w io.Writer) error {
return err return err
} }
// t.t.StoragePrice (types.BigInt) // t.t.StoragePricePerEpoch (types.BigInt)
if err := t.StoragePrice.MarshalCBOR(w); err != nil { if err := t.StoragePricePerEpoch.MarshalCBOR(w); err != nil {
return err return err
} }
@ -3158,11 +3158,11 @@ func (t *StorageDealProposal) UnmarshalCBOR(r io.Reader) error {
return fmt.Errorf("wrong type for uint64 field") return fmt.Errorf("wrong type for uint64 field")
} }
t.Duration = extra 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 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) return xerrors.Errorf("failed to write cid field t.Data: %w", err)
} }
// t.t.TotalPrice (types.BigInt) // t.t.PricePerEpoch (types.BigInt)
if err := t.TotalPrice.MarshalCBOR(w); err != nil { if err := t.PricePerEpoch.MarshalCBOR(w); err != nil {
return err return err
} }
@ -481,11 +481,11 @@ func (t *ClientDealProposal) UnmarshalCBOR(r io.Reader) error {
t.Data = c 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 return err
} }

View File

@ -159,7 +159,7 @@ func (c *Client) onUpdated(ctx context.Context, update clientDealUpdate) {
type ClientDealProposal struct { type ClientDealProposal struct {
Data cid.Cid Data cid.Cid
TotalPrice types.BigInt PricePerEpoch types.BigInt
ProposalExpiration uint64 ProposalExpiration uint64
Duration 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) 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 // TODO: move to a smarter market funds manager
smsg, err := c.mpool.MpoolPushMessage(ctx, &types.Message{ smsg, err := c.mpool.MpoolPushMessage(ctx, &types.Message{
To: actors.StorageMarketAddress, To: actors.StorageMarketAddress,
From: p.Client, From: p.Client,
Value: p.TotalPrice, Value: types.BigMul(p.PricePerEpoch, types.NewInt(p.Duration)),
GasPrice: types.NewInt(0), GasPrice: types.NewInt(0),
GasLimit: types.NewInt(1000000), GasLimit: types.NewInt(1000000),
Method: actors.SMAMethods.AddBalance, 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) dataSize, err := c.dataSize(ctx, p.Data)
proposal := &actors.StorageDealProposal{ proposal := &actors.StorageDealProposal{
PieceRef: p.Data.Bytes(), PieceRef: p.Data.Bytes(),
PieceSize: uint64(dataSize), PieceSize: uint64(dataSize),
PieceSerialization: actors.SerializationUnixFSv0, PieceSerialization: actors.SerializationUnixFSv0,
Client: p.Client, Client: p.Client,
Provider: p.ProviderAddress, Provider: p.ProviderAddress,
ProposalExpiration: p.ProposalExpiration, ProposalExpiration: p.ProposalExpiration,
Duration: p.Duration, Duration: p.Duration,
StoragePrice: p.TotalPrice, StoragePricePerEpoch: p.PricePerEpoch,
StorageCollateral: types.NewInt(uint64(dataSize)), // TODO: real calc StorageCollateral: types.NewInt(uint64(dataSize)), // TODO: real calc
} }
if err := api.SignWith(ctx, c.w.Sign, p.Client, proposal); err != nil { 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: check StorageCollateral
// TODO: // TODO:
minPrice := types.BigMul(p.ask.Ask.Price, types.BigMul(types.NewInt(deal.Proposal.Duration), types.NewInt(deal.Proposal.PieceSize))) minPrice := types.BigMul(p.ask.Ask.Price, types.NewInt(deal.Proposal.PieceSize))
if deal.Proposal.StoragePrice.LessThan(minPrice) { if deal.Proposal.StoragePricePerEpoch.LessThan(minPrice) {
return nil, xerrors.Errorf("storage price less than asking price: %s < %s", deal.Proposal.StoragePrice, 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 { 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 // This doesn't guarantee that the client won't withdraw / lock those funds
// but it's a decent first filter // 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") 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) return nil, xerrors.Errorf("getting block miner actor (%s) failed: %w", vm.blockMiner, err)
} }
// TODO: support multiple blocks in a tipset // TODO: support multiple blocks in a tipset
// TODO: actually wire this up (miner is undef for now) // TODO: actually wire this up (miner is undef for now)
gasReward := types.BigMul(msg.GasPrice, gasUsed) gasReward := types.BigMul(msg.GasPrice, gasUsed)

View File

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