-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dynamic Retrieval pricing #6175
Conversation
} | ||
|
||
var retrievalGetAskCmd = &cli.Command{ | ||
// TODO FIX THIS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this PR is incomplete, better mark it as draft ;-)
@@ -160,80 +155,8 @@ var retrievalDealsListCmd = &cli.Command{ | |||
}, | |||
} | |||
|
|||
var retrievalSetAskCmd = &cli.Command{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we removing this command? Shouldn't this retrieval ask be the fallback price? It could be sent to the pricing strategy, or the pricing strategy could return a boolean saying whether it has calculated a price, or if it wants to fall back to the fixed price.
markets/pricing/cli.go
Outdated
} | ||
|
||
func runPricingFunc(_ context.Context, cmd string, params interface{}) (retrievalmarket.Ask, error) { | ||
j, err := json.MarshalIndent(params, "", " ") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why MarshalIndent? A single-line JSON would be easier to process and debug.
markets/retrievaladapter/provider.go
Outdated
@@ -38,6 +38,50 @@ func NewRetrievalProviderNode(maddr dtypes.MinerAddress, secb sectorblocks.Secto | |||
return &retrievalProviderNode{address.Address(maddr), secb, pp, full} | |||
} | |||
|
|||
func (rpn *retrievalProviderNode) GetDealPricingParams(ctx context.Context, storageDeals []abi.DealID) (retrievalmarket.DealPricingParams, error) { | |||
resp := retrievalmarket.DealPricingParams{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we pack as much data as possible as input to the retrieval pricing function? PieceCID, PieceSize, at least.
markets/retrievaladapter/provider.go
Outdated
@@ -38,6 +38,50 @@ func NewRetrievalProviderNode(maddr dtypes.MinerAddress, secb sectorblocks.Secto | |||
return &retrievalProviderNode{address.Address(maddr), secb, pp, full} | |||
} | |||
|
|||
func (rpn *retrievalProviderNode) GetDealPricingParams(ctx context.Context, storageDeals []abi.DealID) (retrievalmarket.DealPricingParams, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
func (rpn *retrievalProviderNode) GetDealPricingParams(ctx context.Context, storageDeals []abi.DealID) (retrievalmarket.DealPricingParams, error) { | |
func (rpn *retrievalProviderNode) GetRetrievalPricingInput(ctx context.Context, storageDeals []abi.DealID) (retrievalmarket.RetrievalPricingInput, error) { |
node/config/def.go
Outdated
type DefaultRetrievalPricingParams struct { | ||
PricePerByte types.FIL | ||
UnsealPrice types.FIL | ||
PaymentInterval uint64 | ||
PaymentIntervalIncrease uint64 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's keep the set retrieval ask command and remove this from configuration. We can't break that interface.
That allows for setting a "fixed" ask for when:
- clients are querying the retrieval ask (get retrieval ask)
- a dynamic pricing function (if enabled) refuses to calculate a dynamic price, or it errors
And miners will want to adjust the fixed price at runtime, so having these in configuration removes flexibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Follow-up comment to clarify what I think the UX should be here.
I think we need to support three policies for dynamic retrieval pricing.
none
=> no dynamic pricer is configured, all retrievals use the fixed ask, configured via set-ask.default
=> (default we ship with) makes unsealed pieces (potentially) free to retrieve. We need to provide configuration values here because miners should be able to charge for data transfer if they want to (they just would rank lower in the reputation system)external
=> an external script.
What the retrieval protocol would do is:
- If
none
is configured, no changes to current behaviour. - If
default
is configured, call the default pricing function (which has been instantiated with some configuration values, maybe). The function should return a tuple(price: float, dynamic: bool)
.- if
dynamic==true
, just return theprice
. - if
dynamic==false
, the pricing policy has refused to calculate a price (e.g. the piece is sealed), and we fall back to the configured fixed ask. - if it errors, we fall back to the fixed ask.
- if
- If
external
is configured, call the script and use the same logic above.
After chatting with @aarshkshah1992, we can simplify this.
|
} | ||
|
||
path := storiface.PathByType(paths, ft) | ||
if path == "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When is path == ""
? This function always returns and string based on the ft
, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left a couple of suggestions.
When we test this out on a real miner we should measure the performance of checking if a piece in unsealed - it will be called as part of an externally facing API call so we need to make sure it's not too expensive.
Co-authored-by: dirkmc <dirkmdev@gmail.com>
@magik6k Have rebased & addressed your review. Please merge if happy. |
@aarshkshah1992 do you really mean to update the FFI here? |
tcs := map[string]struct { | ||
storeFnc func(s *mocks.MockStore) | ||
pfFunc func(s *mocks.MockpartialFileHandler) | ||
indexFnc func(s *mocks.MockSectorIndex, serverURL string) | ||
|
||
needHttpServer bool | ||
|
||
getAllocatedReturnCode int | ||
|
||
serverUrl string | ||
|
||
// expectation | ||
errStr string | ||
expectedIsUnealed bool | ||
}{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I defer to @magik6k to review the unsealing logic and the test coverage. I'm not so familiar with this part of the codebase.
External: &RetrievalPricingExternal{ | ||
Path: "", | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should omit this altogether. Is it not possible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@raulk Some tests complain that this is needed because of how the toml gets serialized/de-serialised. No harm in keeping it around unless you want me to dig deeper into why those tests complain.
@aarshkshah1992 we need to write docs for this. Can you draft a section for the "Mine >> Managing retrievals" subpage? https://docs.filecoin.io/mine/lotus/manage-retrieval-deals/ A markdown gist is fine. Possible structure for this section: ## Retrieval pricing
Lotus allows you to set different policies to calculate the quoted price of a retrieval deal:
* default: <explain>
* external: <explain>
### Using the default retrieval pricing policy
<explain>
### Using the external retrieval pricing policy
<explain> @atopal pinging you here as your team will likely own the integration of the content ;-) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, am I right that we're missing converage for the interface with the external pricing function? I'd expect these test cases:
- OK: verify that we generate the right input, and that we can process well generated output.
- ERR: path doesn't exist.
- ERR: path is not executable.
- ERR: we can handle badly structured output, e.g. not JSON.
- ERR: we can handle bad output content, e.g. output is JSON, but all fields are nil values, and/or numeric fields overflow.
Co-authored-by: raulk <raul@protocol.ai>
Retrieval pricingLotus allows you to set different policies to calculate the quoted price of a retrieval deal:
Using the default retrieval pricing policy
[Dealmaking.RetrievalPricing]
Strategy = "default"
[Dealmaking.RetrievalPricing.Default]
VerifiedDealsFreeTransfer = false
Using the external retrieval pricing policy
type PricingInput struct {
// PayloadCID is the cid of the payload to retrieve.
PayloadCID cid.Cid
// PieceCID is the cid of the Piece from which the Payload will be retrieved.
PieceCID cid.Cid
// PieceSize is the size of the Piece from which the payload will be retrieved.
PieceSize abi.UnpaddedPieceSize
// Client is the peerID of the retrieval client.
Client peer.ID
// VerifiedDeal is true if there exists a verified storage deal for the PayloadCID.
VerifiedDeal bool
// Unsealed is true if there exists an unsealed sector from which we can retrieve the given payload.
Unsealed bool
// CurrentAsk is the ask configured in the ask-store via the `lotus retrieval-deals set-ask` CLI command.
CurrentAsk Ask
} The output type Ask struct {
PricePerByte abi.TokenAmount
UnsealPrice abi.TokenAmount
PaymentInterval uint64
PaymentIntervalIncrease uint64
}
[Dealmaking.RetrievalPricing]
Strategy = "external"
[Dealmaking.RetrievalPricing.External]
Path = "/var/script" |
@raulk I'd love to write tests for the external pricing script but it's not clear to me how instantiate the nodes with a desired config. For now, all nodes are instantiated with the default config. Does the |
@magik6k Please can you approve the PR if happy ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just one nitpick, looks good otherwise
log.Debugf("checked if local partial file has the piece %s (+%d,%d), returning answer=%t", path, offset, size, has) | ||
return has, nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sector files can technically not have a piece unsealed locally, but have it unsealed in remote storage, so we probably want to return only if has
is true
(Right now this usually won't be the case, but it may be more common if we get a PoRep with multi-TB sectors (numbers like 32tb sectors were floating in the research space))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(we may have the same bug below in Reader
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@magik6k Address this with some tests. Please take a look.
@aarshkshah1992 could you link the issue for the extra test we wanted to add (external pricing function)? |
Filed an issue to write missing e2e tests for the external pricing script feature at #6508. |
Implement Dynamic Retrieval Pricing.
This PR supports two modes of dynamically pricing retrieval deals:
lotus retrieval-deals set-ask
) to price deals.VerifiedDealsFreeTransfer
flag to false in the config.set-ask
CLI command. To use this mode instead of the default above, theUseDynamicRetrievalPricing
flag needs to be set to true in the config.Depends on filecoin-project/go-fil-markets#542.
Manual Testing
Mainnet
AskStore
usingset-ask
and then the correct transfer price is quoted from the ask store for retrieval of payload NOT contained in a verified storage deal.Devnet
TODO
Note: This Lotus PR depends on
go-fil-markets
v1.5.0 which is the Markets version that contains the changes needed for Dynamic Retrieval Pricing.