From 05110623f114655a1ed0b50e0629e7780b033de4 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Fri, 31 Jul 2020 15:13:49 -0400 Subject: [PATCH] Adding different prices for verified deals (#347) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * adding different prices for verified deals * Documentation improvements to verified deal ask Co-authored-by: Sami Mäkelä --- .../storage_retrieval_integration_test.go | 4 +-- shared_testutil/generators.go | 1 + storagemarket/impl/provider.go | 6 ++--- .../impl/providerstates/provider_states.go | 7 ++++- .../providerstates/provider_states_test.go | 7 ++--- storagemarket/impl/storedask/storedask.go | 26 +++++++++++-------- .../impl/storedask/storedask_test.go | 10 ++++--- storagemarket/integration_test.go | 6 ++--- storagemarket/provider.go | 4 +-- storagemarket/types.go | 3 ++- storagemarket/types_cbor_gen.go | 18 +++++++++++-- 11 files changed, 60 insertions(+), 32 deletions(-) diff --git a/retrievalmarket/storage_retrieval_integration_test.go b/retrievalmarket/storage_retrieval_integration_test.go index 94dc4eac..3279791c 100644 --- a/retrievalmarket/storage_retrieval_integration_test.go +++ b/retrievalmarket/storage_retrieval_integration_test.go @@ -67,7 +67,7 @@ func TestStorageRetrieval(t *testing.T) { _ = sh.Client.SubscribeToEvents(clientSubscriber) // set ask price where we'll accept any price - err := sh.Provider.SetAsk(big.NewInt(0), 50_000) + err := sh.Provider.SetAsk(big.NewInt(0), big.NewInt(0), 50_000) assert.NoError(t, err) result := sh.ProposeStorageDeal(t, &storagemarket.DataRef{TransferType: storagemarket.TTGraphsync, Root: sh.PayloadCid}) @@ -307,7 +307,7 @@ func newStorageHarness(ctx context.Context, t *testing.T) *storageHarness { require.NoError(t, err) // set ask price where we'll accept any price - require.NoError(t, provider.SetAsk(big.NewInt(0), 50_000)) + require.NoError(t, provider.SetAsk(big.NewInt(0), big.NewInt(0), 50_000)) require.NoError(t, provider.Start(ctx)) // Closely follows the MinerInfo struct in the spec diff --git a/shared_testutil/generators.go b/shared_testutil/generators.go index 2d4f32ff..fc776e06 100644 --- a/shared_testutil/generators.go +++ b/shared_testutil/generators.go @@ -230,6 +230,7 @@ func MakeTestMinerDeal(state storagemarket.StorageDealStatus, clientDealProposal func MakeTestStorageAsk() *storagemarket.StorageAsk { return &storagemarket.StorageAsk{ Price: MakeTestTokenAmount(), + VerifiedPrice: MakeTestTokenAmount(), MinPieceSize: abi.PaddedPieceSize(rand.Uint64()), Miner: address.TestAddress2, Timestamp: abi.ChainEpoch(rand.Int63()), diff --git a/storagemarket/impl/provider.go b/storagemarket/impl/provider.go index 9b772f79..c8cfafad 100644 --- a/storagemarket/impl/provider.go +++ b/storagemarket/impl/provider.go @@ -41,7 +41,7 @@ var _ network.StorageReceiver = &Provider{} // StoredAsk is an interface which provides access to a StorageAsk type StoredAsk interface { GetAsk() *storagemarket.SignedStorageAsk - SetAsk(price abi.TokenAmount, duration abi.ChainEpoch, options ...storagemarket.StorageAskOption) error + SetAsk(price abi.TokenAmount, verifiedPrice abi.TokenAmount, duration abi.ChainEpoch, options ...storagemarket.StorageAskOption) error } // Provider is the production implementation of the StorageProvider interface @@ -367,8 +367,8 @@ func (p *Provider) ListLocalDeals() ([]storagemarket.MinerDeal, error) { // SetAsk configures the storage miner's ask with the provided price, // duration, and options. Any previously-existing ask is replaced. -func (p *Provider) SetAsk(price abi.TokenAmount, duration abi.ChainEpoch, options ...storagemarket.StorageAskOption) error { - return p.storedAsk.SetAsk(price, duration, options...) +func (p *Provider) SetAsk(price abi.TokenAmount, verifiedPrice abi.TokenAmount, duration abi.ChainEpoch, options ...storagemarket.StorageAskOption) error { + return p.storedAsk.SetAsk(price, verifiedPrice, duration, options...) } /* diff --git a/storagemarket/impl/providerstates/provider_states.go b/storagemarket/impl/providerstates/provider_states.go index 414c427b..f2474edf 100644 --- a/storagemarket/impl/providerstates/provider_states.go +++ b/storagemarket/impl/providerstates/provider_states.go @@ -79,7 +79,12 @@ func ValidateDealProposal(ctx fsm.Context, environment ProviderDealEnvironment, return ctx.Trigger(storagemarket.ProviderEventDealRejected, xerrors.Errorf("proposed provider collateral above maximum: %s > %s", proposal.ProviderCollateral, pcMax)) } - minPrice := big.Div(big.Mul(environment.Ask().Price, abi.NewTokenAmount(int64(proposal.PieceSize))), abi.NewTokenAmount(1<<30)) + askPrice := environment.Ask().Price + if deal.Proposal.VerifiedDeal { + askPrice = environment.Ask().VerifiedPrice + } + + minPrice := big.Div(big.Mul(askPrice, abi.NewTokenAmount(int64(proposal.PieceSize))), abi.NewTokenAmount(1<<30)) if proposal.StoragePricePerEpoch.LessThan(minPrice) { return ctx.Trigger(storagemarket.ProviderEventDealRejected, xerrors.Errorf("storage price per epoch less than asking price: %s < %s", proposal.StoragePricePerEpoch, minPrice)) diff --git a/storagemarket/impl/providerstates/provider_states_test.go b/storagemarket/impl/providerstates/provider_states_test.go index cbde10b8..a424254b 100644 --- a/storagemarket/impl/providerstates/provider_states_test.go +++ b/storagemarket/impl/providerstates/provider_states_test.go @@ -887,9 +887,10 @@ var defaultDataRef = storagemarket.DataRef{ var defaultClientMarketBalance = abi.NewTokenAmount(200 * 10000) var defaultAsk = storagemarket.StorageAsk{ - Price: abi.NewTokenAmount(10000000), - MinPieceSize: abi.PaddedPieceSize(256), - MaxPieceSize: 1 << 20, + Price: abi.NewTokenAmount(10000000), + VerifiedPrice: abi.NewTokenAmount(1000000), + MinPieceSize: abi.PaddedPieceSize(256), + MaxPieceSize: 1 << 20, } var testData = tut.NewTestIPLDTree() diff --git a/storagemarket/impl/storedask/storedask.go b/storagemarket/impl/storedask/storedask.go index 7f5a57f8..2f408529 100644 --- a/storagemarket/impl/storedask/storedask.go +++ b/storagemarket/impl/storedask/storedask.go @@ -19,9 +19,12 @@ import ( var log = logging.Logger("storedask") -// DefaultPrice is the default price set for StorageAsk in Fil / GiB / Epoch +// DefaultPrice is the default price for unverified deals (in attoFil / GiB / Epoch) var DefaultPrice = abi.NewTokenAmount(500000000) +// DefaultVerifiedPrice is the default price for verified deals (in attoFil / GiB / Epoch) +var DefaultVerifiedPrice = abi.NewTokenAmount(50000000) + // DefaultDuration is the default number of epochs a storage ask is in effect for const DefaultDuration abi.ChainEpoch = 1000000 @@ -61,17 +64,17 @@ func NewStoredAsk(ds datastore.Batching, dsKey datastore.Key, spn storagemarket. if s.ask == nil { // TODO: we should be fine with this state, and just say it means 'not actively accepting deals' // for now... lets just set a price - if err := s.SetAsk(DefaultPrice, DefaultDuration); err != nil { + if err := s.SetAsk(DefaultPrice, DefaultVerifiedPrice, DefaultDuration); err != nil { return nil, xerrors.Errorf("failed setting a default price: %w", err) } } return s, nil } -// SetAsk writes a new ask to disk with the provided price, +// SetAsk configures the storage miner's ask with the provided prices (for unverified and verified deals), // duration, and options. Any previously-existing ask is replaced. // It also increments the sequence number on the ask -func (s *StoredAsk) SetAsk(price abi.TokenAmount, duration abi.ChainEpoch, options ...storagemarket.StorageAskOption) error { +func (s *StoredAsk) SetAsk(price abi.TokenAmount, verifiedPrice abi.TokenAmount, duration abi.ChainEpoch, options ...storagemarket.StorageAskOption) error { s.askLk.Lock() defer s.askLk.Unlock() var seqno uint64 @@ -86,13 +89,14 @@ func (s *StoredAsk) SetAsk(price abi.TokenAmount, duration abi.ChainEpoch, optio return err } ask := &storagemarket.StorageAsk{ - Price: price, - Timestamp: height, - Expiry: height + duration, - Miner: s.actor, - SeqNo: seqno, - MinPieceSize: DefaultMinPieceSize, - MaxPieceSize: DefaultMaxPieceSize, + Price: price, + VerifiedPrice: verifiedPrice, + Timestamp: height, + Expiry: height + duration, + Miner: s.actor, + SeqNo: seqno, + MinPieceSize: DefaultMinPieceSize, + MaxPieceSize: DefaultMaxPieceSize, } for _, option := range options { diff --git a/storagemarket/impl/storedask/storedask_test.go b/storagemarket/impl/storedask/storedask_test.go index a4890854..4aa96ff8 100644 --- a/storagemarket/impl/storedask/storedask_test.go +++ b/storagemarket/impl/storedask/storedask_test.go @@ -28,6 +28,7 @@ func TestStoredAsk(t *testing.T) { require.NoError(t, err) testPrice := abi.NewTokenAmount(1000000000) + testVerifiedPrice := abi.NewTokenAmount(100000000) testDuration := abi.ChainEpoch(200) t.Run("auto initializing", func(t *testing.T) { ask := storedAsk.GetAsk() @@ -35,7 +36,7 @@ func TestStoredAsk(t *testing.T) { }) t.Run("setting ask price", func(t *testing.T) { minPieceSize := abi.PaddedPieceSize(1024) - err := storedAsk.SetAsk(testPrice, testDuration, storagemarket.MinPieceSize(minPieceSize)) + err := storedAsk.SetAsk(testPrice, testVerifiedPrice, testDuration, storagemarket.MinPieceSize(minPieceSize)) require.NoError(t, err) ask := storedAsk.GetAsk() require.Equal(t, ask.Ask.Price, testPrice) @@ -47,6 +48,7 @@ func TestStoredAsk(t *testing.T) { require.NoError(t, err) ask := storedAsk2.GetAsk() require.Equal(t, ask.Ask.Price, testPrice) + require.Equal(t, ask.Ask.VerifiedPrice, testVerifiedPrice) require.Equal(t, ask.Ask.Expiry-ask.Ask.Timestamp, testDuration) }) t.Run("node errors", func(t *testing.T) { @@ -59,7 +61,7 @@ func TestStoredAsk(t *testing.T) { // should load cause ask is is still in data store storedAskError, err := storedask.NewStoredAsk(ds, datastore.NewKey("latest-ask"), spnStateIDErr, actor) require.NoError(t, err) - err = storedAskError.SetAsk(testPrice, testDuration) + err = storedAskError.SetAsk(testPrice, testVerifiedPrice, testDuration) require.Error(t, err) spnMinerWorkerErr := &testnodes.FakeProviderNode{ @@ -71,7 +73,7 @@ func TestStoredAsk(t *testing.T) { // should load cause ask is is still in data store storedAskError, err = storedask.NewStoredAsk(ds, datastore.NewKey("latest-ask"), spnMinerWorkerErr, actor) require.NoError(t, err) - err = storedAskError.SetAsk(testPrice, testDuration) + err = storedAskError.SetAsk(testPrice, testVerifiedPrice, testDuration) require.Error(t, err) spnSignBytesErr := &testnodes.FakeProviderNode{ @@ -83,7 +85,7 @@ func TestStoredAsk(t *testing.T) { // should load cause ask is is still in data store storedAskError, err = storedask.NewStoredAsk(ds, datastore.NewKey("latest-ask"), spnSignBytesErr, actor) require.NoError(t, err) - err = storedAskError.SetAsk(testPrice, testDuration) + err = storedAskError.SetAsk(testPrice, testVerifiedPrice, testDuration) require.Error(t, err) }) } diff --git a/storagemarket/integration_test.go b/storagemarket/integration_test.go index b4da59cc..71bbee1c 100644 --- a/storagemarket/integration_test.go +++ b/storagemarket/integration_test.go @@ -82,7 +82,7 @@ func TestMakeDeal(t *testing.T) { _ = h.Client.SubscribeToEvents(clientSubscriber) // set ask price where we'll accept any price - err := h.Provider.SetAsk(big.NewInt(0), 50_000) + err := h.Provider.SetAsk(big.NewInt(0), big.NewInt(0), 50_000) assert.NoError(t, err) result := h.ProposeStorageDeal(t, &storagemarket.DataRef{TransferType: storagemarket.TTGraphsync, Root: h.PayloadCid}, true, false) @@ -291,7 +291,7 @@ func TestRestartClient(t *testing.T) { require.NoError(t, h.Client.Start(ctx)) // set ask price where we'll accept any price - err := h.Provider.SetAsk(big.NewInt(0), 50_000) + err := h.Provider.SetAsk(big.NewInt(0), big.NewInt(0), 50_000) assert.NoError(t, err) wg := sync.WaitGroup{} @@ -461,7 +461,7 @@ func newHarnessWithTestData(t *testing.T, ctx context.Context, td *shared_testut assert.NoError(t, err) // set ask price where we'll accept any price - err = provider.SetAsk(big.NewInt(0), 50_000) + err = provider.SetAsk(big.NewInt(0), big.NewInt(0), 50_000) assert.NoError(t, err) err = provider.Start(ctx) diff --git a/storagemarket/provider.go b/storagemarket/provider.go index 93c3c408..966448c1 100644 --- a/storagemarket/provider.go +++ b/storagemarket/provider.go @@ -26,9 +26,9 @@ type StorageProvider interface { // Stop terminates processing of deals on a StorageProvider Stop() error - // SetAsk configures the storage miner's ask with the provided price, + // SetAsk configures the storage miner's ask with the provided prices (for unverified and verified deals), // duration, and options. Any previously-existing ask is replaced. - SetAsk(price abi.TokenAmount, duration abi.ChainEpoch, options ...StorageAskOption) error + SetAsk(price abi.TokenAmount, verifiedPrice abi.TokenAmount, duration abi.ChainEpoch, options ...StorageAskOption) error // GetAsk returns the storage miner's ask, or nil if one does not exist. GetAsk() *SignedStorageAsk diff --git a/storagemarket/types.go b/storagemarket/types.go index b2baf04f..16ccfdea 100644 --- a/storagemarket/types.go +++ b/storagemarket/types.go @@ -37,7 +37,8 @@ type Balance struct { // storage provider may run its own decision logic). type StorageAsk struct { // Price per GiB / Epoch - Price abi.TokenAmount + Price abi.TokenAmount + VerifiedPrice abi.TokenAmount MinPieceSize abi.PaddedPieceSize MaxPieceSize abi.PaddedPieceSize diff --git a/storagemarket/types_cbor_gen.go b/storagemarket/types_cbor_gen.go index 693e2fd3..dba113fa 100644 --- a/storagemarket/types_cbor_gen.go +++ b/storagemarket/types_cbor_gen.go @@ -1029,7 +1029,7 @@ func (t *SignedStorageAsk) UnmarshalCBOR(r io.Reader) error { return nil } -var lengthBufStorageAsk = []byte{135} +var lengthBufStorageAsk = []byte{136} func (t *StorageAsk) MarshalCBOR(w io.Writer) error { if t == nil { @@ -1047,6 +1047,11 @@ func (t *StorageAsk) MarshalCBOR(w io.Writer) error { return err } + // t.VerifiedPrice (big.Int) (struct) + if err := t.VerifiedPrice.MarshalCBOR(w); err != nil { + return err + } + // t.MinPieceSize (abi.PaddedPieceSize) (uint64) if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.MinPieceSize)); err != nil { @@ -1109,7 +1114,7 @@ func (t *StorageAsk) UnmarshalCBOR(r io.Reader) error { return fmt.Errorf("cbor input should be of type array") } - if extra != 7 { + if extra != 8 { return fmt.Errorf("cbor input had wrong number of fields") } @@ -1121,6 +1126,15 @@ func (t *StorageAsk) UnmarshalCBOR(r io.Reader) error { return xerrors.Errorf("unmarshaling t.Price: %w", err) } + } + // t.VerifiedPrice (big.Int) (struct) + + { + + if err := t.VerifiedPrice.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.VerifiedPrice: %w", err) + } + } // t.MinPieceSize (abi.PaddedPieceSize) (uint64)