-
Notifications
You must be signed in to change notification settings - Fork 59
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Persist retrieval ask on disk (#410)
* Bugfix: Store datastore key in the storage ask repository * Add an AskStore interface/impl for retrievalmarket * Use AskStore in provider impl
- Loading branch information
Showing
6 changed files
with
205 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package retrievalmarket | ||
|
||
import "github.com/filecoin-project/go-state-types/abi" | ||
|
||
// DefaultPricePerByte is the charge per byte retrieved if the miner does | ||
// not specifically set it | ||
var DefaultPricePerByte = abi.NewTokenAmount(2) | ||
|
||
// DefaultUnsealPrice is the default charge to unseal a sector for retrieval | ||
var DefaultUnsealPrice = abi.NewTokenAmount(0) | ||
|
||
// DefaultPaymentInterval is the baseline interval, set to 1Mb | ||
// if the miner does not explicitly set it otherwise | ||
var DefaultPaymentInterval = uint64(1 << 20) | ||
|
||
// DefaultPaymentIntervalIncrease is the amount interval increases on each payment, | ||
// set to to 1Mb if the miner does not explicitly set it otherwise | ||
var DefaultPaymentIntervalIncrease = uint64(1 << 20) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package askstore | ||
|
||
import ( | ||
"bytes" | ||
"sync" | ||
|
||
"github.com/ipfs/go-datastore" | ||
"golang.org/x/xerrors" | ||
|
||
cborutil "github.com/filecoin-project/go-cbor-util" | ||
|
||
"github.com/filecoin-project/go-fil-markets/retrievalmarket" | ||
) | ||
|
||
// AskStoreImpl implements AskStore, persisting a retrieval Ask | ||
// to disk. It also maintains a cache of the current Ask in memory | ||
type AskStoreImpl struct { | ||
lk sync.RWMutex | ||
ask *retrievalmarket.Ask | ||
ds datastore.Batching | ||
key datastore.Key | ||
} | ||
|
||
// NewAskStore returns a new instance of AskStoreImpl | ||
// It will initialize a new default ask and store it if one is not set. | ||
// Otherwise it loads the current Ask from disk | ||
func NewAskStore(ds datastore.Batching, key datastore.Key) (*AskStoreImpl, error) { | ||
s := &AskStoreImpl{ | ||
ds: ds, | ||
key: key, | ||
} | ||
|
||
if err := s.tryLoadAsk(); err != nil { | ||
return nil, err | ||
} | ||
|
||
if s.ask == nil { | ||
// for now set a default retrieval ask | ||
defaultAsk := &retrievalmarket.Ask{ | ||
PricePerByte: retrievalmarket.DefaultPricePerByte, | ||
UnsealPrice: retrievalmarket.DefaultUnsealPrice, | ||
PaymentInterval: retrievalmarket.DefaultPaymentInterval, | ||
PaymentIntervalIncrease: retrievalmarket.DefaultPaymentIntervalIncrease, | ||
} | ||
|
||
if err := s.SetAsk(defaultAsk); err != nil { | ||
return nil, xerrors.Errorf("failed setting a default retrieval ask: %w", err) | ||
} | ||
} | ||
return s, nil | ||
} | ||
|
||
// SetAsk stores retrieval provider's ask | ||
func (s *AskStoreImpl) SetAsk(ask *retrievalmarket.Ask) error { | ||
s.lk.Lock() | ||
defer s.lk.Unlock() | ||
|
||
return s.saveAsk(ask) | ||
} | ||
|
||
// GetAsk returns the current retrieval ask, or nil if one does not exist. | ||
func (s *AskStoreImpl) GetAsk() *retrievalmarket.Ask { | ||
s.lk.RLock() | ||
defer s.lk.RUnlock() | ||
if s.ask == nil { | ||
return nil | ||
} | ||
ask := *s.ask | ||
return &ask | ||
} | ||
|
||
func (s *AskStoreImpl) tryLoadAsk() error { | ||
s.lk.Lock() | ||
defer s.lk.Unlock() | ||
|
||
err := s.loadAsk() | ||
|
||
if err != nil { | ||
if xerrors.Is(err, datastore.ErrNotFound) { | ||
// this is expected | ||
return nil | ||
} | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (s *AskStoreImpl) loadAsk() error { | ||
askb, err := s.ds.Get(s.key) | ||
if err != nil { | ||
return xerrors.Errorf("failed to load most recent retrieval ask from disk: %w", err) | ||
} | ||
|
||
var ask retrievalmarket.Ask | ||
if err := cborutil.ReadCborRPC(bytes.NewReader(askb), &ask); err != nil { | ||
return err | ||
} | ||
|
||
s.ask = &ask | ||
return nil | ||
} | ||
|
||
func (s *AskStoreImpl) saveAsk(a *retrievalmarket.Ask) error { | ||
b, err := cborutil.Dump(a) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if err := s.ds.Put(s.key, b); err != nil { | ||
return err | ||
} | ||
|
||
s.ask = a | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package askstore_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/ipfs/go-datastore" | ||
dss "github.com/ipfs/go-datastore/sync" | ||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/filecoin-project/go-state-types/abi" | ||
|
||
"github.com/filecoin-project/go-fil-markets/retrievalmarket" | ||
"github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/askstore" | ||
) | ||
|
||
func TestAskStoreImpl(t *testing.T) { | ||
ds := dss.MutexWrap(datastore.NewMapDatastore()) | ||
store, err := askstore.NewAskStore(ds, datastore.NewKey("retrieval-ask")) | ||
require.NoError(t, err) | ||
|
||
// A new store returns the default ask | ||
ask := store.GetAsk() | ||
require.NotNil(t, ask) | ||
|
||
require.Equal(t, retrievalmarket.DefaultUnsealPrice, ask.UnsealPrice) | ||
require.Equal(t, retrievalmarket.DefaultPricePerByte, ask.PricePerByte) | ||
require.Equal(t, retrievalmarket.DefaultPaymentInterval, ask.PaymentInterval) | ||
require.Equal(t, retrievalmarket.DefaultPaymentIntervalIncrease, ask.PaymentIntervalIncrease) | ||
|
||
// Store a new ask | ||
newAsk := &retrievalmarket.Ask{ | ||
PricePerByte: abi.NewTokenAmount(123), | ||
UnsealPrice: abi.NewTokenAmount(456), | ||
PaymentInterval: 789, | ||
PaymentIntervalIncrease: 789, | ||
} | ||
err = store.SetAsk(newAsk) | ||
require.NoError(t, err) | ||
|
||
// Fetch new ask | ||
stored := store.GetAsk() | ||
require.Equal(t, newAsk, stored) | ||
|
||
// Construct a new AskStore and make sure it returns the previously-stored ask | ||
newStore, err := askstore.NewAskStore(ds, datastore.NewKey("retrieval-ask")) | ||
require.NoError(t, err) | ||
stored = newStore.GetAsk() | ||
require.Equal(t, newAsk, stored) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters