From 72af55d0677819a3811cc43520a4ffb47230581e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 29 Oct 2019 11:01:18 +0100 Subject: [PATCH] deals: Price per epoch --- api/api.go | 6 +++--- chain/actors/actor_storagemarket.go | 18 ++++++++++++------ chain/actors/cbor_gen.go | 8 ++++---- chain/deals/cbor_gen.go | 8 ++++---- chain/deals/client.go | 24 ++++++++++++------------ chain/deals/provider_states.go | 8 ++++---- chain/vm/vm.go | 1 - node/impl/client/client.go | 11 ++++------- 8 files changed, 43 insertions(+), 41 deletions(-) diff --git a/api/api.go b/api/api.go index 94f69485c..989d42ee8 100644 --- a/api/api.go +++ b/api/api.go @@ -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 { diff --git a/chain/actors/actor_storagemarket.go b/chain/actors/actor_storagemarket.go index 57f7171a5..9a5f88435 100644 --- a/chain/actors/actor_storagemarket.go +++ b/chain/actors/actor_storagemarket.go @@ -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 { diff --git a/chain/actors/cbor_gen.go b/chain/actors/cbor_gen.go index b45586c96..5444dafb0 100644 --- a/chain/actors/cbor_gen.go +++ b/chain/actors/cbor_gen.go @@ -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 } diff --git a/chain/deals/cbor_gen.go b/chain/deals/cbor_gen.go index 0e09cc492..40413170c 100644 --- a/chain/deals/cbor_gen.go +++ b/chain/deals/cbor_gen.go @@ -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 } diff --git a/chain/deals/client.go b/chain/deals/client.go index b6e0b3df5..fa70dbe99 100644 --- a/chain/deals/client.go +++ b/chain/deals/client.go @@ -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 { diff --git a/chain/deals/provider_states.go b/chain/deals/provider_states.go index c2f49d4f0..72e7d17bf 100644 --- a/chain/deals/provider_states.go +++ b/chain/deals/provider_states.go @@ -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") } diff --git a/chain/vm/vm.go b/chain/vm/vm.go index 8b702c48b..38831043b 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -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) diff --git a/node/impl/client/client.go b/node/impl/client/client.go index 926d6f623..a785bef44 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -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, } }